Merge "Statsd can pull kernel wakelock data"
diff --git a/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java
index e644a1f..b4c7f54 100644
--- a/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java
@@ -16,35 +16,28 @@
package android.text;
-import android.app.Activity;
+import static android.text.Layout.Alignment.ALIGN_NORMAL;
+
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
-import android.os.Bundle;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.StubActivity;
-
-import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
import android.text.style.ReplacementSpan;
import android.util.ArraySet;
-import static android.text.Layout.Alignment.ALIGN_NORMAL;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Locale;
-import java.util.Random;
-
-import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Random;
@LargeTest
@RunWith(Parameterized.class)
diff --git a/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java
index 40b56f4..d219d3a 100644
--- a/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java
@@ -16,31 +16,26 @@
package android.widget;
-import android.app.Activity;
-import android.os.Bundle;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.StubActivity;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
import android.text.Selection;
import android.view.KeyEvent;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Locale;
-
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.Collection;
@LargeTest
@RunWith(Parameterized.class)
diff --git a/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java
index b100acb..b6cf7d3 100644
--- a/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java
@@ -16,31 +16,26 @@
package android.widget;
-import android.app.Activity;
-import android.os.Bundle;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.StubActivity;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
import android.text.Selection;
import android.view.KeyEvent;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Locale;
-
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.Collection;
@LargeTest
@RunWith(Parameterized.class)
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java
index 7fc5e4f..e95676b 100644
--- a/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java
@@ -16,27 +16,21 @@
package android.widget;
-import android.app.Activity;
-import android.os.Bundle;
-import android.perftests.utils.PerfStatusReporter;
-import android.util.Log;
-
import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.StubActivity;
import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
import android.support.test.rule.ActivityTestRule;
-import android.support.test.InstrumentationRegistry;
-import java.util.Locale;
-import java.util.Collection;
-import java.util.Arrays;
-
-import org.junit.Test;
import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Locale;
@LargeTest
@RunWith(Parameterized.class)
diff --git a/api/current.txt b/api/current.txt
index 2368231..25cac5c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -919,6 +919,7 @@
field public static final int multiprocess = 16842771; // 0x1010013
field public static final int name = 16842755; // 0x1010003
field public static final int navigationBarColor = 16843858; // 0x1010452
+ field public static final int navigationBarDividerColor = 16844141; // 0x101056d
field public static final int navigationContentDescription = 16843969; // 0x10104c1
field public static final int navigationIcon = 16843968; // 0x10104c0
field public static final int navigationMode = 16843471; // 0x10102cf
@@ -8972,6 +8973,7 @@
field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
+ field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -25639,6 +25641,67 @@
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
+ public final class IpSecAlgorithm implements android.os.Parcelable {
+ ctor public IpSecAlgorithm(java.lang.String, byte[]);
+ ctor public IpSecAlgorithm(java.lang.String, byte[], int);
+ method public int describeContents();
+ method public byte[] getKey();
+ method public java.lang.String getName();
+ method public int getTruncationLengthBits();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)";
+ }
+
+ public final class IpSecManager {
+ method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
+ }
+
+ public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
+ }
+
+ public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
+ method public void close();
+ method protected void finalize();
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+ method public void close() throws java.io.IOException;
+ method public int getPort();
+ method public java.io.FileDescriptor getSocket();
+ }
+
+ public final class IpSecTransform implements java.lang.AutoCloseable {
+ method public void close();
+ field public static final int DIRECTION_IN = 0; // 0x0
+ field public static final int DIRECTION_OUT = 1; // 0x1
+ }
+
+ public static class IpSecTransform.Builder {
+ ctor public IpSecTransform.Builder(android.content.Context);
+ method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
+ }
+
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -48630,19 +48693,26 @@
package android.view.textclassifier {
public final class TextClassification {
+ method public int getActionCount();
method public float getConfidenceScore(java.lang.String);
method public java.lang.String getEntity(int);
method public int getEntityCount();
+ method public android.graphics.drawable.Drawable getIcon(int);
method public android.graphics.drawable.Drawable getIcon();
+ method public android.content.Intent getIntent(int);
method public android.content.Intent getIntent();
+ method public java.lang.CharSequence getLabel(int);
method public java.lang.CharSequence getLabel();
+ method public android.view.View.OnClickListener getOnClickListener(int);
method public android.view.View.OnClickListener getOnClickListener();
method public java.lang.String getText();
}
public static final class TextClassification.Builder {
ctor public TextClassification.Builder();
+ method public android.view.textclassifier.TextClassification.Builder addAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable, android.view.View.OnClickListener);
method public android.view.textclassifier.TextClassification build();
+ method public android.view.textclassifier.TextClassification.Builder clearActions();
method public android.view.textclassifier.TextClassification.Builder setEntityType(java.lang.String, float);
method public android.view.textclassifier.TextClassification.Builder setIcon(android.graphics.drawable.Drawable);
method public android.view.textclassifier.TextClassification.Builder setIntent(android.content.Intent);
diff --git a/api/system-current.txt b/api/system-current.txt
index cdd28b8..82cdbaf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1051,6 +1051,7 @@
field public static final int multiprocess = 16842771; // 0x1010013
field public static final int name = 16842755; // 0x1010003
field public static final int navigationBarColor = 16843858; // 0x1010452
+ field public static final int navigationBarDividerColor = 16844141; // 0x101056d
field public static final int navigationContentDescription = 16843969; // 0x10104c1
field public static final int navigationIcon = 16843968; // 0x10104c0
field public static final int navigationMode = 16843471; // 0x10102cf
@@ -9484,6 +9485,7 @@
field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
+ field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -27874,6 +27876,69 @@
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
+ public final class IpSecAlgorithm implements android.os.Parcelable {
+ ctor public IpSecAlgorithm(java.lang.String, byte[]);
+ ctor public IpSecAlgorithm(java.lang.String, byte[], int);
+ method public int describeContents();
+ method public byte[] getKey();
+ method public java.lang.String getName();
+ method public int getTruncationLengthBits();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)";
+ }
+
+ public final class IpSecManager {
+ method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
+ }
+
+ public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
+ }
+
+ public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
+ method public void close();
+ method protected void finalize();
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+ method public void close() throws java.io.IOException;
+ method public int getPort();
+ method public java.io.FileDescriptor getSocket();
+ }
+
+ public final class IpSecTransform implements java.lang.AutoCloseable {
+ method public void close();
+ field public static final int DIRECTION_IN = 0; // 0x0
+ field public static final int DIRECTION_OUT = 1; // 0x1
+ }
+
+ public static class IpSecTransform.Builder {
+ ctor public IpSecTransform.Builder(android.content.Context);
+ method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
+ method public android.net.IpSecTransform.Builder setNattKeepalive(int);
+ method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
+ method public android.net.IpSecTransform.Builder setUnderlyingNetwork(android.net.Network);
+ }
+
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -52324,19 +52389,26 @@
package android.view.textclassifier {
public final class TextClassification {
+ method public int getActionCount();
method public float getConfidenceScore(java.lang.String);
method public java.lang.String getEntity(int);
method public int getEntityCount();
+ method public android.graphics.drawable.Drawable getIcon(int);
method public android.graphics.drawable.Drawable getIcon();
+ method public android.content.Intent getIntent(int);
method public android.content.Intent getIntent();
+ method public java.lang.CharSequence getLabel(int);
method public java.lang.CharSequence getLabel();
+ method public android.view.View.OnClickListener getOnClickListener(int);
method public android.view.View.OnClickListener getOnClickListener();
method public java.lang.String getText();
}
public static final class TextClassification.Builder {
ctor public TextClassification.Builder();
+ method public android.view.textclassifier.TextClassification.Builder addAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable, android.view.View.OnClickListener);
method public android.view.textclassifier.TextClassification build();
+ method public android.view.textclassifier.TextClassification.Builder clearActions();
method public android.view.textclassifier.TextClassification.Builder setEntityType(java.lang.String, float);
method public android.view.textclassifier.TextClassification.Builder setIcon(android.graphics.drawable.Drawable);
method public android.view.textclassifier.TextClassification.Builder setIntent(android.content.Intent);
diff --git a/api/test-current.txt b/api/test-current.txt
index 90ecb8c..34b663b 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -919,6 +919,7 @@
field public static final int multiprocess = 16842771; // 0x1010013
field public static final int name = 16842755; // 0x1010003
field public static final int navigationBarColor = 16843858; // 0x1010452
+ field public static final int navigationBarDividerColor = 16844141; // 0x101056d
field public static final int navigationContentDescription = 16843969; // 0x10104c1
field public static final int navigationIcon = 16843968; // 0x10104c0
field public static final int navigationMode = 16843471; // 0x10102cf
@@ -3863,6 +3864,8 @@
method public void moveTaskToFront(int, int);
method public void moveTaskToFront(int, int, android.os.Bundle);
method public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
+ method public void removeStacksInWindowingModes(int[]) throws java.lang.SecurityException;
+ method public void removeStacksWithActivityTypes(int[]) throws java.lang.SecurityException;
method public deprecated void restartPackage(java.lang.String);
method public static void setVrThread(int);
method public void setWatchHeapLimit(long);
@@ -4016,14 +4019,11 @@
}
public static class ActivityManager.StackId {
- field public static final int ASSISTANT_STACK_ID = 6; // 0x6
field public static final int DOCKED_STACK_ID = 3; // 0x3
field public static final int FREEFORM_WORKSPACE_STACK_ID = 2; // 0x2
field public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1; // 0x1
- field public static final int HOME_STACK_ID = 0; // 0x0
field public static final int INVALID_STACK_ID = -1; // 0xffffffff
field public static final int PINNED_STACK_ID = 4; // 0x4
- field public static final int RECENTS_STACK_ID = 5; // 0x5
}
public static class ActivityManager.TaskDescription implements android.os.Parcelable {
@@ -9047,6 +9047,7 @@
field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
+ field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -25838,6 +25839,67 @@
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
+ public final class IpSecAlgorithm implements android.os.Parcelable {
+ ctor public IpSecAlgorithm(java.lang.String, byte[]);
+ ctor public IpSecAlgorithm(java.lang.String, byte[], int);
+ method public int describeContents();
+ method public byte[] getKey();
+ method public java.lang.String getName();
+ method public int getTruncationLengthBits();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)";
+ }
+
+ public final class IpSecManager {
+ method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
+ }
+
+ public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
+ }
+
+ public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
+ method public void close();
+ method protected void finalize();
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+ method public void close() throws java.io.IOException;
+ method public int getPort();
+ method public java.io.FileDescriptor getSocket();
+ }
+
+ public final class IpSecTransform implements java.lang.AutoCloseable {
+ method public void close();
+ field public static final int DIRECTION_IN = 0; // 0x0
+ field public static final int DIRECTION_OUT = 1; // 0x1
+ }
+
+ public static class IpSecTransform.Builder {
+ ctor public IpSecTransform.Builder(android.content.Context);
+ method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
+ }
+
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -49187,19 +49249,26 @@
package android.view.textclassifier {
public final class TextClassification {
+ method public int getActionCount();
method public float getConfidenceScore(java.lang.String);
method public java.lang.String getEntity(int);
method public int getEntityCount();
+ method public android.graphics.drawable.Drawable getIcon(int);
method public android.graphics.drawable.Drawable getIcon();
+ method public android.content.Intent getIntent(int);
method public android.content.Intent getIntent();
+ method public java.lang.CharSequence getLabel(int);
method public java.lang.CharSequence getLabel();
+ method public android.view.View.OnClickListener getOnClickListener(int);
method public android.view.View.OnClickListener getOnClickListener();
method public java.lang.String getText();
}
public static final class TextClassification.Builder {
ctor public TextClassification.Builder();
+ method public android.view.textclassifier.TextClassification.Builder addAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable, android.view.View.OnClickListener);
method public android.view.textclassifier.TextClassification build();
+ method public android.view.textclassifier.TextClassification.Builder clearActions();
method public android.view.textclassifier.TextClassification.Builder setEntityType(java.lang.String, float);
method public android.view.textclassifier.TextClassification.Builder setIcon(android.graphics.drawable.Drawable);
method public android.view.textclassifier.TextClassification.Builder setIntent(android.content.Intent);
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 559e8de..7e78d6c 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -24,6 +24,11 @@
BootAnimationUtil.cpp \
ifeq ($(PRODUCT_IOT),true)
+
+LOCAL_SHARED_LIBRARIES += \
+ libandroidthings \
+ libchrome \
+
LOCAL_SRC_FILES += \
iot/iotbootanimation_main.cpp \
iot/BootAction.cpp
@@ -84,6 +89,12 @@
libtinyalsa \
libbase
+ifeq ($(PRODUCT_IOT),true)
+
+LOCAL_INIT_RC := iot/bootanim_iot.rc
+
+endif # PRODUCT_IOT
+
ifdef TARGET_32_BIT_SURFACEFLINGER
LOCAL_32_BIT_ONLY := true
endif
diff --git a/cmds/bootanimation/iot/BootAction.cpp b/cmds/bootanimation/iot/BootAction.cpp
index 889eb2f..665b4d9 100644
--- a/cmds/bootanimation/iot/BootAction.cpp
+++ b/cmds/bootanimation/iot/BootAction.cpp
@@ -18,25 +18,96 @@
#define LOG_TAG "BootAction"
-#include <android-base/strings.h>
-#include <cpu-features.h>
#include <dlfcn.h>
+#include <fcntl.h>
+
+#include <map>
+
+#include <android-base/file.h>
+#include <android-base/strings.h>
+#include <base/json/json_parser.h>
+#include <base/json/json_value_converter.h>
+#include <cpu-features.h>
#include <pio/peripheral_manager_client.h>
#include <utils/Log.h>
+using android::base::ReadFileToString;
+using android::base::RemoveFileIfExists;
using android::base::Split;
using android::base::Join;
using android::base::StartsWith;
using android::base::EndsWith;
+using base::JSONReader;
+using base::Value;
namespace android {
+// Brightness and volume are stored as integer strings in next_boot.json.
+// They are divided by this constant to produce the actual float values in
+// range [0.0, 1.0]. This constant must match its counterpart in
+// DeviceManager.
+constexpr const float kFloatScaleFactor = 1000.0f;
+
+constexpr const char* kNextBootFile = "/data/misc/bootanimation/next_boot.json";
+constexpr const char* kLastBootFile = "/data/misc/bootanimation/last_boot.json";
+
+bool loadParameters(BootAction::SavedBootParameters* parameters)
+{
+ std::string contents;
+ if (!ReadFileToString(kLastBootFile, &contents)) {
+ if (errno != ENOENT)
+ ALOGE("Unable to read from %s: %s", kLastBootFile, strerror(errno));
+
+ return false;
+ }
+
+ std::unique_ptr<Value> json = JSONReader::Read(contents);
+ if (json.get() == nullptr) return false;
+
+ JSONValueConverter<BootAction::SavedBootParameters> converter;
+ if (!converter.Convert(*(json.get()), parameters)) return false;
+
+ return true;
+}
+
+void BootAction::SavedBootParameters::RegisterJSONConverter(
+ JSONValueConverter<SavedBootParameters> *converter) {
+ converter->RegisterIntField("brightness", &SavedBootParameters::brightness);
+ converter->RegisterIntField("volume", &SavedBootParameters::volume);
+ converter->RegisterRepeatedString("param_names",
+ &SavedBootParameters::param_names);
+ converter->RegisterRepeatedString("param_values",
+ &SavedBootParameters::param_values);
+}
+
BootAction::~BootAction() {
if (mLibHandle != nullptr) {
dlclose(mLibHandle);
}
}
+void BootAction::swapBootConfigs() {
+ // rename() will fail if next_boot.json doesn't exist, so delete
+ // last_boot.json manually first.
+ std::string err;
+ if (!RemoveFileIfExists(kLastBootFile, &err))
+ ALOGE("Unable to delete last boot file: %s", err.c_str());
+
+ if (rename(kNextBootFile, kLastBootFile) && errno != ENOENT)
+ ALOGE("Unable to swap boot files: %s", strerror(errno));
+
+ int fd = open(kNextBootFile, O_CREAT, DEFFILEMODE);
+ if (fd == -1) {
+ ALOGE("Unable to create next boot file: %s", strerror(errno));
+ } else {
+ // Make next_boot.json writible to everyone so DeviceManagementService
+ // can save parameters there.
+ if (fchmod(fd, DEFFILEMODE))
+ ALOGE("Unable to set next boot file permissions: %s", strerror(errno));
+ close(fd);
+ }
+}
+
bool BootAction::init(const std::string& libraryPath) {
APeripheralManagerClient* client = nullptr;
ALOGD("Connecting to peripheralmanager");
@@ -51,6 +122,28 @@
ALOGD("Peripheralmanager is up.");
APeripheralManagerClient_delete(client);
+ float brightness = -1.0f;
+ float volume = -1.0f;
+ std::vector<ABootActionParameter> parameters;
+ SavedBootParameters saved_parameters;
+
+ if (loadParameters(&saved_parameters)) {
+ // TODO(b/65462981): Do something with brightness and volume?
+ brightness = saved_parameters.brightness / kFloatScaleFactor;
+ volume = saved_parameters.volume / kFloatScaleFactor;
+
+ if (saved_parameters.param_names.size() == saved_parameters.param_values.size()) {
+ for (size_t i = 0; i < saved_parameters.param_names.size(); i++) {
+ parameters.push_back({
+ .key = saved_parameters.param_names[i]->c_str(),
+ .value = saved_parameters.param_values[i]->c_str()
+ });
+ }
+ } else {
+ ALOGW("Parameter names and values size mismatch");
+ }
+ }
+
ALOGI("Loading boot action %s", libraryPath.c_str());
mLibHandle = dlopen(libraryPath.c_str(), RTLD_NOW);
if (mLibHandle == nullptr) {
@@ -82,7 +175,7 @@
}
ALOGD("Entering boot_action_init");
- bool result = mLibInit();
+ bool result = mLibInit(parameters.data(), parameters.size());
ALOGD("Returned from boot_action_init");
return result;
}
diff --git a/cmds/bootanimation/iot/BootAction.h b/cmds/bootanimation/iot/BootAction.h
index 495aa4f..3cd43be 100644
--- a/cmds/bootanimation/iot/BootAction.h
+++ b/cmds/bootanimation/iot/BootAction.h
@@ -17,16 +17,36 @@
#ifndef _BOOTANIMATION_BOOTACTION_H
#define _BOOTANIMATION_BOOTACTION_H
+#include <map>
#include <string>
+#include <base/json/json_value_converter.h>
+#include <boot_action/boot_action.h> // libandroidthings native API.
#include <utils/RefBase.h>
+using base::JSONValueConverter;
+
namespace android {
class BootAction : public RefBase {
public:
+ struct SavedBootParameters {
+ int brightness;
+ int volume;
+ ScopedVector<std::string> param_names;
+ ScopedVector<std::string> param_values;
+ static void RegisterJSONConverter(
+ JSONValueConverter<SavedBootParameters>* converter);
+ };
+
~BootAction();
+ // Rename next_boot.json to last_boot.json so that we don't repeat
+ // parameters if there is a crash before the framework comes up.
+ // TODO(b/65462981): Is this what we want to do? Should we swap in the
+ // framework instead?
+ static void swapBootConfigs();
+
// libraryPath is a fully qualified path to the target .so library.
bool init(const std::string& libraryPath);
@@ -41,7 +61,8 @@
void shutdown();
private:
- typedef bool (*libInit)();
+ typedef bool (*libInit)(const ABootActionParameter* parameters,
+ size_t num_parameters);
typedef void (*libStartPart)(int partNumber, int playNumber);
typedef void (*libShutdown)();
diff --git a/cmds/bootanimation/iot/bootanim_iot.rc b/cmds/bootanimation/iot/bootanim_iot.rc
new file mode 100644
index 0000000..2fc1336
--- /dev/null
+++ b/cmds/bootanimation/iot/bootanim_iot.rc
@@ -0,0 +1,2 @@
+on post-fs-data
+ mkdir /data/misc/bootanimation 0777 root root
diff --git a/cmds/bootanimation/iot/iotbootanimation_main.cpp b/cmds/bootanimation/iot/iotbootanimation_main.cpp
index d62478b..441a140 100644
--- a/cmds/bootanimation/iot/iotbootanimation_main.cpp
+++ b/cmds/bootanimation/iot/iotbootanimation_main.cpp
@@ -64,6 +64,20 @@
void shutdown() override {
if (mBootAction != nullptr) {
+ // If we have a bootaction we want to wait until we are actually
+ // told to shut down. If the animation exits early keep the action
+ // running.
+ char value[PROPERTY_VALUE_MAX] = {0};
+ for (int exitRequested = 0; exitRequested == 0; ) {
+ property_get("service.bootanim.exit", value, "0");
+ exitRequested = atoi(value);
+
+ // Poll value at 10hz.
+ if (exitRequested == 0) {
+ usleep(100000);
+ }
+ }
+
mBootAction->shutdown();
// Give it two seconds to shut down.
sleep(2);
@@ -80,6 +94,10 @@
int main() {
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
+ // TODO(b/65462981): Should we set brightness/volume here in case the boot
+ // animation is disabled?
+ BootAction::swapBootConfigs();
+
if (bootAnimationDisabled()) {
ALOGI("boot animation disabled");
return 0;
diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk
index 830bf9e..cb5fd02 100644
--- a/cmds/incidentd/Android.mk
+++ b/cmds/incidentd/Android.mk
@@ -23,7 +23,7 @@
LOCAL_MODULE := incidentd
LOCAL_SRC_FILES := \
- src/EncodedBuffer.cpp \
+ src/PrivacyBuffer.cpp \
src/FdBuffer.cpp \
src/IncidentService.cpp \
src/Privacy.cpp \
@@ -31,7 +31,6 @@
src/Section.cpp \
src/io_util.cpp \
src/main.cpp \
- src/protobuf.cpp \
src/report_directory.cpp
LOCAL_CFLAGS += \
@@ -54,6 +53,7 @@
libcutils \
libincident \
liblog \
+ libprotoutil \
libselinux \
libservices \
libutils
@@ -93,16 +93,15 @@
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
LOCAL_SRC_FILES := \
- src/EncodedBuffer.cpp \
+ src/PrivacyBuffer.cpp \
src/FdBuffer.cpp \
src/Privacy.cpp \
src/Reporter.cpp \
src/Section.cpp \
src/io_util.cpp \
- src/protobuf.cpp \
src/report_directory.cpp \
tests/section_list.cpp \
- tests/EncodedBuffer_test.cpp \
+ tests/PrivacyBuffer_test.cpp \
tests/FdBuffer_test.cpp \
tests/Reporter_test.cpp \
tests/Section_test.cpp \
@@ -116,6 +115,7 @@
libcutils \
libincident \
liblog \
+ libprotoutil \
libselinux \
libservices \
libutils \
diff --git a/cmds/incidentd/src/EncodedBuffer.cpp b/cmds/incidentd/src/EncodedBuffer.cpp
deleted file mode 100644
index e8f2c11..0000000
--- a/cmds/incidentd/src/EncodedBuffer.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "EncodedBuffer.h"
-#include "io_util.h"
-#include "protobuf.h"
-
-#include <deque>
-
-const size_t BUFFER_SIZE = 4 * 1024; // 4 KB
-
-/**
- * Read varint from iterator, the iterator will point to next available byte.
- * Return the number of bytes of the varint.
- */
-static uint32_t
-read_raw_varint(FdBuffer::iterator* it)
-{
- uint32_t val = 0;
- int i = 0;
- bool hasNext = true;
- while (hasNext) {
- hasNext = ((**it & 0x80) != 0);
- val += (**it & 0x7F) << (7*i);
- (*it)++;
- i++;
- }
- return val;
-}
-
-/**
- * Write the field to buf based on the wire type, iterator will point to next field.
- * If skip is set to true, no data will be written to buf. Return number of bytes written.
- */
-static size_t
-write_field_or_skip(FdBuffer::iterator* iter, vector<uint8_t>* buf, uint8_t wireType, bool skip)
-{
- FdBuffer::iterator snapshot = iter->snapshot();
- size_t bytesToWrite = 0;
- uint32_t varint = 0;
- switch (wireType) {
- case WIRE_TYPE_VARINT:
- varint = read_raw_varint(iter);
- if(!skip) return write_raw_varint(buf, varint);
- break;
- case WIRE_TYPE_FIXED64:
- bytesToWrite = 8;
- break;
- case WIRE_TYPE_LENGTH_DELIMITED:
- bytesToWrite = read_raw_varint(iter);
- if(!skip) write_raw_varint(buf, bytesToWrite);
- break;
- case WIRE_TYPE_FIXED32:
- bytesToWrite = 4;
- break;
- }
- if (skip) {
- *iter += bytesToWrite;
- } else {
- for (size_t i=0; i<bytesToWrite; i++) {
- buf->push_back(**iter);
- (*iter)++;
- }
- }
- return skip ? 0 : *iter - snapshot;
-}
-
-/**
- * Strip next field based on its private policy and request spec, then stores data in buf.
- * Return NO_ERROR if succeeds, otherwise BAD_VALUE is returned to indicate bad data in FdBuffer.
- *
- * The iterator must point to the head of a protobuf formatted field for successful operation.
- * After exit with NO_ERROR, iterator points to the next protobuf field's head.
- */
-static status_t
-stripField(FdBuffer::iterator* iter, vector<uint8_t>* buf, const Privacy* parentPolicy, const PrivacySpec& spec)
-{
- if (iter->outOfBound() || parentPolicy == NULL) return BAD_VALUE;
-
- uint32_t varint = read_raw_varint(iter);
- uint8_t wireType = read_wire_type(varint);
- uint32_t fieldId = read_field_id(varint);
- const Privacy* policy = parentPolicy->lookup(fieldId);
-
- if (policy == NULL || !policy->IsMessageType() || !policy->HasChildren()) {
- bool skip = !spec.CheckPremission(policy);
- size_t amt = buf->size();
- if (!skip) amt += write_header(buf, fieldId, wireType);
- amt += write_field_or_skip(iter, buf, wireType, skip); // point to head of next field
- return buf->size() != amt ? BAD_VALUE : NO_ERROR;
- }
- // current field is message type and its sub-fields have extra privacy policies
- deque<vector<uint8_t>> q;
- uint32_t msgSize = read_raw_varint(iter);
- size_t finalSize = 0;
- FdBuffer::iterator start = iter->snapshot();
- while ((*iter - start) != (int)msgSize) {
- vector<uint8_t> v;
- status_t err = stripField(iter, &v, policy, spec);
- if (err != NO_ERROR) return err;
- if (v.empty()) continue;
- q.push_back(v);
- finalSize += v.size();
- }
-
- write_header(buf, fieldId, wireType);
- write_raw_varint(buf, finalSize);
- buf->reserve(finalSize); // reserve the size of the field
- while (!q.empty()) {
- vector<uint8_t> subField = q.front();
- for (vector<uint8_t>::iterator it = subField.begin(); it != subField.end(); it++) {
- buf->push_back(*it);
- }
- q.pop_front();
- }
- return NO_ERROR;
-}
-
-// ================================================================================
-EncodedBuffer::EncodedBuffer(const FdBuffer& buffer, const Privacy* policy)
- : mFdBuffer(buffer),
- mPolicy(policy),
- mBuffers(),
- mSize(0)
-{
-}
-
-EncodedBuffer::~EncodedBuffer()
-{
-}
-
-status_t
-EncodedBuffer::strip(const PrivacySpec& spec)
-{
- // optimization when no strip happens
- if (mPolicy == NULL || !mPolicy->HasChildren() || spec.RequireAll()) {
- if (spec.CheckPremission(mPolicy)) mSize = mFdBuffer.size();
- return NO_ERROR;
- }
-
- FdBuffer::iterator it = mFdBuffer.begin();
- vector<uint8_t> field;
- field.reserve(BUFFER_SIZE);
-
- while (it != mFdBuffer.end()) {
- status_t err = stripField(&it, &field, mPolicy, spec);
- if (err != NO_ERROR) return err;
- if (field.size() > BUFFER_SIZE) { // rotate to another chunk if buffer size exceeds
- mBuffers.push_back(field);
- mSize += field.size();
- field.clear();
- }
- }
- if (!field.empty()) {
- mBuffers.push_back(field);
- mSize += field.size();
- }
- return NO_ERROR;
-}
-
-void
-EncodedBuffer::clear()
-{
- mSize = 0;
- mBuffers.clear();
-}
-
-size_t
-EncodedBuffer::size() const { return mSize; }
-
-status_t
-EncodedBuffer::flush(int fd)
-{
- if (size() == mFdBuffer.size()) return mFdBuffer.flush(fd);
-
- for (vector<vector<uint8_t>>::iterator it = mBuffers.begin(); it != mBuffers.end(); it++) {
- status_t err = write_all(fd, it->data(), it->size());
- if (err != NO_ERROR) return err;
- }
- return NO_ERROR;
-}
-
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index bb399b5..b7633a4 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -17,7 +17,6 @@
#define LOG_TAG "incidentd"
#include "FdBuffer.h"
-#include "io_util.h"
#include <cutils/log.h>
#include <utils/SystemClock.h>
@@ -31,10 +30,9 @@
const ssize_t MAX_BUFFER_COUNT = 256; // 4 MB max
FdBuffer::FdBuffer()
- :mBuffers(),
+ :mBuffer(BUFFER_SIZE),
mStartTime(-1),
mFinishTime(-1),
- mCurrentWritten(-1),
mTimedOut(false),
mTruncated(false)
{
@@ -42,11 +40,6 @@
FdBuffer::~FdBuffer()
{
- const int N = mBuffers.size();
- for (int i=0; i<N; i++) {
- uint8_t* buf = mBuffers[i];
- free(buf);
- }
}
status_t
@@ -60,20 +53,12 @@
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
- uint8_t* buf = NULL;
while (true) {
- if (mCurrentWritten >= BUFFER_SIZE || mCurrentWritten < 0) {
- if (mBuffers.size() == MAX_BUFFER_COUNT) {
- mTruncated = true;
- break;
- }
- buf = (uint8_t*)malloc(BUFFER_SIZE);
- if (buf == NULL) {
- return NO_MEMORY;
- }
- mBuffers.push_back(buf);
- mCurrentWritten = 0;
+ if (mBuffer.size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
+ mTruncated = true;
+ break;
}
+ if (mBuffer.writeBuffer() == NULL) return NO_MEMORY;
int64_t remainingTime = (mStartTime + timeout) - uptimeMillis();
if (remainingTime <= 0) {
@@ -91,7 +76,7 @@
if ((pfds.revents & POLLERR) != 0) {
return errno != 0 ? -errno : UNKNOWN_ERROR;
} else {
- ssize_t amt = ::read(fd, buf + mCurrentWritten, BUFFER_SIZE - mCurrentWritten);
+ ssize_t amt = ::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
if (amt < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue;
@@ -101,11 +86,10 @@
} else if (amt == 0) {
break;
}
- mCurrentWritten += amt;
+ mBuffer.wp()->move(amt);
}
}
}
-
mFinishTime = uptimeMillis();
return NO_ERROR;
}
@@ -132,20 +116,12 @@
int rpos = 0, wpos = 0;
// This is the buffer used to store processed data
- uint8_t* buf = NULL;
while (true) {
- if (mCurrentWritten >= BUFFER_SIZE || mCurrentWritten < 0) {
- if (mBuffers.size() == MAX_BUFFER_COUNT) {
- mTruncated = true;
- break;
- }
- buf = (uint8_t*)malloc(BUFFER_SIZE);
- if (buf == NULL) {
- return NO_MEMORY;
- }
- mBuffers.push_back(buf);
- mCurrentWritten = 0;
+ if (mBuffer.size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
+ mTruncated = true;
+ break;
}
+ if (mBuffer.writeBuffer() == NULL) return NO_MEMORY;
int64_t remainingTime = (mStartTime + timeoutMs) - uptimeMillis();
if (remainingTime <= 0) {
@@ -223,7 +199,7 @@
}
// read from parsing process
- ssize_t amt = ::read(fromFd, buf + mCurrentWritten, BUFFER_SIZE - mCurrentWritten);
+ ssize_t amt = ::read(fromFd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
if (amt < 0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
return -errno;
@@ -231,7 +207,7 @@
} else if (amt == 0) {
break;
} else {
- mCurrentWritten += amt;
+ mBuffer.wp()->move(amt);
}
}
@@ -242,105 +218,11 @@
size_t
FdBuffer::size() const
{
- if (mBuffers.empty()) return 0;
- return ((mBuffers.size() - 1) * BUFFER_SIZE) + mCurrentWritten;
+ return mBuffer.size();
}
-status_t
-FdBuffer::flush(int fd) const
+EncodedBuffer::iterator
+FdBuffer::data() const
{
- size_t i=0;
- status_t err = NO_ERROR;
- for (i=0; i<mBuffers.size()-1; i++) {
- err = write_all(fd, mBuffers[i], BUFFER_SIZE);
- if (err != NO_ERROR) return err;
- }
- return write_all(fd, mBuffers[i], mCurrentWritten);
-}
-
-FdBuffer::iterator
-FdBuffer::begin() const
-{
- return iterator(*this, 0, 0);
-}
-
-FdBuffer::iterator
-FdBuffer::end() const
-{
- if (mBuffers.empty() || mCurrentWritten < 0) return begin();
- if (mCurrentWritten == BUFFER_SIZE)
- // FdBuffer doesn't allocate another buf since no more bytes to read.
- return FdBuffer::iterator(*this, mBuffers.size(), 0);
- return FdBuffer::iterator(*this, mBuffers.size() - 1, mCurrentWritten);
-}
-
-// ===============================================================================
-FdBuffer::iterator::iterator(const FdBuffer& buffer, ssize_t index, ssize_t offset)
- : mFdBuffer(buffer),
- mIndex(index),
- mOffset(offset)
-{
-}
-
-FdBuffer::iterator&
-FdBuffer::iterator::operator=(iterator& other) const { return other; }
-
-FdBuffer::iterator&
-FdBuffer::iterator::operator+(size_t offset)
-{
- size_t newOffset = mOffset + offset;
- while (newOffset >= BUFFER_SIZE) {
- mIndex++;
- newOffset -= BUFFER_SIZE;
- }
- mOffset = newOffset;
- return *this;
-}
-
-FdBuffer::iterator&
-FdBuffer::iterator::operator+=(size_t offset) { return *this + offset; }
-
-FdBuffer::iterator&
-FdBuffer::iterator::operator++() { return *this + 1; }
-
-FdBuffer::iterator
-FdBuffer::iterator::operator++(int) { return *this + 1; }
-
-bool
-FdBuffer::iterator::operator==(iterator other) const
-{
- return mIndex == other.mIndex && mOffset == other.mOffset;
-}
-
-bool
-FdBuffer::iterator::operator!=(iterator other) const { return !(*this == other); }
-
-int
-FdBuffer::iterator::operator-(iterator other) const
-{
- return (int)bytesRead() - (int)other.bytesRead();
-}
-
-FdBuffer::iterator::reference
-FdBuffer::iterator::operator*() const
-{
- return mFdBuffer.mBuffers[mIndex][mOffset];
-}
-
-FdBuffer::iterator
-FdBuffer::iterator::snapshot() const
-{
- return FdBuffer::iterator(mFdBuffer, mIndex, mOffset);
-}
-
-size_t
-FdBuffer::iterator::bytesRead() const
-{
- return mIndex * BUFFER_SIZE + mOffset;
-}
-
-bool
-FdBuffer::iterator::outOfBound() const
-{
- return bytesRead() > mFdBuffer.size();
+ return mBuffer.begin();
}
diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h
index dfe39c6..8857ae7 100644
--- a/cmds/incidentd/src/FdBuffer.h
+++ b/cmds/incidentd/src/FdBuffer.h
@@ -17,11 +17,11 @@
#ifndef FD_BUFFER_H
#define FD_BUFFER_H
+#include <android/util/EncodedBuffer.h>
#include <utils/Errors.h>
-#include <vector>
-
using namespace android;
+using namespace android::util;
using namespace std;
/**
@@ -71,52 +71,19 @@
size_t size() const;
/**
- * Flush all the data to given file descriptor;
- */
- status_t flush(int fd) const;
-
- /**
* How long the read took in milliseconds.
*/
int64_t durationMs() const { return mFinishTime - mStartTime; }
/**
- * Read data stored in FdBuffer
+ * Reader API for data stored in FdBuffer
*/
- class iterator;
- friend class iterator;
- class iterator : public std::iterator<std::random_access_iterator_tag, uint8_t> {
- public:
- iterator(const FdBuffer& buffer, ssize_t index, ssize_t offset);
- iterator& operator=(iterator& other) const;
- iterator& operator+(size_t offset);
- iterator& operator+=(size_t offset);
- iterator& operator++();
- iterator operator++(int);
- bool operator==(iterator other) const;
- bool operator!=(iterator other) const;
- int operator-(iterator other) const;
- reference operator*() const;
-
- // return the snapshot of the current iterator
- iterator snapshot() const;
- // how many bytes are read
- size_t bytesRead() const;
- // random access could make the iterator out of bound
- bool outOfBound() const;
- private:
- const FdBuffer& mFdBuffer;
- size_t mIndex;
- size_t mOffset;
- };
- iterator begin() const;
- iterator end() const;
+ EncodedBuffer::iterator data() const;
private:
- vector<uint8_t*> mBuffers;
+ EncodedBuffer mBuffer;
int64_t mStartTime;
int64_t mFinishTime;
- ssize_t mCurrentWritten;
bool mTimedOut;
bool mTruncated;
};
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
new file mode 100644
index 0000000..07a064cf
--- /dev/null
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+#include "PrivacyBuffer.h"
+#include "io_util.h"
+
+#include <android/util/protobuf.h>
+#include <deque>
+
+using namespace android::util;
+
+/**
+ * Write the field to buf based on the wire type, iterator will point to next field.
+ * If skip is set to true, no data will be written to buf. Return number of bytes written.
+ */
+static size_t
+write_field_or_skip(EncodedBuffer::iterator* iter, EncodedBuffer* buf, uint8_t wireType, bool skip)
+{
+ EncodedBuffer::Pointer snapshot = iter->rp()->copy();
+ size_t bytesToWrite = 0;
+ uint32_t varint = 0;
+ switch (wireType) {
+ case WIRE_TYPE_VARINT:
+ varint = iter->readRawVarint();
+ if(!skip) return buf->writeRawVarint(varint);
+ break;
+ case WIRE_TYPE_FIXED64:
+ bytesToWrite = 8;
+ break;
+ case WIRE_TYPE_LENGTH_DELIMITED:
+ bytesToWrite = iter->readRawVarint();
+ if(!skip) buf->writeRawVarint(bytesToWrite);
+ break;
+ case WIRE_TYPE_FIXED32:
+ bytesToWrite = 4;
+ break;
+ }
+ if (skip) {
+ iter->rp()->move(bytesToWrite);
+ } else {
+ for (size_t i=0; i<bytesToWrite; i++) {
+ *buf->writeBuffer() = iter->next();
+ buf->wp()->move();
+ }
+ }
+ return skip ? 0 : iter->rp()->pos() - snapshot.pos();
+}
+
+/**
+ * Strip next field based on its private policy and request spec, then stores data in buf.
+ * Return NO_ERROR if succeeds, otherwise BAD_VALUE is returned to indicate bad data in FdBuffer.
+ *
+ * The iterator must point to the head of a protobuf formatted field for successful operation.
+ * After exit with NO_ERROR, iterator points to the next protobuf field's head.
+ */
+static status_t
+stripField(EncodedBuffer::iterator* iter, EncodedBuffer* buf, const Privacy* parentPolicy, const PrivacySpec& spec)
+{
+ if (!iter->hasNext() || parentPolicy == NULL) return BAD_VALUE;
+ uint32_t varint = iter->readRawVarint();
+ uint8_t wireType = read_wire_type(varint);
+ uint32_t fieldId = read_field_id(varint);
+ const Privacy* policy = parentPolicy->lookup(fieldId);
+
+ if (policy == NULL || !policy->IsMessageType() || !policy->HasChildren()) {
+ bool skip = !spec.CheckPremission(policy);
+ size_t amt = buf->size();
+ if (!skip) amt += buf->writeHeader(fieldId, wireType);
+ amt += write_field_or_skip(iter, buf, wireType, skip); // point to head of next field
+ return buf->size() != amt ? BAD_VALUE : NO_ERROR;
+ }
+ // current field is message type and its sub-fields have extra privacy policies
+ deque<EncodedBuffer*> q;
+ uint32_t msgSize = iter->readRawVarint();
+ size_t finalSize = 0;
+ EncodedBuffer::Pointer start = iter->rp()->copy();
+ while (iter->rp()->pos() - start.pos() != msgSize) {
+ EncodedBuffer* v = new EncodedBuffer();
+ status_t err = stripField(iter, v, policy, spec);
+ if (err != NO_ERROR) return err;
+ if (v->size() == 0) continue;
+ q.push_back(v);
+ finalSize += v->size();
+ }
+
+ buf->writeHeader(fieldId, wireType);
+ buf->writeRawVarint(finalSize);
+ while (!q.empty()) {
+ EncodedBuffer* subField = q.front();
+ EncodedBuffer::iterator it = subField->begin();
+ while (it.hasNext()) {
+ *buf->writeBuffer() = it.next();
+ buf->wp()->move();
+ }
+ q.pop_front();
+ delete subField;
+ }
+ return NO_ERROR;
+}
+
+// ================================================================================
+PrivacyBuffer::PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data)
+ :mPolicy(policy),
+ mData(data),
+ mBuffer(0),
+ mSize(0)
+{
+}
+
+PrivacyBuffer::~PrivacyBuffer()
+{
+}
+
+status_t
+PrivacyBuffer::strip(const PrivacySpec& spec)
+{
+ // optimization when no strip happens
+ if (mPolicy == NULL || !mPolicy->HasChildren() || spec.RequireAll()) {
+ if (spec.CheckPremission(mPolicy)) mSize = mData.size();
+ return NO_ERROR;
+ }
+ while (mData.hasNext()) {
+ status_t err = stripField(&mData, &mBuffer, mPolicy, spec);
+ if (err != NO_ERROR) return err;
+ }
+ if (mData.bytesRead() != mData.size()) return BAD_VALUE;
+ mSize = mBuffer.size();
+ mData.rp()->rewind(); // rewind the read pointer back to beginning after the strip.
+ return NO_ERROR;
+}
+
+void
+PrivacyBuffer::clear()
+{
+ mSize = 0;
+ mBuffer.wp()->rewind();
+}
+
+size_t
+PrivacyBuffer::size() const { return mSize; }
+
+status_t
+PrivacyBuffer::flush(int fd)
+{
+ status_t err = NO_ERROR;
+ EncodedBuffer::iterator iter = size() == mData.size() ? mData : mBuffer.begin();
+ while (iter.readBuffer() != NULL) {
+ err = write_all(fd, iter.readBuffer(), iter.currentToRead());
+ iter.rp()->move(iter.currentToRead());
+ if (err != NO_ERROR) return err;
+ }
+ return NO_ERROR;
+}
diff --git a/cmds/incidentd/src/EncodedBuffer.h b/cmds/incidentd/src/PrivacyBuffer.h
similarity index 69%
rename from cmds/incidentd/src/EncodedBuffer.h
rename to cmds/incidentd/src/PrivacyBuffer.h
index ea8603a..720b38e 100644
--- a/cmds/incidentd/src/EncodedBuffer.h
+++ b/cmds/incidentd/src/PrivacyBuffer.h
@@ -14,25 +14,27 @@
* limitations under the License.
*/
-#ifndef ENCODED_BUFFER_H
-#define ENCODED_BUFFER_H
+#ifndef PRIVACY_BUFFER_H
+#define PRIVACY_BUFFER_H
-#include "FdBuffer.h"
#include "Privacy.h"
+#include <android/util/EncodedBuffer.h>
#include <stdint.h>
-#include <vector>
+#include <utils/Errors.h>
+
+using namespace android;
+using namespace android::util;
/**
- * EncodedBuffer is constructed from FdBuffer which holds original protobuf formatted data and
- * its privacy policy in its tagged proto message. The class strips PII-sensitive fields
- * based on the request and holds stripped data in its buffer for output.
+ * PrivacyBuffer holds the original protobuf data and strips PII-sensitive fields
+ * based on the request and holds stripped data in its own buffer for output.
*/
-class EncodedBuffer
+class PrivacyBuffer
{
public:
- EncodedBuffer(const FdBuffer& buffer, const Privacy* policy);
- ~EncodedBuffer();
+ PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data);
+ ~PrivacyBuffer();
/**
* Strip based on the request and hold data in its own buffer. Return NO_ERROR if strip succeeds.
@@ -55,10 +57,11 @@
status_t flush(int fd);
private:
- const FdBuffer& mFdBuffer;
const Privacy* mPolicy;
- vector<vector<uint8_t>> mBuffers;
+ EncodedBuffer::iterator& mData;
+
+ EncodedBuffer mBuffer;
size_t mSize;
};
-#endif // ENCODED_BUFFER_H
\ No newline at end of file
+#endif // PRIVACY_BUFFER_H
\ No newline at end of file
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index 11347e2..917b70d 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -179,8 +179,8 @@
// Execute - go get the data and write it into the file descriptors.
err = (*section)->Execute(&batch);
if (err != NO_ERROR) {
- ALOGW("Incident section %s (%d) failed. Stopping report.",
- (*section)->name.string(), id);
+ ALOGW("Incident section %s (%d) failed: %s. Stopping report.",
+ (*section)->name.string(), id, strerror(-err));
goto DONE;
}
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 166fef0..892bcca 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -16,15 +16,15 @@
#define LOG_TAG "incidentd"
-#include "EncodedBuffer.h"
#include "FdBuffer.h"
#include "Privacy.h"
+#include "PrivacyBuffer.h"
#include "Section.h"
#include "io_util.h"
-#include "protobuf.h"
#include "section_list.h"
+#include <android/util/protobuf.h>
#include <private/android_filesystem_config.h>
#include <binder/IServiceManager.h>
#include <map>
@@ -32,8 +32,13 @@
#include <wait.h>
#include <unistd.h>
+using namespace android::util;
using namespace std;
+// special section ids
+const int FIELD_ID_INCIDENT_HEADER = 1;
+
+// incident section parameters
const int WAIT_MAX = 5;
const struct timespec WAIT_INTERVAL_NS = {0, 200 * 1000 * 1000};
const char* INCIDENT_HELPER = "/system/bin/incident_helper";
@@ -127,7 +132,8 @@
write_report_requests(const int id, const FdBuffer& buffer, ReportRequestSet* requests)
{
status_t err = -EBADF;
- EncodedBuffer encodedBuffer(buffer, get_privacy_of_section(id));
+ EncodedBuffer::iterator data = buffer.data();
+ PrivacyBuffer privacyBuffer(get_privacy_of_section(id), data);
int writeable = 0;
// The streaming ones, group requests by spec in order to save unnecessary strip operations
@@ -143,34 +149,34 @@
for (map<PrivacySpec, vector<sp<ReportRequest>>>::iterator mit = requestsBySpec.begin(); mit != requestsBySpec.end(); mit++) {
PrivacySpec spec = mit->first;
- err = encodedBuffer.strip(spec);
- if (err != NO_ERROR) return err; // it means the encodedBuffer data is corrupted.
- if (encodedBuffer.size() == 0) continue;
+ err = privacyBuffer.strip(spec);
+ if (err != NO_ERROR) return err; // it means the privacyBuffer data is corrupted.
+ if (privacyBuffer.size() == 0) continue;
for (vector<sp<ReportRequest>>::iterator it = mit->second.begin(); it != mit->second.end(); it++) {
sp<ReportRequest> request = *it;
- err = write_section_header(request->fd, id, encodedBuffer.size());
+ err = write_section_header(request->fd, id, privacyBuffer.size());
if (err != NO_ERROR) { request->err = err; continue; }
- err = encodedBuffer.flush(request->fd);
+ err = privacyBuffer.flush(request->fd);
if (err != NO_ERROR) { request->err = err; continue; }
writeable++;
- ALOGD("Section %d flushed %zu bytes to fd %d with spec %d", id, encodedBuffer.size(), request->fd, spec.dest);
+ ALOGD("Section %d flushed %zu bytes to fd %d with spec %d", id, privacyBuffer.size(), request->fd, spec.dest);
}
- encodedBuffer.clear();
+ privacyBuffer.clear();
}
// The dropbox file
if (requests->mainFd() >= 0) {
- err = encodedBuffer.strip(get_default_dropbox_spec());
+ err = privacyBuffer.strip(get_default_dropbox_spec());
if (err != NO_ERROR) return err; // the buffer data is corrupted.
- if (encodedBuffer.size() == 0) goto DONE;
+ if (privacyBuffer.size() == 0) goto DONE;
- err = write_section_header(requests->mainFd(), id, encodedBuffer.size());
+ err = write_section_header(requests->mainFd(), id, privacyBuffer.size());
if (err != NO_ERROR) { requests->setMainFd(-1); goto DONE; }
- err = encodedBuffer.flush(requests->mainFd());
+ err = privacyBuffer.flush(requests->mainFd());
if (err != NO_ERROR) { requests->setMainFd(-1); goto DONE; }
writeable++;
- ALOGD("Section %d flushed %zu bytes to dropbox %d", id, encodedBuffer.size(), requests->mainFd());
+ ALOGD("Section %d flushed %zu bytes to dropbox %d", id, privacyBuffer.size(), requests->mainFd());
}
DONE:
diff --git a/cmds/incidentd/tests/FdBuffer_test.cpp b/cmds/incidentd/tests/FdBuffer_test.cpp
index d1436b2..2afa778 100644
--- a/cmds/incidentd/tests/FdBuffer_test.cpp
+++ b/cmds/incidentd/tests/FdBuffer_test.cpp
@@ -49,12 +49,11 @@
void AssertBufferContent(const char* expected) {
int i=0;
- FdBuffer::iterator it = buffer.begin();
- while (expected[i] != '\0') {
- ASSERT_EQ(*it, expected[i++]);
- it++;
+ EncodedBuffer::iterator it = buffer.data();
+ while (it.hasNext()) {
+ ASSERT_EQ(it.next(), expected[i++]);
}
- ASSERT_EQ(it, buffer.end());
+ EXPECT_EQ(expected[i], '\0');
}
bool DoDataStream(int rFd, int wFd) {
@@ -92,20 +91,8 @@
}
TEST_F(FdBufferTest, IterateEmpty) {
- FdBuffer::iterator it = buffer.begin();
- EXPECT_EQ(it, buffer.end());
- it += 1;
- EXPECT_TRUE(it.outOfBound());
-}
-
-TEST_F(FdBufferTest, IteratorSnapshot) {
- FdBuffer::iterator it = buffer.begin();
- it += 4;
- FdBuffer::iterator snapshot = it.snapshot();
- it += 5;
- EXPECT_TRUE(snapshot != it);
- EXPECT_EQ(it - snapshot, 5);
- EXPECT_EQ(snapshot - it, -5);
+ EncodedBuffer::iterator it = buffer.data();
+ EXPECT_FALSE(it.hasNext());
}
TEST_F(FdBufferTest, ReadAndIterate) {
@@ -114,15 +101,15 @@
ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
int i=0;
- for (FdBuffer::iterator it = buffer.begin(); it != buffer.end(); ++it) {
- EXPECT_EQ(*it, (uint8_t)testdata[i++]);
+ EncodedBuffer::iterator it = buffer.data();
+ while (it.hasNext()) {
+ EXPECT_EQ(it.next(), (uint8_t)testdata[i++]);
}
- FdBuffer::iterator it = buffer.begin();
- it += buffer.size();
- EXPECT_EQ(it, buffer.end());
+ it.rp()->rewind();
+ it.rp()->move(buffer.size());
EXPECT_EQ(it.bytesRead(), testdata.size());
- EXPECT_FALSE(it.outOfBound());
+ EXPECT_FALSE(it.hasNext());
}
TEST_F(FdBufferTest, ReadTimeout) {
@@ -258,13 +245,15 @@
EXPECT_FALSE(buffer.timedOut());
EXPECT_TRUE(buffer.truncated());
wait(&pid);
- FdBuffer::iterator it = buffer.begin();
- it += fourMB;
+ EncodedBuffer::iterator it = buffer.data();
+ it.rp()->move(fourMB);
EXPECT_EQ(it.bytesRead(), fourMB);
- EXPECT_EQ(it, buffer.end());
- for (FdBuffer::iterator it = buffer.begin(); it != buffer.end(); it++) {
+ EXPECT_FALSE(it.hasNext());
+
+ it.rp()->rewind();
+ while (it.hasNext()) {
char c = 'A' + (it.bytesRead() % 64 / 8);
- ASSERT_TRUE(*it == c);
+ ASSERT_TRUE(it.next() == c);
}
}
}
diff --git a/cmds/incidentd/tests/EncodedBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
similarity index 77%
rename from cmds/incidentd/tests/EncodedBuffer_test.cpp
rename to cmds/incidentd/tests/PrivacyBuffer_test.cpp
index 37a938a..8f6e355 100644
--- a/cmds/incidentd/tests/EncodedBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "EncodedBuffer.h"
+#include "FdBuffer.h"
+#include "PrivacyBuffer.h"
#include <android-base/file.h>
#include <android-base/test_utils.h>
@@ -42,9 +43,10 @@
const string FIX32_FIELD_4 = "\x25\xff\xff\xff\xff"; // -1
const string MESSAGE_FIELD_5 = "\x2a\x10" + VARINT_FIELD_1 + STRING_FIELD_2;
-class EncodedBufferTest : public Test {
+
+class PrivacyBufferTest : public Test {
public:
- virtual ~EncodedBufferTest() {
+ virtual ~PrivacyBufferTest() {
// Delete in reverse order of construction, to be consistent with
// regular allocation/deallocation.
while (!privacies.empty()) {
@@ -60,9 +62,10 @@
void writeToFdBuffer(string str) {
ASSERT_TRUE(WriteStringToFile(str, tf.path, false));
ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, 10000));
+ ASSERT_EQ(str.size(), buffer.size());
}
- void assertBuffer(EncodedBuffer& buf, string expected) {
+ void assertBuffer(PrivacyBuffer& buf, string expected) {
ASSERT_EQ(buf.size(), expected.size());
CaptureStdout();
ASSERT_EQ(buf.flush(STDOUT_FILENO), NO_ERROR);
@@ -71,9 +74,10 @@
void assertStrip(uint8_t dest, string expected, Privacy* policy) {
PrivacySpec spec(dest);
- EncodedBuffer encodedBuf(buffer, policy);
- ASSERT_EQ(encodedBuf.strip(spec), NO_ERROR);
- assertBuffer(encodedBuf, expected);
+ EncodedBuffer::iterator bufData = buffer.data();
+ PrivacyBuffer privacyBuf(policy, bufData);
+ ASSERT_EQ(privacyBuf.strip(spec), NO_ERROR);
+ assertBuffer(privacyBuf, expected);
}
void assertStripByFields(uint8_t dest, string expected, int size, Privacy* privacy, ...) {
@@ -134,67 +138,67 @@
}
};
-TEST_F(EncodedBufferTest, NullFieldPolicy) {
+TEST_F(PrivacyBufferTest, NullFieldPolicy) {
writeToFdBuffer(STRING_FIELD_0);
assertStrip(EXPLICIT, STRING_FIELD_0, create_string_privacy(300, AUTOMATIC, NULL));
}
-TEST_F(EncodedBufferTest, StripSpecNotAllowed) {
+TEST_F(PrivacyBufferTest, StripSpecNotAllowed) {
writeToFdBuffer(STRING_FIELD_0);
assertStripByFields(AUTOMATIC, "", 1, create_privacy(0, STRING_TYPE, EXPLICIT));
}
-TEST_F(EncodedBufferTest, StripVarintField) {
+TEST_F(PrivacyBufferTest, StripVarintField) {
writeToFdBuffer(VARINT_FIELD_1);
assertStripByFields(EXPLICIT, "", 1, create_privacy(1, OTHER_TYPE, LOCAL));
}
-TEST_F(EncodedBufferTest, StripLengthDelimitedField_String) {
+TEST_F(PrivacyBufferTest, StripLengthDelimitedField_String) {
writeToFdBuffer(STRING_FIELD_2);
assertStripByFields(EXPLICIT, "", 1, create_privacy(2, STRING_TYPE, LOCAL));
}
-TEST_F(EncodedBufferTest, StripFixed64Field) {
+TEST_F(PrivacyBufferTest, StripFixed64Field) {
writeToFdBuffer(FIX64_FIELD_3);
assertStripByFields(EXPLICIT, "", 1, create_privacy(3, OTHER_TYPE, LOCAL));
}
-TEST_F(EncodedBufferTest, StripFixed32Field) {
+TEST_F(PrivacyBufferTest, StripFixed32Field) {
writeToFdBuffer(FIX32_FIELD_4);
assertStripByFields(EXPLICIT, "", 1, create_privacy(4, OTHER_TYPE, LOCAL));
}
-TEST_F(EncodedBufferTest, StripLengthDelimitedField_Message) {
+TEST_F(PrivacyBufferTest, StripLengthDelimitedField_Message) {
writeToFdBuffer(MESSAGE_FIELD_5);
assertStripByFields(EXPLICIT, "", 1, create_privacy(5, MESSAGE_TYPE, LOCAL));
}
-TEST_F(EncodedBufferTest, NoStripVarintField) {
+TEST_F(PrivacyBufferTest, NoStripVarintField) {
writeToFdBuffer(VARINT_FIELD_1);
assertStripByFields(EXPLICIT, VARINT_FIELD_1, 1, create_privacy(1, OTHER_TYPE, AUTOMATIC));
}
-TEST_F(EncodedBufferTest, NoStripLengthDelimitedField_String) {
+TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_String) {
writeToFdBuffer(STRING_FIELD_2);
assertStripByFields(EXPLICIT, STRING_FIELD_2, 1, create_privacy(2, STRING_TYPE, AUTOMATIC));
}
-TEST_F(EncodedBufferTest, NoStripFixed64Field) {
+TEST_F(PrivacyBufferTest, NoStripFixed64Field) {
writeToFdBuffer(FIX64_FIELD_3);
assertStripByFields(EXPLICIT, FIX64_FIELD_3, 1, create_privacy(3, OTHER_TYPE, AUTOMATIC));
}
-TEST_F(EncodedBufferTest, NoStripFixed32Field) {
+TEST_F(PrivacyBufferTest, NoStripFixed32Field) {
writeToFdBuffer(FIX32_FIELD_4);
assertStripByFields(EXPLICIT, FIX32_FIELD_4, 1, create_privacy(4, OTHER_TYPE, AUTOMATIC));
}
-TEST_F(EncodedBufferTest, NoStripLengthDelimitedField_Message) {
+TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_Message) {
writeToFdBuffer(MESSAGE_FIELD_5);
assertStripByFields(EXPLICIT, MESSAGE_FIELD_5, 1, create_privacy(5, MESSAGE_TYPE, AUTOMATIC));
}
-TEST_F(EncodedBufferTest, StripVarintAndString) {
+TEST_F(PrivacyBufferTest, StripVarintAndString) {
writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2
+ FIX64_FIELD_3 + FIX32_FIELD_4);
string expected = STRING_FIELD_0 + FIX64_FIELD_3 + FIX32_FIELD_4;
@@ -202,7 +206,7 @@
create_privacy(1, OTHER_TYPE, LOCAL), create_privacy(2, STRING_TYPE, LOCAL));
}
-TEST_F(EncodedBufferTest, StripVarintAndFixed64) {
+TEST_F(PrivacyBufferTest, StripVarintAndFixed64) {
writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2
+ FIX64_FIELD_3 + FIX32_FIELD_4);
string expected = STRING_FIELD_0 + STRING_FIELD_2 + FIX32_FIELD_4;
@@ -210,46 +214,49 @@
create_privacy(1, OTHER_TYPE, LOCAL), create_privacy(3, OTHER_TYPE, LOCAL));
}
-TEST_F(EncodedBufferTest, StripVarintInNestedMessage) {
+TEST_F(PrivacyBufferTest, StripVarintInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5);
Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
assertStripByFields(EXPLICIT, expected, 1, create_message_privacy(5, list));
}
-TEST_F(EncodedBufferTest, StripFix64AndVarintInNestedMessage) {
+TEST_F(PrivacyBufferTest, StripFix64AndVarintInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + FIX64_FIELD_3 + MESSAGE_FIELD_5);
Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
assertStripByFields(EXPLICIT, expected, 2, create_privacy(3, OTHER_TYPE, LOCAL), create_message_privacy(5, list));
}
-TEST_F(EncodedBufferTest, ClearAndStrip) {
+TEST_F(PrivacyBufferTest, ClearAndStrip) {
string data = STRING_FIELD_0 + VARINT_FIELD_1;
writeToFdBuffer(data);
Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
- EncodedBuffer encodedBuf(buffer, create_message_privacy(300, list));
+ EncodedBuffer::iterator bufData = buffer.data();
+ PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData);
PrivacySpec spec1(EXPLICIT), spec2(LOCAL);
- ASSERT_EQ(encodedBuf.strip(spec1), NO_ERROR);
- assertBuffer(encodedBuf, STRING_FIELD_0);
- ASSERT_EQ(encodedBuf.strip(spec2), NO_ERROR);
- assertBuffer(encodedBuf, data);
+ ASSERT_EQ(privacyBuf.strip(spec1), NO_ERROR);
+ assertBuffer(privacyBuf, STRING_FIELD_0);
+ ASSERT_EQ(privacyBuf.strip(spec2), NO_ERROR);
+ assertBuffer(privacyBuf, data);
}
-TEST_F(EncodedBufferTest, BadDataInFdBuffer) {
+TEST_F(PrivacyBufferTest, BadDataInFdBuffer) {
writeToFdBuffer("iambaddata");
Privacy* list[] = { create_privacy(4, OTHER_TYPE, AUTOMATIC), NULL };
- EncodedBuffer encodedBuf(buffer, create_message_privacy(300, list));
+ EncodedBuffer::iterator bufData = buffer.data();
+ PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData);
PrivacySpec spec;
- ASSERT_EQ(encodedBuf.strip(spec), BAD_VALUE);
+ ASSERT_EQ(privacyBuf.strip(spec), BAD_VALUE);
}
-TEST_F(EncodedBufferTest, BadDataInNestedMessage) {
+TEST_F(PrivacyBufferTest, BadDataInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5 + "aoeoe");
Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
Privacy* field5[] = { create_message_privacy(5, list), NULL };
- EncodedBuffer encodedBuf(buffer, create_message_privacy(300, field5));
+ EncodedBuffer::iterator bufData = buffer.data();
+ PrivacyBuffer privacyBuf(create_message_privacy(300, field5), bufData);
PrivacySpec spec;
- ASSERT_EQ(encodedBuf.strip(spec), BAD_VALUE);
+ ASSERT_EQ(privacyBuf.strip(spec), BAD_VALUE);
}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 79faa1b..c5c38f5 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -416,7 +416,7 @@
PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
null, null);
params.sessionParams.setSize(
- PackageHelper.calculateInstalledSize(pkgLite, false,
+ PackageHelper.calculateInstalledSize(pkgLite,
params.sessionParams.abiOverride));
} catch (PackageParserException | IOException e) {
System.err.println("Error: Failed to parse APK file: " + e);
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 2db8eee..56f9512 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -53,8 +53,11 @@
src/StatsLogProcessor.cpp \
src/stats_log.proto \
src/statsd_config.proto \
- src/stats_constants.proto \
src/DropboxReader.cpp \
+ src/matchers/LogEntryMatcherManager.cpp \
+ src/metrics/CountMetricProducer.cpp \
+ src/metrics/ConditionTracker.cpp \
+ src/metrics/MetricsManager.cpp \
LOCAL_CFLAGS += \
@@ -108,6 +111,9 @@
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_MODULE_TAGS := tests
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/src \
+ STATSD_PROTO_INCLUDES
+
LOCAL_CFLAGS += \
-Wall \
-Werror \
@@ -116,21 +122,23 @@
-Wno-unused-function \
-Wno-unused-parameter
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src \
- STATSD_PROTO_INCLUDES
-
LOCAL_SRC_FILES := \
+ src/stats_log.proto \
+ src/statsd_config.proto \
../../core/java/android/os/IStatsCompanionService.aidl \
../../core/java/android/os/IStatsManager.aidl \
src/StatsService.cpp \
tests/indexed_priority_queue_test.cpp \
+ src/parse_util.cpp \
src/LogEntryPrinter.cpp \
src/LogReader.cpp \
+ src/matchers/LogEntryMatcherManager.cpp \
tests/LogReader_test.cpp \
+ tests/LogEntryMatcher_test.cpp \
LOCAL_STATIC_LIBRARIES := \
libgmock \
- statsd_proto
+ statsd_proto \
LOCAL_SHARED_LIBRARIES := \
libbase \
diff --git a/cmds/statsd/src/DropboxReader.cpp b/cmds/statsd/src/DropboxReader.cpp
index 27a01c8c..430e7af 100644
--- a/cmds/statsd/src/DropboxReader.cpp
+++ b/cmds/statsd/src/DropboxReader.cpp
@@ -105,16 +105,12 @@
}
void DropboxReader::printLog(FILE* out, const StatsLogReport& logReport) {
- fprintf(out, "start_time_msec=%lld, end_time_msec=%lld, ", logReport.start_report_millis(),
- logReport.end_report_millis());
+ fprintf(out, "start_time_ns=%lld, end_time_ns=%lld, ", logReport.start_report_nanos(),
+ logReport.end_report_nanos());
for (int i = 0; i < logReport.event_metrics().data_size(); i++) {
EventMetricData eventMetricData = logReport.event_metrics().data(i);
- for (int j = 0; j < eventMetricData.key_value_pair_size(); j++) {
- fprintf(out, "key=%d, ", eventMetricData.key_value_pair(j).key());
- fprintf(out, "value_str=%s ", eventMetricData.key_value_pair(j).value_str().c_str());
- fprintf(out, "value_int=%lld ", eventMetricData.key_value_pair(j).value_int());
- fprintf(out, "value_float=%f ", eventMetricData.key_value_pair(j).value_float());
- }
+ // TODO: Pretty-print the proto.
+ // fprintf(out, "EventMetricData=%s", eventMetricData.SerializeAsString().c_str());
}
fprintf(out, "\n");
}
diff --git a/cmds/statsd/src/DropboxWriter.h b/cmds/statsd/src/DropboxWriter.h
index 6107685..d72f103 100644
--- a/cmds/statsd/src/DropboxWriter.h
+++ b/cmds/statsd/src/DropboxWriter.h
@@ -17,7 +17,8 @@
#ifndef DROPBOX_WRITER_H
#define DROPBOX_WRITER_H
-#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
+#include <utils/RefBase.h>
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
using std::string;
@@ -25,7 +26,7 @@
namespace os {
namespace statsd {
-class DropboxWriter {
+class DropboxWriter : public virtual RefBase {
public:
/* tag will be part of the file name, and used as the key to build the file index inside
DropBoxManagerService.
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 280f9af..117fb5e 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -16,52 +16,74 @@
#include <StatsLogProcessor.h>
+#include <cutils/log.h>
+#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
#include <log/log_event_list.h>
+#include <metrics/CountMetricProducer.h>
#include <parse_util.h>
#include <utils/Errors.h>
using namespace android;
+using std::make_unique;
+using std::unique_ptr;
+using std::vector;
namespace android {
namespace os {
namespace statsd {
StatsLogProcessor::StatsLogProcessor() : m_dropbox_writer("all-logs") {
- // Initialize the EventTagMap, which is how we know the names of the numeric event tags.
- // If this fails, we can't print well, but something will print.
- m_tags = android_openEventTagMap(NULL);
-
- // Printing format
- m_format = android_log_format_new();
- android_log_setPrintFormat(m_format, FORMAT_THREADTIME);
+ // hardcoded config
+ // this should be called from StatsService when it receives a statsd_config
+ UpdateConfig(0, buildFakeConfig());
}
StatsLogProcessor::~StatsLogProcessor() {
- if (m_tags != NULL) {
- android_closeEventTagMap(m_tags);
- }
- android_log_format_free(m_format);
}
+StatsdConfig StatsLogProcessor::buildFakeConfig() {
+ // HACK: Hard code a test metric for counting screen on events...
+ StatsdConfig config;
+ config.set_config_id(12345L);
+
+ CountMetric* metric = config.add_count_metric();
+ metric->set_metric_id(20150717L);
+ metric->set_what("SCREEN_IS_ON");
+ metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+
+ LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_IS_ON");
+
+ SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()
+ ->set_key(1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleLogEntryMatcher->mutable_key_value_matcher(0)
+ ->set_eq_int(2/*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+ return config;
+}
+
+// TODO: what if statsd service restarts? How do we know what logs are already processed before?
void StatsLogProcessor::OnLogEvent(const log_msg& msg) {
- status_t err;
- AndroidLogEntry entry;
- char buf[1024];
+ // TODO: Use EventMetric to filter the events we want to log.
+ EventMetricData eventMetricData = parse(msg);
+ m_dropbox_writer.addEventMetricData(eventMetricData);
- err = android_log_processBinaryLogBuffer(&(const_cast<log_msg*>(&msg)->entry_v1), &entry,
- m_tags, buf, sizeof(buf));
-
- // dump all statsd logs to dropbox for now.
- // TODO: Add filtering, aggregation, etc.
- if (err == NO_ERROR) {
- EventMetricData eventMetricData = parse(msg);
- m_dropbox_writer.addEventMetricData(eventMetricData);
+ // pass the event to metrics managers.
+ for (auto& pair : mMetricsManagers) {
+ pair.second->onLogEvent(msg);
}
}
-void StatsLogProcessor::UpdateConfig(const int config_source, StatsdConfig config) {
- m_configs[config_source] = config;
+void StatsLogProcessor::UpdateConfig(const int config_source, const StatsdConfig& config) {
+ auto it = mMetricsManagers.find(config_source);
+ if (it != mMetricsManagers.end()) {
+ it->second->finish();
+ }
+
ALOGD("Updated configuration for source %i", config_source);
+
+ mMetricsManagers.insert({config_source, std::make_unique<MetricsManager>(config)});
}
} // namespace statsd
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 1e525c07..88c63fa 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -16,8 +16,14 @@
#ifndef STATS_LOG_PROCESSOR_H
#define STATS_LOG_PROCESSOR_H
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "DropboxWriter.h"
+#include "LogReader.h"
+#include "metrics/MetricsManager.h"
#include "parse_util.h"
+#include <log/logprint.h>
+#include <stdio.h>
#include <unordered_map>
namespace android {
@@ -31,26 +37,15 @@
virtual void OnLogEvent(const log_msg& msg);
- virtual void UpdateConfig(const int config_source, StatsdConfig config);
+ void UpdateConfig(const int config_source, const StatsdConfig& config);
private:
- /**
- * Numeric to string tag name mapping.
- */
- EventTagMap* m_tags;
-
- /**
- * Pretty printing format.
- */
- AndroidLogFormat* m_format;
-
+ // TODO: use EventMetrics to log the events.
DropboxWriter m_dropbox_writer;
- /**
- * Configs that have been specified, keyed by the source. This allows us to over-ride the config
- * from a source later.
- */
- std::unordered_map<int, StatsdConfig> m_configs;
+ std::unordered_map<int, std::unique_ptr<MetricsManager>> mMetricsManagers;
+
+ static StatsdConfig buildFakeConfig();
};
} // namespace statsd
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index b02579d..a16b115 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -25,7 +25,6 @@
#include <android/os/IStatsCompanionService.h>
#include <binder/IResultReceiver.h>
#include <binder/IShellCallback.h>
-#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
#include <utils/Looper.h>
#include <deque>
diff --git a/cmds/statsd/src/matchers/LogEntryMatcherManager.cpp b/cmds/statsd/src/matchers/LogEntryMatcherManager.cpp
new file mode 100644
index 0000000..ab7b2b1d
--- /dev/null
+++ b/cmds/statsd/src/matchers/LogEntryMatcherManager.cpp
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LogEntryMatcherManager.h"
+#include <cutils/log.h>
+#include <log/event_tag_map.h>
+#include <log/log_event_list.h>
+#include <log/logprint.h>
+#include <utils/Errors.h>
+#include <unordered_map>
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "parse_util.h"
+
+using std::set;
+using std::string;
+using std::unordered_map;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+LogEventWrapper LogEntryMatcherManager::parseLogEvent(log_msg msg) {
+ LogEventWrapper wrapper;
+ wrapper.timestamp_ns = msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec;
+ wrapper.tagId = getTagId(msg);
+
+ // start iterating k,v pairs.
+ android_log_context context =
+ create_android_log_parser(const_cast<log_msg*>(&msg)->msg() + sizeof(uint32_t),
+ const_cast<log_msg*>(&msg)->len() - sizeof(uint32_t));
+ android_log_list_element elem;
+
+ if (context) {
+ memset(&elem, 0, sizeof(elem));
+ size_t index = 0;
+ int32_t key = -1;
+ do {
+ elem = android_log_read_next(context);
+ switch ((int)elem.type) {
+ case EVENT_TYPE_INT:
+ if (index % 2 == 0) {
+ key = elem.data.int32;
+ } else {
+ wrapper.intMap[key] = elem.data.int32;
+ }
+ index++;
+ break;
+ case EVENT_TYPE_FLOAT:
+ if (index % 2 == 1) {
+ wrapper.floatMap[key] = elem.data.float32;
+ }
+ index++;
+ break;
+ case EVENT_TYPE_STRING:
+ if (index % 2 == 1) {
+ wrapper.strMap[key] = elem.data.string;
+ }
+ index++;
+ break;
+ case EVENT_TYPE_LONG:
+ if (index % 2 == 1) {
+ wrapper.intMap[key] = elem.data.int64;
+ }
+ index++;
+ break;
+ case EVENT_TYPE_LIST:
+ break;
+ case EVENT_TYPE_LIST_STOP:
+ break;
+ case EVENT_TYPE_UNKNOWN:
+ break;
+ default:
+ elem.complete = true;
+ break;
+ }
+
+ if (elem.complete) {
+ break;
+ }
+ } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
+
+ android_log_destroy(&context);
+ }
+
+ return wrapper;
+}
+
+bool LogEntryMatcherManager::matches(const LogEntryMatcher& matcher, const LogEventWrapper& event) {
+ const int tagId = event.tagId;
+ const unordered_map<int, long>& intMap = event.intMap;
+ const unordered_map<int, string>& strMap = event.strMap;
+ const unordered_map<int, float>& floatMap = event.floatMap;
+ const unordered_map<int, bool>& boolMap = event.boolMap;
+
+ if (matcher.has_combination()) { // Need to evaluate composite matching
+ switch (matcher.combination().operation()) {
+ case LogicalOperation::AND:
+ for (auto nestedMatcher : matcher.combination().matcher()) {
+ if (!matches(nestedMatcher, event)) {
+ return false; // return false if any nested matcher is false;
+ }
+ }
+ return true; // Otherwise, return true.
+ case LogicalOperation::OR:
+ for (auto nestedMatcher : matcher.combination().matcher()) {
+ if (matches(nestedMatcher, event)) {
+ return true; // return true if any nested matcher is true;
+ }
+ }
+ return false;
+ case LogicalOperation::NOT:
+ return !matches(matcher.combination().matcher(0), event);
+
+ // Case NAND is just inverting the return statement of AND
+ case LogicalOperation::NAND:
+ for (auto nestedMatcher : matcher.combination().matcher()) {
+ auto simple = nestedMatcher.simple_log_entry_matcher();
+ if (!matches(nestedMatcher, event)) {
+ return true; // return false if any nested matcher is false;
+ }
+ }
+ return false; // Otherwise, return true.
+ case LogicalOperation::NOR:
+ for (auto nestedMatcher : matcher.combination().matcher()) {
+ if (matches(nestedMatcher, event)) {
+ return false; // return true if any nested matcher is true;
+ }
+ }
+ return true;
+ }
+ return false;
+ } else {
+ return matchesSimple(matcher.simple_log_entry_matcher(), event);
+ }
+}
+
+bool LogEntryMatcherManager::matchesSimple(const SimpleLogEntryMatcher& simpleMatcher,
+ const LogEventWrapper& event) {
+ const int tagId = event.tagId;
+ const unordered_map<int, long>& intMap = event.intMap;
+ const unordered_map<int, string>& strMap = event.strMap;
+ const unordered_map<int, float>& floatMap = event.floatMap;
+ const unordered_map<int, bool>& boolMap = event.boolMap;
+
+ for (int i = 0; i < simpleMatcher.tag_size(); i++) {
+ if (simpleMatcher.tag(i) != tagId) {
+ continue;
+ }
+
+ // now see if this event is interesting to us -- matches ALL the matchers
+ // defined in the metrics.
+ bool allMatched = true;
+ for (int j = 0; j < simpleMatcher.key_value_matcher_size(); j++) {
+ auto cur = simpleMatcher.key_value_matcher(j);
+
+ // TODO: Check if this key is a magic key (eg package name).
+ int key = cur.key_matcher().key();
+
+ switch (cur.value_matcher_case()) {
+ case KeyValueMatcher::ValueMatcherCase::kEqString: {
+ auto it = strMap.find(key);
+ if (it == strMap.end() || cur.eq_string().compare(it->second) != 0) {
+ allMatched = false;
+ }
+ break;
+ }
+ case KeyValueMatcher::ValueMatcherCase::kEqInt: {
+ auto it = intMap.find(key);
+ if (it == intMap.end() || cur.eq_int() != it->second) {
+ allMatched = false;
+ }
+ break;
+ }
+ case KeyValueMatcher::ValueMatcherCase::kEqBool: {
+ auto it = boolMap.find(key);
+ if (it == boolMap.end() || cur.eq_bool() != it->second) {
+ allMatched = false;
+ }
+ break;
+ }
+ // Begin numeric comparisons
+ case KeyValueMatcher::ValueMatcherCase::kLtInt: {
+ auto it = intMap.find(key);
+ if (it == intMap.end() || cur.lt_int() <= it->second) {
+ allMatched = false;
+ }
+ break;
+ }
+ case KeyValueMatcher::ValueMatcherCase::kGtInt: {
+ auto it = intMap.find(key);
+ if (it == intMap.end() || cur.gt_int() >= it->second) {
+ allMatched = false;
+ }
+ break;
+ }
+ case KeyValueMatcher::ValueMatcherCase::kLtFloat: {
+ auto it = floatMap.find(key);
+ if (it == floatMap.end() || cur.lt_float() <= it->second) {
+ allMatched = false;
+ }
+ break;
+ }
+ case KeyValueMatcher::ValueMatcherCase::kGtFloat: {
+ auto it = floatMap.find(key);
+ if (it == floatMap.end() || cur.gt_float() >= it->second) {
+ allMatched = false;
+ }
+ break;
+ }
+ // Begin comparisons with equality
+ case KeyValueMatcher::ValueMatcherCase::kLteInt: {
+ auto it = intMap.find(key);
+ if (it == intMap.end() || cur.lte_int() < it->second) {
+ allMatched = false;
+ }
+ break;
+ }
+ case KeyValueMatcher::ValueMatcherCase::kGteInt: {
+ auto it = intMap.find(key);
+ if (it == intMap.end() || cur.gte_int() > it->second) {
+ allMatched = false;
+ }
+ break;
+ }
+ case KeyValueMatcher::ValueMatcherCase::VALUE_MATCHER_NOT_SET:
+ // If value matcher is not present, assume that we match.
+ break;
+ }
+ }
+
+ if (allMatched) {
+ return true;
+ }
+ }
+ return false;
+}
+
+set<int> LogEntryMatcherManager::getTagIdsFromMatcher(const LogEntryMatcher& matcher) {
+ set<int> result;
+ switch (matcher.contents_case()) {
+ case LogEntryMatcher::kCombination:
+ for (auto sub_matcher : matcher.combination().matcher()) {
+ set<int> tagSet = getTagIdsFromMatcher(sub_matcher);
+ result.insert(tagSet.begin(), tagSet.end());
+ }
+ break;
+ case LogEntryMatcher::kSimpleLogEntryMatcher:
+ for (int i = 0; i < matcher.simple_log_entry_matcher().tag_size(); i++) {
+ result.insert(matcher.simple_log_entry_matcher().tag(i));
+ }
+ break;
+ case LogEntryMatcher::CONTENTS_NOT_SET:
+ break;
+ }
+ return result;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/matchers/LogEntryMatcherManager.h b/cmds/statsd/src/matchers/LogEntryMatcherManager.h
new file mode 100644
index 0000000..fc8e6a1
--- /dev/null
+++ b/cmds/statsd/src/matchers/LogEntryMatcherManager.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOG_ENTRY_MATCHER_MANAGER_H
+#define LOG_ENTRY_MATCHER_MANAGER_H
+
+#include <log/log_read.h>
+#include <log/logprint.h>
+#include <set>
+#include <unordered_map>
+#include <vector>
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+using std::string;
+using std::unordered_map;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+typedef struct {
+ int tagId;
+ long timestamp_ns;
+ std::unordered_map<int, long> intMap;
+ std::unordered_map<int, std::string> strMap;
+ std::unordered_map<int, bool> boolMap;
+ std::unordered_map<int, float> floatMap;
+} LogEventWrapper;
+
+/**
+ * Keeps track per log entry which simple log entry matchers match.
+ */
+class LogEntryMatcherManager {
+public:
+ LogEntryMatcherManager();
+
+ ~LogEntryMatcherManager(){};
+
+ static LogEventWrapper parseLogEvent(log_msg msg);
+
+ static std::set<int> getTagIdsFromMatcher(const LogEntryMatcher& matcher);
+
+ static bool matches(const LogEntryMatcher& matcher, const LogEventWrapper& wrapper);
+
+ static bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher,
+ const LogEventWrapper& wrapper);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#endif // LOG_ENTRY_MATCHER_MANAGER_H
diff --git a/cmds/statsd/src/metrics/ConditionTracker.cpp b/cmds/statsd/src/metrics/ConditionTracker.cpp
new file mode 100644
index 0000000..684ffdb
--- /dev/null
+++ b/cmds/statsd/src/metrics/ConditionTracker.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ConditionTracker"
+#define DEBUG true // STOPSHIP if true
+#define VLOG(...) \
+ if (DEBUG) ALOGD(__VA_ARGS__);
+
+#include "ConditionTracker.h"
+#include <cutils/log.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+ConditionTracker::ConditionTracker() : mIsConditionMet(true) {
+ VLOG("ConditionTracker()");
+}
+
+ConditionTracker::ConditionTracker(const Condition& condition)
+ : mCondition(condition), mIsConditionMet(true) {
+ VLOG("ConditionTracker()");
+}
+
+ConditionTracker::~ConditionTracker() {
+ VLOG("~ConditionTracker()");
+}
+
+void ConditionTracker::evaluateCondition(const LogEventWrapper& event) {
+ // modify condition.
+ VLOG("evaluateCondition");
+}
+
+bool ConditionTracker::isConditionMet() const {
+ VLOG("isConditionMet() %d", mIsConditionMet);
+ return mIsConditionMet;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/metrics/ConditionTracker.h b/cmds/statsd/src/metrics/ConditionTracker.h
new file mode 100644
index 0000000..b94d5ab
--- /dev/null
+++ b/cmds/statsd/src/metrics/ConditionTracker.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONDITION_TRACKER_H
+#define CONDITION_TRACKER_H
+
+#include <utils/RefBase.h>
+#include "../matchers/LogEntryMatcherManager.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class ConditionTracker : public RefBase {
+public:
+ ConditionTracker();
+
+ ConditionTracker(const Condition& condition);
+
+ ~ConditionTracker();
+
+ void evaluateCondition(const LogEventWrapper& event);
+
+ bool isConditionMet() const;
+
+private:
+ // this is the definition of the Condition.
+ Condition mCondition;
+
+ bool mIsConditionMet;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif // CONDITION_TRACKER_H
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
new file mode 100644
index 0000000..fbd013e
--- /dev/null
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CountMetric"
+#define DEBUG true // STOPSHIP if true
+#define VLOG(...) \
+ if (DEBUG) ALOGD(__VA_ARGS__);
+
+#include "CountMetricProducer.h"
+#include "parse_util.h"
+
+#include <cutils/log.h>
+#include <limits.h>
+#include <stdlib.h>
+
+using std::unordered_map;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+CountMetricProducer::CountMetricProducer(const CountMetric& metric,
+ const sp<ConditionTracker> condition)
+ : mMetric(metric),
+ mConditionTracker(condition),
+ mStartTime(std::time(nullptr)),
+ mCounter(0),
+ mCurrentBucketStartTime(mStartTime) {
+ // TODO: evaluate initial conditions. and set mConditionMet.
+ if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
+ mBucketSize_sec = metric.bucket().bucket_size_millis() / 1000;
+ } else {
+ mBucketSize_sec = LONG_MAX;
+ }
+
+ VLOG("created. bucket size %lu start_time: %lu", mBucketSize_sec, mStartTime);
+}
+
+CountMetricProducer::CountMetricProducer(const CountMetric& metric)
+ : CountMetricProducer(metric, new ConditionTracker()) {
+}
+
+CountMetricProducer::~CountMetricProducer() {
+ VLOG("~CountMetricProducer() called");
+}
+
+void CountMetricProducer::finish() {
+ // TODO: write the StatsLogReport to dropbox using
+ // DropboxWriter.
+ onDumpReport();
+}
+
+void CountMetricProducer::onDumpReport() {
+ VLOG("dump report now...");
+}
+
+void CountMetricProducer::onMatchedLogEvent(const LogEventWrapper& event) {
+ time_t eventTime = event.timestamp_ns / 1000000000;
+
+ // this is old event, maybe statsd restarted?
+ if (eventTime < mStartTime) {
+ return;
+ }
+
+ if (mConditionTracker->isConditionMet()) {
+ flushCounterIfNeeded(eventTime);
+ mCounter++;
+ }
+}
+
+// When a new matched event comes in, we check if it falls into the current bucket. And flush the
+// counter to the StatsLogReport and adjust the bucket if needed.
+void CountMetricProducer::flushCounterIfNeeded(const time_t& eventTime) {
+ if (mCurrentBucketStartTime + mBucketSize_sec > eventTime) {
+ return;
+ }
+
+ // TODO: add a KeyValuePair to StatsLogReport.
+ ALOGD("CountMetric: dump counter %d", mCounter);
+
+ // reset counter
+ mCounter = 0;
+
+ // adjust the bucket start time
+ mCurrentBucketStartTime =
+ mCurrentBucketStartTime +
+ ((eventTime - mCurrentBucketStartTime) / mBucketSize_sec) * mBucketSize_sec;
+
+ VLOG("new bucket start time: %lu", mCurrentBucketStartTime);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
new file mode 100644
index 0000000..7665791
--- /dev/null
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COUNT_METRIC_PRODUCER_H
+#define COUNT_METRIC_PRODUCER_H
+
+#include <mutex>
+#include <thread>
+#include <unordered_map>
+#include "../matchers/LogEntryMatcherManager.h"
+#include "ConditionTracker.h"
+#include "DropboxWriter.h"
+#include "MetricProducer.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class CountMetricProducer : public MetricProducer {
+public:
+ CountMetricProducer(const CountMetric& countMetric, const sp<ConditionTracker> condition);
+
+ CountMetricProducer(const CountMetric& countMetric);
+
+ virtual ~CountMetricProducer();
+
+ void onMatchedLogEvent(const LogEventWrapper& event) override;
+
+ void finish() override;
+
+ void onDumpReport() override;
+
+private:
+ const CountMetric mMetric;
+
+ const sp<ConditionTracker> mConditionTracker;
+
+ const time_t mStartTime;
+ // TODO: Add dimensions.
+ int mCounter;
+
+ time_t mCurrentBucketStartTime;
+
+ long mBucketSize_sec;
+
+ void flushCounterIfNeeded(const time_t& newEventTime);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#endif // COUNT_METRIC_PRODUCER_H
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
new file mode 100644
index 0000000..44a778b
--- /dev/null
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef METRIC_PRODUCER_H
+#define METRIC_PRODUCER_H
+
+#include <log/logprint.h>
+#include "../matchers/LogEntryMatcherManager.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// A MetricProducer is responsible for compute one single metrics, creating stats log report, and
+// writing the report to dropbox.
+class MetricProducer {
+public:
+ virtual ~MetricProducer(){};
+
+ // Consume the stats log if it's interesting to this metric.
+ virtual void onMatchedLogEvent(const LogEventWrapper& event) = 0;
+
+ // This is called when the metric collecting is done, e.g., when there is a new configuration
+ // coming. MetricProducer should do the clean up, and dump existing data to dropbox.
+ virtual void finish() = 0;
+
+ virtual void onDumpReport() = 0;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#endif // METRIC_PRODUCER_H
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
new file mode 100644
index 0000000..cb74206
--- /dev/null
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "MetricManager"
+#define DEBUG true // STOPSHIP if true
+#define VLOG(...) \
+ if (DEBUG) ALOGD(__VA_ARGS__);
+
+#include "MetricsManager.h"
+#include <cutils/log.h>
+#include <log/logprint.h>
+#include "CountMetricProducer.h"
+#include "parse_util.h"
+
+using std::make_unique;
+using std::set;
+using std::string;
+using std::unique_ptr;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+MetricsManager::MetricsManager(const StatsdConfig& config) : mConfig(config), mLogMatchers() {
+ std::unordered_map<string, LogEntryMatcher> matcherMap;
+ std::unordered_map<string, sp<ConditionTracker>> conditionMap;
+
+ for (int i = 0; i < config.log_entry_matcher_size(); i++) {
+ const LogEntryMatcher& logMatcher = config.log_entry_matcher(i);
+ mMatchers.push_back(logMatcher);
+
+ matcherMap[config.log_entry_matcher(i).name()] = logMatcher;
+
+ mLogMatchers[logMatcher.name()] = vector<unique_ptr<MetricProducer>>();
+ // Collect all the tag ids that are interesting
+ set<int> tagIds = LogEntryMatcherManager::getTagIdsFromMatcher(logMatcher);
+
+ mTagIds.insert(tagIds.begin(), tagIds.end());
+ }
+
+ for (int i = 0; i < config.condition_size(); i++) {
+ const Condition& condition = config.condition(i);
+ conditionMap[condition.name()] = new ConditionTracker(condition);
+ }
+
+ // Build MetricProducers for each metric defined in config.
+ // (1) build CountMetricProducer
+ for (int i = 0; i < config.count_metric_size(); i++) {
+ const CountMetric& metric = config.count_metric(i);
+ auto it = mLogMatchers.find(metric.what());
+ if (it == mLogMatchers.end()) {
+ ALOGW("cannot find the LogEntryMatcher %s in config", metric.what().c_str());
+ continue;
+ }
+
+ if (metric.has_condition()) {
+ auto condition_it = conditionMap.find(metric.condition());
+ if (condition_it == conditionMap.end()) {
+ ALOGW("cannot find the Condition %s in the config", metric.condition().c_str());
+ continue;
+ }
+ it->second.push_back(make_unique<CountMetricProducer>(metric, condition_it->second));
+ } else {
+ it->second.push_back(make_unique<CountMetricProducer>(metric));
+ }
+ }
+
+ // TODO: build other types of metrics too.
+}
+
+MetricsManager::~MetricsManager() {
+ VLOG("~MetricManager()");
+}
+
+void MetricsManager::finish() {
+ for (auto const& entryPair : mLogMatchers) {
+ for (auto const& metric : entryPair.second) {
+ metric->finish();
+ }
+ }
+}
+
+// Consume the stats log if it's interesting to this metric.
+void MetricsManager::onLogEvent(const log_msg& logMsg) {
+ int tagId = getTagId(logMsg);
+ if (mTagIds.find(tagId) == mTagIds.end()) {
+ // not interesting...
+ return;
+ }
+ // Since at least one of the metrics is interested in this event, we parse it now.
+ LogEventWrapper event = LogEntryMatcherManager::parseLogEvent(logMsg);
+
+ // Evaluate the conditions. Order matters, this should happen
+ // before sending the event to metrics
+ for (auto& condition : mConditionTracker) {
+ condition->evaluateCondition(event);
+ }
+
+ // Now find out which LogMatcher matches this event, and let relevant metrics know.
+ for (auto matcher : mMatchers) {
+ if (LogEntryMatcherManager::matches(matcher, event)) {
+ auto it = mLogMatchers.find(matcher.name());
+ if (it != mLogMatchers.end()) {
+ for (auto const& it2 : it->second) {
+ // Only metrics that matches this event get notified.
+ it2->onMatchedLogEvent(event);
+ }
+ } else {
+ // TODO: we should remove any redundant matchers that the config provides.
+ ALOGW("Matcher not used by any metrics.");
+ }
+ }
+ }
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
new file mode 100644
index 0000000..77d7535
--- /dev/null
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef METRICS_MANAGER_H
+#define METRICS_MANAGER_H
+
+#include <cutils/log.h>
+#include <log/logprint.h>
+#include <unordered_map>
+#include "../matchers/LogEntryMatcherManager.h"
+#include "ConditionTracker.h"
+#include "MetricProducer.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// A MetricsManager is responsible for managing metrics from one single config source.
+class MetricsManager {
+public:
+ MetricsManager(const StatsdConfig& config);
+
+ ~MetricsManager();
+
+ // Consume the stats log if it's interesting to this metric.
+ void onLogEvent(const log_msg& logMsg);
+
+ void finish();
+
+private:
+ const StatsdConfig mConfig;
+
+ // All event tags that are interesting to my metrics.
+ std::set<int> mTagIds;
+
+ // The matchers that my metrics share.
+ std::vector<LogEntryMatcher> mMatchers;
+
+ // The conditions that my metrics share.
+ std::vector<sp<ConditionTracker>> mConditionTracker;
+
+ // the map from LogEntryMatcher names to the metrics that use this matcher.
+ std::unordered_map<std::string, std::vector<std::unique_ptr<MetricProducer>>> mLogMatchers;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif // METRICS_MANAGER_H
diff --git a/cmds/statsd/src/parse_util.cpp b/cmds/statsd/src/parse_util.cpp
index b68f135..61421880 100644
--- a/cmds/statsd/src/parse_util.cpp
+++ b/cmds/statsd/src/parse_util.cpp
@@ -17,23 +17,30 @@
#include <log/log_event_list.h>
#include <parse_util.h>
-using android::os::statsd::EVENT_TIMESTAMP;
-using android::os::statsd::EventMetricData;
-using android::os::statsd::KeyId;
-using android::os::statsd::KeyId_IsValid;
-using android::os::statsd::KeyValuePair;
-using android::os::statsd::TagId;
-using android::os::statsd::TagId_IsValid;
+namespace android {
+namespace os {
+namespace statsd {
+
+static inline uint32_t get4LE(const char* src) {
+ return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+int getTagId(log_msg msg) {
+ return get4LE(msg.msg());
+}
EventMetricData parse(log_msg msg) {
// dump all statsd logs to dropbox for now.
// TODO: Add filtering, aggregation, etc.
EventMetricData eventMetricData;
+ // set tag.
+ int tag = getTagId(msg);
+ // TODO: Replace the following line when we can serialize on the fly.
+ //eventMetricData.set_tag(tag);
+
// set timestamp of the event.
- KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
- keyValuePair->set_key(EVENT_TIMESTAMP);
- keyValuePair->set_value_int(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec);
+ eventMetricData.set_timestamp_nanos(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec);
// start iterating k,v pairs.
android_log_context context =
@@ -45,54 +52,57 @@
memset(&elem, 0, sizeof(elem));
size_t index = 0;
int32_t key = -1;
- int32_t tag = -1;
do {
elem = android_log_read_next(context);
switch ((int)elem.type) {
case EVENT_TYPE_INT:
- if (index == 0) {
- tag = elem.data.int32;
- if (TagId_IsValid(tag)) {
- eventMetricData.set_tag(static_cast<TagId>(tag));
- } else {
- break;
- }
- } else if (index % 2 == 1) {
+ if (index % 2 == 0) {
key = elem.data.int32;
- } else if (KeyId_IsValid(key)) {
+ } else {
+ // TODO: Fix the following lines when we can serialize on the fly.
+ /*
int32_t val = elem.data.int32;
KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
- keyValuePair->set_key(static_cast<KeyId>(key));
+ keyValuePair->set_key(key);
keyValuePair->set_value_int(val);
- } else {
+ */
}
index++;
break;
case EVENT_TYPE_FLOAT:
- if (index % 2 == 0 && KeyId_IsValid(key)) {
+ if (index % 2 == 1) {
+ // TODO: Fix the following lines when we can serialize on the fly.
+ /*
float val = elem.data.float32;
KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
- keyValuePair->set_key(static_cast<KeyId>(key));
+ keyValuePair->set_key(key);
keyValuePair->set_value_float(val);
+ */
}
index++;
break;
case EVENT_TYPE_STRING:
- if (index % 2 == 0 && KeyId_IsValid(key)) {
+ if (index % 2 == 1) {
+ // TODO: Fix the following lines when we can serialize on the fly.
+ /*
char* val = elem.data.string;
KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
- keyValuePair->set_key(static_cast<KeyId>(key));
+ keyValuePair->set_key(key);
keyValuePair->set_value_str(val);
+ */
}
index++;
break;
case EVENT_TYPE_LONG:
- if (index % 2 == 0 && KeyId_IsValid(key)) {
+ if (index % 2 == 1) {
+ // TODO: Fix the following lines when we can serialize on the fly.
+ /*
int64_t val = elem.data.int64;
KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
- keyValuePair->set_key(static_cast<KeyId>(key));
+ keyValuePair->set_key(key);
keyValuePair->set_value_int(val);
+ */
}
index++;
break;
@@ -117,3 +127,6 @@
return eventMetricData;
}
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/parse_util.h b/cmds/statsd/src/parse_util.h
index e9f4c27..8b82e7b 100644
--- a/cmds/statsd/src/parse_util.h
+++ b/cmds/statsd/src/parse_util.h
@@ -21,8 +21,16 @@
#include <log/logprint.h>
-using android::os::statsd::EventMetricData;
+namespace android {
+namespace os {
+namespace statsd {
-EventMetricData parse(const log_msg msg);
+EventMetricData parse(log_msg msg);
+
+int getTagId(log_msg msg);
+
+} // namespace statsd
+} // namespace os
+} // namespace android
#endif // PARSE_UTIL_H
diff --git a/cmds/statsd/src/stats_constants.proto b/cmds/statsd/src/stats_constants.proto
deleted file mode 100644
index 9758a2e..0000000
--- a/cmds/statsd/src/stats_constants.proto
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-syntax = "proto2";
-
-package android.os.statsd;
-
-option optimize_for = LITE_RUNTIME;
-
-option java_package = "com.android.internal.logging";
-option java_outer_classname = "StatsConstantsProto";
-
-enum TagId {
- WAKELOCK = 1;
- SCREEN = 2;
- PROCESS = 1112; // TODO: Temporary usage only for testing.
-}
-
-enum KeyId {
- STATE = 1;
- ANOTHER_STATE = 2;
- EVENT_TIMESTAMP = 1001;
- PACKAGE_NAME = 1002;
- PACKAGE_VERSION = 1003;
- PACKAGE_VERSION_STRING = 1004;
- ATTRIBUTION_CHAIN = 1005;
-}
diff --git a/cmds/statsd/src/stats_events.proto b/cmds/statsd/src/stats_events.proto
new file mode 100644
index 0000000..dffc68e
--- /dev/null
+++ b/cmds/statsd/src/stats_events.proto
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package android.os.statsd;
+
+option java_package = "com.android.os";
+option java_outer_classname = "StatsEventProto";
+
+message StatsEvent {
+ oneof log_entry_event {
+ ScreenStateChange screen_state_change = 2;
+ ProcessStateChange process_state_change = 1112;
+ }
+}
+
+message ScreenStateChange {
+ enum State {
+ STATE_UNKNOWN = 0;
+ STATE_OFF = 1;
+ STATE_ON = 2;
+ STATE_DOZE = 3;
+ STATE_DOZE_SUSPEND = 4;
+ STATE_VR = 5;
+ }
+ optional State display_state = 1;
+}
+
+message ProcessStateChange {
+ enum State {
+ START = 1;
+ CRASH = 2;
+ }
+ optional State state = 1;
+
+ optional int32 uid = 2;
+
+ optional string package_name = 1002;
+
+ optional int32 package_version = 3;
+ optional string package_version_string = 4;
+}
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 2c66ded..2dc0cc7 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -13,20 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
package android.os.statsd;
-option optimize_for = LITE_RUNTIME;
-
option java_package = "com.android.os";
option java_outer_classname = "StatsLog";
-import "frameworks/base/cmds/statsd/src/statsd_config.proto";
-import "frameworks/base/cmds/statsd/src/stats_constants.proto";
+import "frameworks/base/cmds/statsd/src/stats_events.proto";
message KeyValuePair {
- optional KeyId key = 1;
+ optional int32 key = 1;
oneof value {
string value_str = 2;
@@ -37,15 +36,15 @@
}
message EventMetricData {
- optional TagId tag = 1;
+ optional int64 timestamp_nanos = 1;
- repeated KeyValuePair key_value_pair = 2;
+ optional StatsEvent stats_events = 2;
}
message CountBucketInfo {
- optional int64 start_bucket_millis = 1;
+ optional int64 start_bucket_nanos = 1;
- optional int64 end_bucket_millis = 2;
+ optional int64 end_bucket_nanos = 2;
optional int64 count = 3;
}
@@ -59,9 +58,9 @@
message StatsLogReport {
optional int32 metric_id = 1;
- optional int64 start_report_millis = 2;
+ optional int64 start_report_nanos = 2;
- optional int64 end_report_millis = 3;
+ optional int64 end_report_nanos = 3;
message EventMetricDataWrapper {
repeated EventMetricData data = 1;
@@ -69,7 +68,6 @@
message CountMetricDataWrapper {
repeated CountMetricData data = 1;
}
-
oneof data {
EventMetricDataWrapper event_metrics = 4;
CountMetricDataWrapper count_metrics = 5;
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index c6119df..3e4ebaf 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -1,15 +1,30 @@
-syntax = "proto2";
-package android.os.statsd;
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+syntax = "proto2";
option optimize_for = LITE_RUNTIME;
+package android.os.statsd;
+
option java_package = "com.android.internal.os";
option java_outer_classname = "StatsdConfigProto";
-import "frameworks/base/cmds/statsd/src/stats_constants.proto";
-
message KeyMatcher {
- optional KeyId key = 1;
+ optional int32 key = 1;
+
optional bool as_package_name = 2 [ default = false ];
}
@@ -19,14 +34,15 @@
oneof value_matcher {
bool eq_bool = 2;
string eq_string = 3;
- int32 eq_int32 = 4;
- int64 eq_int64 = 5;
- int32 lt_int32 = 6;
- int32 gt_int32 = 7;
- int64 lt_int64 = 8;
- int64 gt_int64 = 9;
- float lt_float = 10;
- float gt_float = 11;
+ int32 eq_int = 4;
+
+ int64 lt_int = 5;
+ int64 gt_int = 6;
+ float lt_float = 7;
+ float gt_float = 8;
+
+ int64 lte_int = 9;
+ int64 gte_int = 10;
}
}
@@ -39,7 +55,7 @@
}
message SimpleLogEntryMatcher {
- repeated TagId tag = 1;
+ repeated int32 tag = 1;
repeated KeyValueMatcher key_value_matcher = 2;
}
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
new file mode 100644
index 0000000..473704a
--- /dev/null
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -0,0 +1,315 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#define LOG_TAG "statsd_test"
+
+#include <gtest/gtest.h>
+#include <log/log_event_list.h>
+#include <log/log_read.h>
+#include <log/logprint.h>
+#include "../src/matchers/LogEntryMatcherManager.h"
+#include "../src/parse_util.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+#include <stdio.h>
+
+using namespace android::os::statsd;
+using std::unordered_map;
+
+const int kTagIdWakelock = 123;
+const int kKeyIdState = 45;
+const int kKeyIdPackageVersion = 67;
+
+#ifdef __ANDROID__
+TEST(LogEntryMatcherTest, TestSimpleMatcher) {
+ // Set up the matcher
+ LogEntryMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+ simpleMatcher->add_tag(kTagIdWakelock);
+
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
+
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+}
+
+TEST(LogEntryMatcherTest, TestBoolMatcher) {
+ // Set up the matcher
+ LogEntryMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+ simpleMatcher->add_tag(kTagIdWakelock);
+ auto keyValue = simpleMatcher->add_key_value_matcher();
+ keyValue->mutable_key_matcher()->set_key(kKeyIdState);
+
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
+
+ keyValue->set_eq_bool(true);
+ wrapper.boolMap[kKeyIdState] = true;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+
+ keyValue->set_eq_bool(false);
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+
+ wrapper.boolMap[kTagIdWakelock] = false;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+}
+
+TEST(LogEntryMatcherTest, TestStringMatcher) {
+ // Set up the matcher
+ LogEntryMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+ simpleMatcher->add_tag(kTagIdWakelock);
+ auto keyValue = simpleMatcher->add_key_value_matcher();
+ keyValue->mutable_key_matcher()->set_key(kKeyIdState);
+ keyValue->set_eq_string("wakelock_name");
+
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
+
+ wrapper.strMap[kKeyIdState] = "wakelock_name";
+
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+}
+
+TEST(LogEntryMatcherTest, TestIntComparisonMatcher) {
+ // Set up the matcher
+ LogEntryMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+ simpleMatcher->add_tag(kTagIdWakelock);
+ auto keyValue = simpleMatcher->add_key_value_matcher();
+ keyValue->mutable_key_matcher()->set_key(kKeyIdState);
+
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
+
+ keyValue->set_lt_int(10);
+ wrapper.intMap[kKeyIdState] = 11;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 10;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 9;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+
+ keyValue->set_gt_int(10);
+ wrapper.intMap[kKeyIdState] = 11;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 10;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 9;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+}
+
+TEST(LogEntryMatcherTest, TestIntWithEqualityComparisonMatcher) {
+ // Set up the matcher
+ LogEntryMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+ simpleMatcher->add_tag(kTagIdWakelock);
+ auto keyValue = simpleMatcher->add_key_value_matcher();
+ keyValue->mutable_key_matcher()->set_key(kKeyIdState);
+
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
+
+ keyValue->set_lte_int(10);
+ wrapper.intMap[kKeyIdState] = 11;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 10;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 9;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+
+ keyValue->set_gte_int(10);
+ wrapper.intMap[kKeyIdState] = 11;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 10;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 9;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+}
+
+TEST(LogEntryMatcherTest, TestFloatComparisonMatcher) {
+ // Set up the matcher
+ LogEntryMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+ simpleMatcher->add_tag(kTagIdWakelock);
+ auto keyValue = simpleMatcher->add_key_value_matcher();
+ keyValue->mutable_key_matcher()->set_key(kKeyIdState);
+
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
+
+ keyValue->set_lt_float(10.0);
+ wrapper.floatMap[kKeyIdState] = 10.1;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.floatMap[kKeyIdState] = 9.9;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+
+ keyValue->set_gt_float(10.0);
+ wrapper.floatMap[kKeyIdState] = 10.1;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.floatMap[kKeyIdState] = 9.9;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+}
+
+// Helper for the composite matchers.
+void addSimpleMatcher(SimpleLogEntryMatcher* simpleMatcher, int tag, int key, int val) {
+ simpleMatcher->add_tag(tag);
+ auto keyValue = simpleMatcher->add_key_value_matcher();
+ keyValue->mutable_key_matcher()->set_key(key);
+ keyValue->set_eq_int(val);
+}
+
+TEST(LogEntryMatcherTest, TestAndMatcher) {
+ // Set up the matcher
+ LogEntryMatcher matcher;
+ auto combination = matcher.mutable_combination();
+ combination->set_operation(LogicalOperation::AND);
+
+ addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
+ kTagIdWakelock, kKeyIdState, 3);
+ addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
+ kTagIdWakelock, kKeyIdPackageVersion, 4);
+
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
+
+ wrapper.intMap[1003] = 4;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap.clear();
+ wrapper.intMap[1] = 3;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap.clear();
+ wrapper.intMap[1] = 3;
+ wrapper.intMap[1003] = 4;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+}
+
+TEST(LogEntryMatcherTest, TestOrMatcher) {
+ // Set up the matcher
+ LogEntryMatcher matcher;
+ auto combination = matcher.mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+
+ addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
+ kTagIdWakelock, kKeyIdState, 3);
+ addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
+ kTagIdWakelock, kKeyIdPackageVersion, 4);
+
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
+
+ // Don't set any key-value pairs.
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[1003] = 4;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap.clear();
+ wrapper.intMap[1] = 3;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap.clear();
+ wrapper.intMap[1] = 3;
+ wrapper.intMap[1003] = 4;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+}
+
+TEST(LogEntryMatcherTest, TestNotMatcher) {
+ // Set up the matcher
+ LogEntryMatcher matcher;
+ auto combination = matcher.mutable_combination();
+ combination->set_operation(LogicalOperation::NOT);
+
+ // Define first simpleMatcher
+ addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
+ kTagIdWakelock, kKeyIdState, 3);
+
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
+
+ // Don't set any key-value pairs.
+ wrapper.intMap[kKeyIdState] = 3;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+}
+
+TEST(LogEntryMatcherTest, TestNANDMatcher) {
+ // Set up the matcher
+ LogEntryMatcher matcher;
+ auto combination = matcher.mutable_combination();
+ combination->set_operation(LogicalOperation::NAND);
+
+ addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
+ kTagIdWakelock, kKeyIdState, 3);
+ addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
+ kTagIdWakelock, kKeyIdPackageVersion, 4);
+
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
+
+ // Don't set any key-value pairs.
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 3;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdPackageVersion] = 4;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+}
+
+TEST(LogEntryMatcherTest, TestNORMatcher) {
+ // Set up the matcher
+ LogEntryMatcher matcher;
+ auto combination = matcher.mutable_combination();
+ combination->set_operation(LogicalOperation::NOR);
+
+ addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
+ kTagIdWakelock, kKeyIdState, 3);
+ addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
+ kTagIdWakelock, kKeyIdPackageVersion, 4);
+
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
+
+ // Don't set any key-value pairs.
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 3;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdPackageVersion] = 4;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+}
+
+// Tests that a NOT on top of AND is the same as NAND
+TEST(LogEntryMatcherTest, TestMultipleLayerMatcher) {
+ LogEntryMatcher matcher;
+ auto not_combination = matcher.mutable_combination();
+ not_combination->set_operation(LogicalOperation::NOT);
+
+ // Now add the AND
+ auto combination = not_combination->add_matcher()->mutable_combination();
+ combination->set_operation(LogicalOperation::AND);
+ addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
+ kTagIdWakelock, kKeyIdState, 3);
+ addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
+ kTagIdWakelock, kKeyIdPackageVersion, 4);
+
+ LogEventWrapper wrapper;
+ wrapper.tagId = kTagIdWakelock;
+
+ // Don't set any key-value pairs.
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdState] = 3;
+ EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.intMap[kKeyIdPackageVersion] = 4;
+ EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone
index df68f14..42e6ecf 100644
--- a/config/compiled-classes-phone
+++ b/config/compiled-classes-phone
@@ -5022,8 +5022,6 @@
android.widget.RemoteViews$BitmapCache
android.widget.RemoteViews$BitmapReflectionAction
android.widget.RemoteViews$LayoutParamAction
-android.widget.RemoteViews$MemoryUsageCounter
-android.widget.RemoteViews$MutablePair
android.widget.RemoteViews$OnClickHandler
android.widget.RemoteViews$OnViewAppliedListener
android.widget.RemoteViews$ReflectionAction
@@ -5031,7 +5029,7 @@
android.widget.RemoteViews$RemoteViewsContextWrapper
android.widget.RemoteViews$RunnableAction
android.widget.RemoteViews$RuntimeAction
-android.widget.RemoteViews$SetDrawableParameters
+android.widget.RemoteViews$SetDrawableTint
android.widget.RemoteViews$SetOnClickPendingIntent
android.widget.RemoteViews$SetOnClickPendingIntent$1
android.widget.RemoteViews$ViewGroupAction
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 337d7a0..1b86724 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -2193,6 +2193,7 @@
android.util.Log
android.util.Log$1
android.util.Log$ImmediateLogWriter
+android.util.Log$PreloadHolder
android.util.Log$TerribleFailureHandler
android.util.LogPrinter
android.util.LongArray
@@ -2723,13 +2724,11 @@
android.widget.RemoteViews$Action
android.widget.RemoteViews$BitmapCache
android.widget.RemoteViews$LayoutParamAction
-android.widget.RemoteViews$MemoryUsageCounter
-android.widget.RemoteViews$MutablePair
android.widget.RemoteViews$OnClickHandler
android.widget.RemoteViews$ReflectionAction
android.widget.RemoteViews$RemoteView
android.widget.RemoteViews$RuntimeAction
-android.widget.RemoteViews$SetDrawableParameters
+android.widget.RemoteViews$SetDrawableTint
android.widget.RemoteViewsAdapter$RemoteAdapterConnectionCallback
android.widget.RtlSpacingHelper
android.widget.ScrollBarDrawable
diff --git a/config/preloaded-classes-extra b/config/preloaded-classes-extra
index 959fff5..09f393a 100644
--- a/config/preloaded-classes-extra
+++ b/config/preloaded-classes-extra
@@ -8,6 +8,7 @@
android.media.SoundPool
android.text.format.Formatter
android.text.Html$HtmlParser
+android.util.Log$PreloadHolder
com.android.org.conscrypt.TrustedCertificateStore
org.ccil.cowan.tagsoup.HTMLScanner
sun.security.jca.Providers
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 00d6657..1a2dc5c 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -843,7 +843,7 @@
// Assumes forward playing from here on.
for (int i = 0; i < mEvents.size(); i++) {
AnimationEvent event = mEvents.get(i);
- if (event.getTime() > currentPlayTime) {
+ if (event.getTime() > currentPlayTime || event.getTime() == DURATION_INFINITE) {
break;
}
@@ -1264,7 +1264,8 @@
} else {
for (int i = mLastEventId + 1; i < size; i++) {
AnimationEvent event = mEvents.get(i);
- if (event.getTime() <= currentPlayTime) {
+ // TODO: need a function that accounts for infinite duration to compare time
+ if (event.getTime() != DURATION_INFINITE && event.getTime() <= currentPlayTime) {
latestId = i;
}
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 5e2e333..26f96fb 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -16,10 +16,6 @@
package android.app;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -46,6 +42,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -675,10 +672,7 @@
/** First static stack ID.
* @hide */
- public static final int FIRST_STATIC_STACK_ID = 0;
-
- /** Home activity stack ID. */
- public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID;
+ private static final int FIRST_STATIC_STACK_ID = 0;
/** ID of stack where fullscreen activities are normally launched into. */
public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;
@@ -692,15 +686,9 @@
/** ID of stack that always on top (always visible) when it exist. */
public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;
- /** ID of stack that contains the Recents activity. */
- public static final int RECENTS_STACK_ID = PINNED_STACK_ID + 1;
-
- /** ID of stack that contains activities launched by the assistant. */
- public static final int ASSISTANT_STACK_ID = RECENTS_STACK_ID + 1;
-
/** Last static stack stack ID.
* @hide */
- public static final int LAST_STATIC_STACK_ID = ASSISTANT_STACK_ID;
+ private static final int LAST_STATIC_STACK_ID = PINNED_STACK_ID;
/** Start of ID range used by stacks that are created dynamically.
* @hide */
@@ -720,15 +708,6 @@
}
/**
- * Returns true if dynamic stacks are allowed to be visible behind the input stack.
- * @hide
- */
- // TODO: Figure-out a way to remove.
- public static boolean isDynamicStacksVisibleBehindAllowed(int stackId) {
- return stackId == PINNED_STACK_ID || stackId == ASSISTANT_STACK_ID;
- }
-
- /**
* Returns true if we try to maintain focus in the current stack when the top activity
* finishes.
* @hide
@@ -740,15 +719,6 @@
}
/**
- * Returns true if the input stack is affected by drag resizing.
- * @hide
- */
- public static boolean isStackAffectedByDragResizing(int stackId) {
- return isStaticStack(stackId) && stackId != PINNED_STACK_ID
- && stackId != ASSISTANT_STACK_ID;
- }
-
- /**
* Returns true if the windows of tasks being moved to the target stack from the source
* stack should be replaced, meaning that window manager will keep the old window around
* until the new is ready.
@@ -760,26 +730,6 @@
}
/**
- * Return whether a stackId is a stack that be a backdrop to a translucent activity. These
- * are generally fullscreen stacks.
- * @hide
- */
- public static boolean isBackdropToTranslucentActivity(int stackId) {
- return stackId == FULLSCREEN_WORKSPACE_STACK_ID
- || stackId == ASSISTANT_STACK_ID;
- }
-
- /**
- * Returns true if activities from stasks in the given {@param stackId} are allowed to
- * enter picture-in-picture.
- * @hide
- */
- public static boolean isAllowedToEnterPictureInPicture(int stackId) {
- return stackId != HOME_STACK_ID && stackId != ASSISTANT_STACK_ID &&
- stackId != RECENTS_STACK_ID;
- }
-
- /**
* Returns true if the top task in the task is allowed to return home when finished and
* there are other tasks in the stack.
* @hide
@@ -810,34 +760,18 @@
&& stackId != DOCKED_STACK_ID;
}
- /**
- * Returns true if the input stack id should only be present on a device that supports
- * multi-window mode.
- * @see android.app.ActivityManager#supportsMultiWindow
- * @hide
- */
- // TODO: What about the other side of docked stack if we move this to WindowConfiguration?
- public static boolean isMultiWindowStack(int stackId) {
- return stackId == PINNED_STACK_ID || stackId == FREEFORM_WORKSPACE_STACK_ID
- || stackId == DOCKED_STACK_ID;
- }
-
- /**
- * Returns true if the input {@param stackId} is HOME_STACK_ID or RECENTS_STACK_ID
- * @hide
- */
- public static boolean isHomeOrRecentsStack(int stackId) {
- return stackId == HOME_STACK_ID || stackId == RECENTS_STACK_ID;
- }
-
- /** Returns true if the input stack and its content can affect the device orientation.
+ /** Returns the stack id for the input windowing mode.
* @hide */
- public static boolean canSpecifyOrientation(int stackId) {
- return stackId == HOME_STACK_ID
- || stackId == RECENTS_STACK_ID
- || stackId == FULLSCREEN_WORKSPACE_STACK_ID
- || stackId == ASSISTANT_STACK_ID
- || isDynamicStack(stackId);
+ // TODO: To be removed once we are not using stack id for stuff...
+ public static int getStackIdForWindowingMode(int windowingMode) {
+ switch (windowingMode) {
+ case WINDOWING_MODE_PINNED: return PINNED_STACK_ID;
+ case WINDOWING_MODE_FREEFORM: return FREEFORM_WORKSPACE_STACK_ID;
+ case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return DOCKED_STACK_ID;
+ case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return FULLSCREEN_WORKSPACE_STACK_ID;
+ case WINDOWING_MODE_FULLSCREEN: return FULLSCREEN_WORKSPACE_STACK_ID;
+ default: return INVALID_STACK_ID;
+ }
}
/** Returns the windowing mode that should be used for this input stack id.
@@ -847,14 +781,9 @@
final int windowingMode;
switch (stackId) {
case FULLSCREEN_WORKSPACE_STACK_ID:
- case HOME_STACK_ID:
- case RECENTS_STACK_ID:
windowingMode = inSplitScreenMode
? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY : WINDOWING_MODE_FULLSCREEN;
break;
- case ASSISTANT_STACK_ID:
- windowingMode = WINDOWING_MODE_FULLSCREEN;
- break;
case PINNED_STACK_ID:
windowingMode = WINDOWING_MODE_PINNED;
break;
@@ -869,51 +798,6 @@
}
return windowingMode;
}
-
- /** Returns the stack id for the input windowing mode.
- * @hide */
- // TODO: To be removed once we are not using stack id for stuff...
- public static int getStackIdForWindowingMode(int windowingMode) {
- switch (windowingMode) {
- case WINDOWING_MODE_PINNED: return PINNED_STACK_ID;
- case WINDOWING_MODE_FREEFORM: return FREEFORM_WORKSPACE_STACK_ID;
- case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return DOCKED_STACK_ID;
- default: return INVALID_STACK_ID;
- }
- }
-
- /** Returns the activity type that should be used for this input stack id.
- * @hide */
- // TODO: To be removed once we are not using stack id for stuff...
- public static int getActivityTypeForStackId(int stackId) {
- final int activityType;
- switch (stackId) {
- case HOME_STACK_ID:
- activityType = ACTIVITY_TYPE_HOME;
- break;
- case RECENTS_STACK_ID:
- activityType = ACTIVITY_TYPE_RECENTS;
- break;
- case ASSISTANT_STACK_ID:
- activityType = ACTIVITY_TYPE_ASSISTANT;
- break;
- default :
- activityType = ACTIVITY_TYPE_STANDARD;
- }
- return activityType;
- }
-
- /** Returns the stack id for the input activity type.
- * @hide */
- // TODO: To be removed once we are not using stack id for stuff...
- public static int getStackIdForActivityType(int activityType) {
- switch (activityType) {
- case ACTIVITY_TYPE_HOME: return HOME_STACK_ID;
- case ACTIVITY_TYPE_RECENTS: return RECENTS_STACK_ID;
- case ACTIVITY_TYPE_ASSISTANT: return ASSISTANT_STACK_ID;
- default: return INVALID_STACK_ID;
- }
- }
}
/**
@@ -1910,6 +1794,12 @@
*/
public int resizeMode;
+ /**
+ * The full configuration the task is currently running in.
+ * @hide
+ */
+ public Configuration configuration = new Configuration();
+
public RunningTaskInfo() {
}
@@ -1934,6 +1824,7 @@
dest.writeInt(numRunning);
dest.writeInt(supportsSplitScreenMultiWindow ? 1 : 0);
dest.writeInt(resizeMode);
+ configuration.writeToParcel(dest, flags);
}
public void readFromParcel(Parcel source) {
@@ -1951,6 +1842,7 @@
numRunning = source.readInt();
supportsSplitScreenMultiWindow = source.readInt() != 0;
resizeMode = source.readInt();
+ configuration.readFromParcel(source);
}
public static final Creator<RunningTaskInfo> CREATOR = new Creator<RunningTaskInfo>() {
@@ -2133,6 +2025,35 @@
}
/**
+ * Removes stacks in the windowing modes from the system if they are of activity type
+ * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
+ *
+ * @hide
+ */
+ @TestApi
+ public void removeStacksInWindowingModes(int[] windowingModes) throws SecurityException {
+ try {
+ getService().removeStacksInWindowingModes(windowingModes);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Removes stack of the activity types from the system.
+ *
+ * @hide
+ */
+ @TestApi
+ public void removeStacksWithActivityTypes(int[] activityTypes) throws SecurityException {
+ try {
+ getService().removeStacksWithActivityTypes(activityTypes);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Represents a task snapshot.
* @hide
*/
@@ -2610,6 +2531,11 @@
public boolean visible;
// Index of the stack in the display's stack list, can be used for comparison of stack order
public int position;
+ /**
+ * The full configuration the stack is currently running in.
+ * @hide
+ */
+ public Configuration configuration = new Configuration();
@Override
public int describeContents() {
@@ -2644,6 +2570,7 @@
} else {
dest.writeInt(0);
}
+ configuration.writeToParcel(dest, flags);
}
public void readFromParcel(Parcel source) {
@@ -2671,6 +2598,7 @@
if (source.readInt() > 0) {
topActivity = ComponentName.readFromParcel(source);
}
+ configuration.readFromParcel(source);
}
public static final Creator<StackInfo> CREATOR = new Creator<StackInfo>() {
@@ -2698,6 +2626,8 @@
sb.append(" displayId="); sb.append(displayId);
sb.append(" userId="); sb.append(userId);
sb.append("\n");
+ sb.append(" configuration="); sb.append(configuration);
+ sb.append("\n");
prefix = prefix + " ";
for (int i = 0; i < taskIds.length; ++i) {
sb.append(prefix); sb.append("taskId="); sb.append(taskIds[i]);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4e8d240..b07327f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5281,7 +5281,7 @@
final ApplicationInfo aInfo =
sPackageManager.getApplicationInfo(
packageName,
- 0 /*flags*/,
+ PackageManager.GET_SHARED_LIBRARY_FILES,
UserHandle.myUserId());
if (mActivities.size() > 0) {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index eccb264..955b463 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -380,7 +380,8 @@
boolean preserveWindows, boolean animate, int animationDuration);
List<ActivityManager.StackInfo> getAllStackInfos();
void setFocusedStack(int stackId);
- ActivityManager.StackInfo getStackInfo(int stackId);
+ ActivityManager.StackInfo getFocusedStackInfo();
+ ActivityManager.StackInfo getStackInfo(int windowingMode, int activityType);
boolean convertFromTranslucent(in IBinder token);
boolean convertToTranslucent(in IBinder token, in Bundle options);
void notifyActivityDrawn(in IBinder token);
@@ -440,7 +441,6 @@
// Start of M transactions
void notifyCleartextNetwork(int uid, in byte[] firstPacket);
int createStackOnDisplay(int displayId);
- int getFocusedStackId();
void setTaskResizeable(int taskId, int resizeableMode);
boolean requestAssistContextExtras(int requestType, in IResultReceiver receiver,
in Bundle receiverExtras, in IBinder activityToken,
@@ -540,6 +540,13 @@
void notifyPinnedStackAnimationStarted();
void notifyPinnedStackAnimationEnded();
void removeStack(int stackId);
+ /**
+ * Removes stacks in the input windowing modes from the system if they are of activity type
+ * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
+ */
+ void removeStacksInWindowingModes(in int[] windowingModes);
+ /** Removes stack of the activity types from the system. */
+ void removeStacksWithActivityTypes(in int[] activityTypes);
void makePackageIdle(String packageName, int userId);
int getMemoryTrimLevel();
/**
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 76643d6..54f74b1 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -174,7 +174,7 @@
*/
public Intent createConfirmFactoryResetCredentialIntent(
CharSequence title, CharSequence description, CharSequence alternateButtonLabel) {
- if (!LockPatternUtils.frpCredentialEnabled()) {
+ if (!LockPatternUtils.frpCredentialEnabled(mContext)) {
Log.w(TAG, "Factory reset credentials not supported.");
return null;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 60f4ed0..fee7d6c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3839,8 +3839,8 @@
contentView.setImageViewBitmap(R.id.profile_badge, profileBadge);
contentView.setViewVisibility(R.id.profile_badge, View.VISIBLE);
if (isColorized()) {
- contentView.setDrawableParameters(R.id.profile_badge, false, -1,
- getPrimaryTextColor(), PorterDuff.Mode.SRC_ATOP, -1);
+ contentView.setDrawableTint(R.id.profile_badge, false,
+ getPrimaryTextColor(), PorterDuff.Mode.SRC_ATOP);
}
}
}
@@ -4130,18 +4130,14 @@
if (action != null) {
int contrastColor = resolveContrastColor();
- contentView.setDrawableParameters(R.id.reply_icon_action,
+ contentView.setDrawableTint(R.id.reply_icon_action,
true /* targetBackground */,
- -1,
- contrastColor,
- PorterDuff.Mode.SRC_ATOP, -1);
+ contrastColor, PorterDuff.Mode.SRC_ATOP);
int iconColor = NotificationColorUtil.isColorLight(contrastColor)
? Color.BLACK : Color.WHITE;
- contentView.setDrawableParameters(R.id.reply_icon_action,
+ contentView.setDrawableTint(R.id.reply_icon_action,
false /* targetBackground */,
- -1,
- iconColor,
- PorterDuff.Mode.SRC_ATOP, -1);
+ iconColor, PorterDuff.Mode.SRC_ATOP);
contentView.setOnClickPendingIntent(R.id.right_icon,
action.actionIntent);
contentView.setOnClickPendingIntent(R.id.reply_icon_action,
@@ -4185,8 +4181,8 @@
private void bindExpandButton(RemoteViews contentView) {
int color = getPrimaryHighlightColor();
- contentView.setDrawableParameters(R.id.expand_button, false, -1, color,
- PorterDuff.Mode.SRC_ATOP, -1);
+ contentView.setDrawableTint(R.id.expand_button, false, color,
+ PorterDuff.Mode.SRC_ATOP);
contentView.setInt(R.id.notification_header, "setOriginalNotificationColor",
color);
}
@@ -4293,8 +4289,7 @@
mN.mSmallIcon = Icon.createWithResource(mContext, mN.icon);
}
contentView.setImageViewIcon(R.id.icon, mN.mSmallIcon);
- contentView.setDrawableParameters(R.id.icon, false /* targetBackground */,
- -1 /* alpha */, -1 /* colorFilter */, null /* mode */, mN.iconLevel);
+ contentView.setInt(R.id.icon, "setImageLevel", mN.iconLevel);
processSmallIconColor(mN.mSmallIcon, contentView, ambient);
}
@@ -4684,8 +4679,8 @@
bgColor = mContext.getColor(oddAction ? R.color.notification_action_list
: R.color.notification_action_list_dark);
}
- button.setDrawableParameters(R.id.button_holder, true, -1, bgColor,
- PorterDuff.Mode.SRC_ATOP, -1);
+ button.setDrawableTint(R.id.button_holder, true,
+ bgColor, PorterDuff.Mode.SRC_ATOP);
CharSequence title = action.title;
ColorStateList[] outResultColor = null;
if (isLegacy()) {
@@ -4818,8 +4813,8 @@
boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon);
int color = ambient ? resolveAmbientColor() : getPrimaryHighlightColor();
if (colorable) {
- contentView.setDrawableParameters(R.id.icon, false, -1, color,
- PorterDuff.Mode.SRC_ATOP, -1);
+ contentView.setDrawableTint(R.id.icon, false, color,
+ PorterDuff.Mode.SRC_ATOP);
}
contentView.setInt(R.id.notification_header, "setOriginalIconColor",
@@ -4835,8 +4830,8 @@
if (largeIcon != null && isLegacy()
&& getColorUtil().isGrayscaleIcon(mContext, largeIcon)) {
// resolve color will fall back to the default when legacy
- contentView.setDrawableParameters(R.id.icon, false, -1, resolveContrastColor(),
- PorterDuff.Mode.SRC_ATOP, -1);
+ contentView.setDrawableTint(R.id.icon, false, resolveContrastColor(),
+ PorterDuff.Mode.SRC_ATOP);
}
}
@@ -6750,8 +6745,8 @@
: NotificationColorUtil.resolveColor(mBuilder.mContext,
Notification.COLOR_DEFAULT);
- button.setDrawableParameters(R.id.action0, false, -1, tintColor,
- PorterDuff.Mode.SRC_ATOP, -1);
+ button.setDrawableTint(R.id.action0, false, tintColor,
+ PorterDuff.Mode.SRC_ATOP);
if (!tombstone) {
button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 8fa7d6c..eb52cb7 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -41,6 +41,7 @@
import android.service.notification.StatusBarNotification;
import android.service.notification.ZenModeConfig;
import android.util.Log;
+import android.util.proto.ProtoOutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -1061,6 +1062,27 @@
+ "]";
}
+ /** @hide */
+ public void toProto(ProtoOutputStream proto, long fieldId) {
+ final long pToken = proto.start(fieldId);
+
+ bitwiseToProtoEnum(proto, PolicyProto.PRIORITY_CATEGORIES, priorityCategories);
+ proto.write(PolicyProto.PRIORITY_CALL_SENDER, priorityCallSenders);
+ proto.write(PolicyProto.PRIORITY_MESSAGE_SENDER, priorityMessageSenders);
+ bitwiseToProtoEnum(
+ proto, PolicyProto.SUPPRESSED_VISUAL_EFFECTS, suppressedVisualEffects);
+
+ proto.end(pToken);
+ }
+
+ private static void bitwiseToProtoEnum(ProtoOutputStream proto, long fieldId, int data) {
+ for (int i = 1; data > 0; ++i, data >>>= 1) {
+ if ((data & 1) == 1) {
+ proto.write(fieldId, i);
+ }
+ }
+ }
+
public static String suppressedEffectsToString(int effects) {
if (effects <= 0) return "";
final StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/app/SharedElementCallback.java b/core/java/android/app/SharedElementCallback.java
index af13e69..0d14a8d 100644
--- a/core/java/android/app/SharedElementCallback.java
+++ b/core/java/android/app/SharedElementCallback.java
@@ -176,7 +176,7 @@
Drawable d = imageView.getDrawable();
Drawable bg = imageView.getBackground();
if (d != null && (bg == null || bg.getAlpha() == 0)) {
- Bitmap bitmap = TransitionUtils.createDrawableBitmap(d);
+ Bitmap bitmap = TransitionUtils.createDrawableBitmap(d, imageView);
if (bitmap != null) {
Bundle bundle = new Bundle();
if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index fe7afed..80144bd 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -70,14 +70,15 @@
* Setting this flag disables quick settings completely, but does not disable expanding the
* notification shade.
*/
- public static final int DISABLE2_QUICK_SETTINGS = 0x00000001;
+ public static final int DISABLE2_QUICK_SETTINGS = 1;
+ public static final int DISABLE2_SYSTEM_ICONS = 1 << 1;
public static final int DISABLE2_NONE = 0x00000000;
- public static final int DISABLE2_MASK = DISABLE2_QUICK_SETTINGS;
+ public static final int DISABLE2_MASK = DISABLE2_QUICK_SETTINGS | DISABLE2_SYSTEM_ICONS;
@IntDef(flag = true,
- value = {DISABLE2_NONE, DISABLE2_MASK, DISABLE2_QUICK_SETTINGS})
+ value = {DISABLE2_NONE, DISABLE2_MASK, DISABLE2_QUICK_SETTINGS, DISABLE2_SYSTEM_ICONS})
@Retention(RetentionPolicy.SOURCE)
public @interface Disable2Flags {}
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 0cb3804..6b40538 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -500,10 +500,15 @@
* @hide
*/
public boolean supportSplitScreenWindowingMode() {
- if (mActivityType == ACTIVITY_TYPE_ASSISTANT) {
+ return supportSplitScreenWindowingMode(mWindowingMode, mActivityType);
+ }
+
+ /** @hide */
+ public static boolean supportSplitScreenWindowingMode(int windowingMode, int activityType) {
+ if (activityType == ACTIVITY_TYPE_ASSISTANT) {
return false;
}
- return mWindowingMode != WINDOWING_MODE_FREEFORM && mWindowingMode != WINDOWING_MODE_PINNED;
+ return windowingMode != WINDOWING_MODE_FREEFORM && windowingMode != WINDOWING_MODE_PINNED;
}
private static String windowingModeToString(@WindowingMode int windowingMode) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 6bccad9..d9670ca 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -7534,12 +7534,12 @@
}
/**
- * Called by the device owner or profile owner to set the name of the organization under
- * management.
- * <p>
- * If the organization name needs to be localized, it is the responsibility of the
- * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
- * and set a new version of this string accordingly.
+ * Called by the device owner (since API 26) or profile owner (since API 24) to set the name of
+ * the organization under management.
+ *
+ * <p>If the organization name needs to be localized, it is the responsibility of the {@link
+ * DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast and set
+ * a new version of this string accordingly.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param title The organization name or {@code null} to clear a previously set name.
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 55c22de..c208f1d 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1260,12 +1260,12 @@
* <p>Typically used when the view associated with the view is a container for an HTML
* document.
*
- * <strong>WARNING:</strong> a {@link android.service.autofill.AutofillService} should only
- * use this domain for autofill purposes when it trusts the app generating it (i.e., the app
- * defined by {@link AssistStructure#getActivityComponent()}).
+ * <p><b>Warning:</b> an autofill service cannot trust the value reported by this method
+ * without verifing its authenticity—see the "Web security" section of
+ * {@link android.service.autofill.AutofillService} for more details.
*
* @return domain-only part of the document. For example, if the full URL is
- * {@code http://my.site/login?user=my_user}, it returns {@code my.site}.
+ * {@code https://my.site/login?user=my_user}, it returns {@code my.site}.
*/
@Nullable public String getWebDomain() {
return mWebDomain;
diff --git a/core/java/android/app/timezone/RulesUpdaterContract.java b/core/java/android/app/timezone/RulesUpdaterContract.java
index 2a22ead..74ed658 100644
--- a/core/java/android/app/timezone/RulesUpdaterContract.java
+++ b/core/java/android/app/timezone/RulesUpdaterContract.java
@@ -83,8 +83,7 @@
Intent intent = createUpdaterIntent(updaterAppPackageName);
intent.putExtra(EXTRA_CHECK_TOKEN, checkTokenBytes);
context.sendBroadcastAsUser(
- intent,
- UserHandle.of(UserHandle.myUserId()),
+ intent, UserHandle.SYSTEM,
RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION);
}
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 70591d4..84765f6 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1134,6 +1134,29 @@
}
/**
+ * Sets the {@link BluetoothClass} Bluetooth Class of Device (CoD) of
+ * the local Bluetooth adapter.
+ *
+ * @param bluetoothClass {@link BluetoothClass} to set the local Bluetooth adapter to.
+ * @return true if successful, false if unsuccessful.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setBluetoothClass(BluetoothClass bluetoothClass) {
+ if (getState() != STATE_ON) return false;
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) return mService.setBluetoothClass(bluetoothClass);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return false;
+ }
+
+ /**
* Get the current Bluetooth scan mode of the local Bluetooth adapter.
* <p>The Bluetooth scan mode determines if the local adapter is
* connectable and/or discoverable from remote Bluetooth devices.
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index 57e4abb..f22ea6e 100755
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -19,6 +19,10 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
/**
* Represents a Bluetooth class, which describes general characteristics
* and capabilities of a device. For example, a Bluetooth class will
@@ -275,6 +279,48 @@
return (mClass & Device.BITMASK);
}
+ /**
+ * Return the Bluetooth Class of Device (CoD) value including the
+ * {@link BluetoothClass.Service}, {@link BluetoothClass.Device.Major} and
+ * minor device fields.
+ *
+ * <p>This value is an integer representation of Bluetooth CoD as in
+ * Bluetooth specification.
+ *
+ * @see <a href="Bluetooth CoD">https://www.bluetooth.com/specifications/assigned-numbers/baseband</a>
+ *
+ * @hide
+ */
+ public int getClassOfDevice() {
+ return mClass;
+ }
+
+ /**
+ * Return the Bluetooth Class of Device (CoD) value including the
+ * {@link BluetoothClass.Service}, {@link BluetoothClass.Device.Major} and
+ * minor device fields.
+ *
+ * <p>This value is a byte array representation of Bluetooth CoD as in
+ * Bluetooth specification.
+ *
+ * <p>Bluetooth COD information is 3 bytes, but stored as an int. Hence the
+ * MSB is useless and needs to be thrown away. The lower 3 bytes are
+ * converted into a byte array MSB to LSB. Hence, using BIG_ENDIAN.
+ *
+ * @see <a href="Bluetooth CoD">https://www.bluetooth.com/specifications/assigned-numbers/baseband</a>
+ *
+ * @hide
+ */
+ public byte[] getClassOfDeviceBytes() {
+ byte[] bytes = ByteBuffer.allocate(4)
+ .order(ByteOrder.BIG_ENDIAN)
+ .putInt(mClass)
+ .array();
+
+ // Discard the top byte
+ return Arrays.copyOfRange(bytes, 1, bytes.length);
+ }
+
/** @hide */
public static final int PROFILE_HEADSET = 0;
/** @hide */
diff --git a/core/java/android/bluetooth/BluetoothInputHost.java b/core/java/android/bluetooth/BluetoothInputHost.java
index 37f0427..e18d9d1 100644
--- a/core/java/android/bluetooth/BluetoothInputHost.java
+++ b/core/java/android/bluetooth/BluetoothInputHost.java
@@ -74,7 +74,7 @@
public static final byte SUBCLASS2_GAMEPAD = (byte) 0x02;
public static final byte SUBCLASS2_REMOTE_CONTROL = (byte) 0x03;
public static final byte SUBCLASS2_SENSING_DEVICE = (byte) 0x04;
- public static final byte SUBCLASS2_DIGITIZER_TABLED = (byte) 0x05;
+ public static final byte SUBCLASS2_DIGITIZER_TABLET = (byte) 0x05;
public static final byte SUBCLASS2_CARD_READER = (byte) 0x06;
/**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 03e4dfe..693921d 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3034,6 +3034,9 @@
* <dt> {@link #CONNECTIVITY_SERVICE} ("connection")
* <dd> A {@link android.net.ConnectivityManager ConnectivityManager} for
* handling management of network connections.
+ * <dt> {@link #IPSEC_SERVICE} ("ipsec")
+ * <dd> A {@link android.net.IpSecManager IpSecManager} for managing IPSec on
+ * sockets and networks.
* <dt> {@link #WIFI_SERVICE} ("wifi")
* <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of Wi-Fi
* connectivity. On releases before NYC, it should only be obtained from an application
@@ -3378,7 +3381,6 @@
* {@link android.net.IpSecManager} for encrypting Sockets or Networks with
* IPSec.
*
- * @hide
* @see #getSystemService
*/
public static final String IPSEC_SERVICE = "ipsec";
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0e70645..1352bc2 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -554,14 +554,6 @@
*/
void reconcileSecondaryDexFiles(String packageName);
- /**
- * Update status of external media on the package manager to scan and
- * install packages installed on the external media. Like say the
- * StorageManagerService uses this to call into the package manager to update
- * status of sdcard.
- */
- void updateExternalMediaStatus(boolean mounted, boolean reportStatus);
-
PackageCleanItem nextPackageToClean(in PackageCleanItem lastPackage);
int getMoveStatus(int moveId);
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 17b4f87..b45c26c 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -318,16 +318,19 @@
return null;
}
+ @Override
public String toString() {
return "PermissionInfo{"
+ Integer.toHexString(System.identityHashCode(this))
+ " " + name + "}";
}
+ @Override
public int describeContents() {
return 0;
}
+ @Override
public void writeToParcel(Parcel dest, int parcelableFlags) {
super.writeToParcel(dest, parcelableFlags);
dest.writeInt(protectionLevel);
@@ -338,11 +341,25 @@
TextUtils.writeToParcel(nonLocalizedDescription, dest, parcelableFlags);
}
+ /** @hide */
+ public int calculateFootprint() {
+ int size = name.length();
+ if (nonLocalizedLabel != null) {
+ size += nonLocalizedLabel.length();
+ }
+ if (nonLocalizedDescription != null) {
+ size += nonLocalizedDescription.length();
+ }
+ return size;
+ }
+
public static final Creator<PermissionInfo> CREATOR =
new Creator<PermissionInfo>() {
+ @Override
public PermissionInfo createFromParcel(Parcel source) {
return new PermissionInfo(source);
}
+ @Override
public PermissionInfo[] newArray(int size) {
return new PermissionInfo[size];
}
diff --git a/core/java/android/hardware/LegacySensorManager.java b/core/java/android/hardware/LegacySensorManager.java
index f5cf3f7..098121d 100644
--- a/core/java/android/hardware/LegacySensorManager.java
+++ b/core/java/android/hardware/LegacySensorManager.java
@@ -204,7 +204,7 @@
}
private static final class LegacyListener implements SensorEventListener {
- private float mValues[] = new float[6];
+ private float[] mValues = new float[6];
private SensorListener mTarget;
private int mSensors;
private final LmsFilter mYawfilter = new LmsFilter();
@@ -256,7 +256,7 @@
}
public void onSensorChanged(SensorEvent event) {
- final float v[] = mValues;
+ final float[] v = mValues;
v[0] = event.values[0];
v[1] = event.values[1];
v[2] = event.values[2];
@@ -264,10 +264,10 @@
int legacyType = getLegacySensorType(type);
mapSensorDataToWindow(legacyType, v, LegacySensorManager.getRotation());
if (type == Sensor.TYPE_ORIENTATION) {
- if ((mSensors & SensorManager.SENSOR_ORIENTATION_RAW)!=0) {
+ if ((mSensors & SensorManager.SENSOR_ORIENTATION_RAW) != 0) {
mTarget.onSensorChanged(SensorManager.SENSOR_ORIENTATION_RAW, v);
}
- if ((mSensors & SensorManager.SENSOR_ORIENTATION)!=0) {
+ if ((mSensors & SensorManager.SENSOR_ORIENTATION) != 0) {
v[0] = mYawfilter.filter(event.timestamp, v[0]);
mTarget.onSensorChanged(SensorManager.SENSOR_ORIENTATION, v);
}
@@ -317,7 +317,7 @@
switch (sensor) {
case SensorManager.SENSOR_ACCELEROMETER:
case SensorManager.SENSOR_MAGNETIC_FIELD:
- values[0] =-y;
+ values[0] = -y;
values[1] = x;
values[2] = z;
break;
@@ -337,15 +337,15 @@
switch (sensor) {
case SensorManager.SENSOR_ACCELEROMETER:
case SensorManager.SENSOR_MAGNETIC_FIELD:
- values[0] =-x;
- values[1] =-y;
+ values[0] = -x;
+ values[1] = -y;
values[2] = z;
break;
case SensorManager.SENSOR_ORIENTATION:
case SensorManager.SENSOR_ORIENTATION_RAW:
values[0] = (x >= 180) ? (x - 180) : (x + 180);
- values[1] =-y;
- values[2] =-z;
+ values[1] = -y;
+ values[2] = -z;
break;
}
}
@@ -369,10 +369,11 @@
private static final class LmsFilter {
private static final int SENSORS_RATE_MS = 20;
private static final int COUNT = 12;
- private static final float PREDICTION_RATIO = 1.0f/3.0f;
- private static final float PREDICTION_TIME = (SENSORS_RATE_MS*COUNT/1000.0f)*PREDICTION_RATIO;
- private float mV[] = new float[COUNT*2];
- private long mT[] = new long[COUNT*2];
+ private static final float PREDICTION_RATIO = 1.0f / 3.0f;
+ private static final float PREDICTION_TIME =
+ (SENSORS_RATE_MS * COUNT / 1000.0f) * PREDICTION_RATIO;
+ private float[] mV = new float[COUNT * 2];
+ private long[] mT = new long[COUNT * 2];
private int mIndex;
public LmsFilter() {
@@ -383,9 +384,9 @@
float v = in;
final float ns = 1.0f / 1000000000.0f;
float v1 = mV[mIndex];
- if ((v-v1) > 180) {
+ if ((v - v1) > 180) {
v -= 360;
- } else if ((v1-v) > 180) {
+ } else if ((v1 - v) > 180) {
v += 360;
}
/* Manage the circular buffer, we write the data twice spaced
@@ -393,40 +394,43 @@
* when it's full
*/
mIndex++;
- if (mIndex >= COUNT*2)
+ if (mIndex >= COUNT * 2) {
mIndex = COUNT;
+ }
mV[mIndex] = v;
mT[mIndex] = time;
- mV[mIndex-COUNT] = v;
- mT[mIndex-COUNT] = time;
+ mV[mIndex - COUNT] = v;
+ mT[mIndex - COUNT] = time;
float A, B, C, D, E;
float a, b;
int i;
A = B = C = D = E = 0;
- for (i=0 ; i<COUNT-1 ; i++) {
+ for (i = 0; i < COUNT - 1; i++) {
final int j = mIndex - 1 - i;
final float Z = mV[j];
- final float T = (mT[j]/2 + mT[j+1]/2 - time)*ns;
- float dT = (mT[j] - mT[j+1])*ns;
+ final float T = (mT[j] / 2 + mT[j + 1] / 2 - time) * ns;
+ float dT = (mT[j] - mT[j + 1]) * ns;
dT *= dT;
- A += Z*dT;
- B += T*(T*dT);
- C += (T*dT);
- D += Z*(T*dT);
+ A += Z * dT;
+ B += T * (T * dT);
+ C += (T * dT);
+ D += Z * (T * dT);
E += dT;
}
- b = (A*B + C*D) / (E*B + C*C);
- a = (E*b - A) / C;
- float f = b + PREDICTION_TIME*a;
+ b = (A * B + C * D) / (E * B + C * C);
+ a = (E * b - A) / C;
+ float f = b + PREDICTION_TIME * a;
// Normalize
f *= (1.0f / 360.0f);
- if (((f>=0)?f:-f) >= 0.5f)
- f = f - (float)Math.ceil(f + 0.5f) + 1.0f;
- if (f < 0)
+ if (((f >= 0) ? f : -f) >= 0.5f) {
+ f = f - (float) Math.ceil(f + 0.5f) + 1.0f;
+ }
+ if (f < 0) {
f += 1.0f;
+ }
f *= 360.0f;
return f;
}
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index f02e484..7fb0c89 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -794,12 +794,12 @@
1, // SENSOR_TYPE_PICK_UP_GESTURE
1, // SENSOR_TYPE_WRIST_TILT_GESTURE
1, // SENSOR_TYPE_DEVICE_ORIENTATION
- 16,// SENSOR_TYPE_POSE_6DOF
+ 16, // SENSOR_TYPE_POSE_6DOF
1, // SENSOR_TYPE_STATIONARY_DETECT
1, // SENSOR_TYPE_MOTION_DETECT
1, // SENSOR_TYPE_HEART_BEAT
2, // SENSOR_TYPE_DYNAMIC_SENSOR_META
- 16,// skip over additional sensor info type
+ 16, // skip over additional sensor info type
1, // SENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT
6, // SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED
};
@@ -857,8 +857,8 @@
static int getMaxLengthValuesArray(Sensor sensor, int sdkLevel) {
// RotationVector length has changed to 3 to 5 for API level 18
// Set it to 3 for backward compatibility.
- if (sensor.mType == Sensor.TYPE_ROTATION_VECTOR &&
- sdkLevel <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ if (sensor.mType == Sensor.TYPE_ROTATION_VECTOR
+ && sdkLevel <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
return 3;
}
int offset = sensor.mType;
@@ -1033,9 +1033,9 @@
* Returns true if the sensor is a wake-up sensor.
* <p>
* <b>Application Processor Power modes</b> <p>
- * Application Processor(AP), is the processor on which applications run. When no wake lock is held
- * and the user is not interacting with the device, this processor can enter a “Suspend” mode,
- * reducing the power consumption by 10 times or more.
+ * Application Processor(AP), is the processor on which applications run. When no wake lock is
+ * held and the user is not interacting with the device, this processor can enter a “Suspend”
+ * mode, reducing the power consumption by 10 times or more.
* </p>
* <p>
* <b>Non-wake-up sensors</b> <p>
@@ -1232,6 +1232,6 @@
*/
private void setUuid(long msb, long lsb) {
// TODO(b/29547335): Rename this method to setId.
- mId = (int)msb;
+ mId = (int) msb;
}
}
diff --git a/core/java/android/hardware/SensorAdditionalInfo.java b/core/java/android/hardware/SensorAdditionalInfo.java
index 0c6a415..7c876cf 100644
--- a/core/java/android/hardware/SensorAdditionalInfo.java
+++ b/core/java/android/hardware/SensorAdditionalInfo.java
@@ -200,7 +200,7 @@
public static final int TYPE_DEBUG_INFO = 0x40000000;
SensorAdditionalInfo(
- Sensor aSensor, int aType, int aSerial, int [] aIntValues, float [] aFloatValues) {
+ Sensor aSensor, int aType, int aSerial, int[] aIntValues, float[] aFloatValues) {
sensor = aSensor;
type = aType;
serial = aSerial;
@@ -222,10 +222,10 @@
null, new float[] { strength, declination, inclination});
}
/** @hide */
- public static SensorAdditionalInfo createCustomInfo(Sensor aSensor, int type, float [] data) {
+ public static SensorAdditionalInfo createCustomInfo(Sensor aSensor, int type, float[] data) {
if (type < TYPE_CUSTOM_INFO || type >= TYPE_DEBUG_INFO || aSensor == null) {
- throw new IllegalArgumentException("invalid parameter(s): type: " + type +
- "; sensor: " + aSensor);
+ throw new IllegalArgumentException(
+ "invalid parameter(s): type: " + type + "; sensor: " + aSensor);
}
return new SensorAdditionalInfo(aSensor, type, 0, null, data);
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index c0bca97..bbd04a3 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -207,8 +207,8 @@
* timestamp = event.timestamp;
* float[] deltaRotationMatrix = new float[9];
* SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
- * // User code should concatenate the delta rotation we computed with the current rotation
- * // in order to get the updated rotation.
+ * // User code should concatenate the delta rotation we computed with the current
+ * // rotation in order to get the updated rotation.
* // rotationCurrent = rotationCurrent * deltaRotationMatrix;
* }
* </pre>
@@ -244,21 +244,22 @@
* <h4>{@link android.hardware.Sensor#TYPE_GRAVITY Sensor.TYPE_GRAVITY}:</h4>
* <p>A three dimensional vector indicating the direction and magnitude of gravity. Units
* are m/s^2. The coordinate system is the same as is used by the acceleration sensor.</p>
- * <p><b>Note:</b> When the device is at rest, the output of the gravity sensor should be identical
- * to that of the accelerometer.</p>
+ * <p><b>Note:</b> When the device is at rest, the output of the gravity sensor should be
+ * identical to that of the accelerometer.</p>
*
- * <h4>{@link android.hardware.Sensor#TYPE_LINEAR_ACCELERATION Sensor.TYPE_LINEAR_ACCELERATION}:</h4>
- * A three dimensional vector indicating acceleration along each device axis, not including
- * gravity. All values have units of m/s^2. The coordinate system is the same as is used by the
- * acceleration sensor.
+ * <h4>
+ * {@link android.hardware.Sensor#TYPE_LINEAR_ACCELERATION Sensor.TYPE_LINEAR_ACCELERATION}:
+ * </h4> A three dimensional vector indicating acceleration along each device axis, not
+ * including gravity. All values have units of m/s^2. The coordinate system is the same as is
+ * used by the acceleration sensor.
* <p>The output of the accelerometer, gravity and linear-acceleration sensors must obey the
* following relation:</p>
- * <p><ul>acceleration = gravity + linear-acceleration</ul></p>
+ * <p><ul>acceleration = gravity + linear-acceleration</ul></p>
*
* <h4>{@link android.hardware.Sensor#TYPE_ROTATION_VECTOR Sensor.TYPE_ROTATION_VECTOR}:</h4>
- * <p>The rotation vector represents the orientation of the device as a combination of an <i>angle</i>
- * and an <i>axis</i>, in which the device has rotated through an angle θ around an axis
- * <x, y, z>.</p>
+ * <p>The rotation vector represents the orientation of the device as a combination of an
+ * <i>angle</i> and an <i>axis</i>, in which the device has rotated through an angle θ
+ * around an axis <x, y, z>.</p>
* <p>The three elements of the rotation vector are
* <x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)>, such that the magnitude of the rotation
* vector is equal to sin(θ/2), and the direction of the rotation vector is equal to the
diff --git a/core/java/android/hardware/SensorListener.java b/core/java/android/hardware/SensorListener.java
index c71e968..e2033b6 100644
--- a/core/java/android/hardware/SensorListener.java
+++ b/core/java/android/hardware/SensorListener.java
@@ -19,8 +19,8 @@
/**
* Used for receiving notifications from the SensorManager when
* sensor values have changed.
- *
- * @deprecated Use
+ *
+ * @deprecated Use
* {@link android.hardware.SensorEventListener SensorEventListener} instead.
*/
@Deprecated
@@ -36,7 +36,7 @@
* <p><u>Definition of the coordinate system used below.</u><p>
* <p>The X axis refers to the screen's horizontal axis
* (the small edge in portrait mode, the long edge in landscape mode) and
- * points to the right.
+ * points to the right.
* <p>The Y axis refers to the screen's vertical axis and points towards
* the top of the screen (the origin is in the lower-left corner).
* <p>The Z axis points toward the sky when the device is lying on its back
@@ -44,18 +44,18 @@
* <p> <b>IMPORTANT NOTE:</b> The axis <b><u>are swapped</u></b> when the
* device's screen orientation changes. To access the unswapped values,
* use indices 3, 4 and 5 in values[].
- *
+ *
* <p>{@link android.hardware.SensorManager#SENSOR_ORIENTATION SENSOR_ORIENTATION},
* {@link android.hardware.SensorManager#SENSOR_ORIENTATION_RAW SENSOR_ORIENTATION_RAW}:<p>
* All values are angles in degrees.
- *
+ *
* <p>values[0]: Azimuth, rotation around the Z axis (0<=azimuth<360).
* 0 = North, 90 = East, 180 = South, 270 = West
- *
+ *
* <p>values[1]: Pitch, rotation around X axis (-180<=pitch<=180), with positive
* values when the z-axis moves toward the y-axis.
*
- * <p>values[2]: Roll, rotation around Y axis (-90<=roll<=90), with positive values
+ * <p>values[2]: Roll, rotation around Y axis (-90<=roll<=90), with positive values
* when the z-axis moves toward the x-axis.
*
* <p>Note that this definition of yaw, pitch and roll is different from the
@@ -64,17 +64,17 @@
*
* <p>{@link android.hardware.SensorManager#SENSOR_ACCELEROMETER SENSOR_ACCELEROMETER}:<p>
* All values are in SI units (m/s^2) and measure contact forces.
- *
- * <p>values[0]: force applied by the device on the x-axis
- * <p>values[1]: force applied by the device on the y-axis
+ *
+ * <p>values[0]: force applied by the device on the x-axis
+ * <p>values[1]: force applied by the device on the y-axis
* <p>values[2]: force applied by the device on the z-axis
- *
+ *
* <p><u>Examples</u>:
* <li>When the device is pushed on its left side toward the right, the
* x acceleration value is negative (the device applies a reaction force
* to the push toward the left)</li>
- *
- * <li>When the device lies flat on a table, the acceleration value is
+ *
+ * <li>When the device lies flat on a table, the acceleration value is
* {@link android.hardware.SensorManager#STANDARD_GRAVITY -STANDARD_GRAVITY},
* which correspond to the force the device applies on the table in reaction
* to gravity.</li>
@@ -83,7 +83,7 @@
* All values are in micro-Tesla (uT) and measure the ambient magnetic
* field in the X, Y and -Z axis.
* <p><b><u>Note:</u></b> the magnetic field's Z axis is inverted.
- *
+ *
* @param sensor The ID of the sensor being monitored
* @param values The new values for the sensor.
*/
@@ -97,5 +97,5 @@
* @param sensor The ID of the sensor being monitored
* @param accuracy The new accuracy of this sensor.
*/
- public void onAccuracyChanged(int sensor, int accuracy);
+ public void onAccuracyChanged(int sensor, int accuracy);
}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index e1cd451..35aaf78 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -83,7 +83,7 @@
/** @hide */
protected static final String TAG = "SensorManager";
- private static final float[] mTempMatrix = new float[16];
+ private static final float[] sTempMatrix = new float[16];
// Cached lists of sensors by type. Guarded by mSensorListByType.
private final SparseArray<List<Sensor>> mSensorListByType =
@@ -188,7 +188,7 @@
* @deprecated use {@link android.hardware.Sensor Sensor} instead.
*/
@Deprecated
- public static final int SENSOR_MAX = ((SENSOR_ALL + 1)>>1);
+ public static final int SENSOR_MAX = ((SENSOR_ALL + 1) >> 1);
/**
@@ -425,8 +425,9 @@
} else {
list = new ArrayList<Sensor>();
for (Sensor i : fullList) {
- if (i.getType() == type)
+ if (i.getType() == type) {
list.add(i);
+ }
}
}
list = Collections.unmodifiableList(list);
@@ -461,8 +462,9 @@
} else {
List<Sensor> list = new ArrayList();
for (Sensor i : fullList) {
- if (i.getType() == type)
+ if (i.getType() == type) {
list.add(i);
+ }
}
return Collections.unmodifiableList(list);
}
@@ -490,10 +492,11 @@
// For the following sensor types, return a wake-up sensor. These types are by default
// defined as wake-up sensors. For the rest of the SDK defined sensor types return a
// non_wake-up version.
- if (type == Sensor.TYPE_PROXIMITY || type == Sensor.TYPE_SIGNIFICANT_MOTION ||
- type == Sensor.TYPE_TILT_DETECTOR || type == Sensor.TYPE_WAKE_GESTURE ||
- type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE ||
- type == Sensor.TYPE_WRIST_TILT_GESTURE || type == Sensor.TYPE_DYNAMIC_SENSOR_META) {
+ if (type == Sensor.TYPE_PROXIMITY || type == Sensor.TYPE_SIGNIFICANT_MOTION
+ || type == Sensor.TYPE_TILT_DETECTOR || type == Sensor.TYPE_WAKE_GESTURE
+ || type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE
+ || type == Sensor.TYPE_WRIST_TILT_GESTURE
+ || type == Sensor.TYPE_DYNAMIC_SENSOR_META) {
wakeUpSensor = true;
}
@@ -509,12 +512,12 @@
* <p>
* For example,
* <ul>
- * <li>getDefaultSensor({@link Sensor#TYPE_ACCELEROMETER}, true) returns a wake-up accelerometer
- * sensor if it exists. </li>
- * <li>getDefaultSensor({@link Sensor#TYPE_PROXIMITY}, false) returns a non wake-up proximity
- * sensor if it exists. </li>
- * <li>getDefaultSensor({@link Sensor#TYPE_PROXIMITY}, true) returns a wake-up proximity sensor
- * which is the same as the Sensor returned by {@link #getDefaultSensor(int)}. </li>
+ * <li>getDefaultSensor({@link Sensor#TYPE_ACCELEROMETER}, true) returns a wake-up
+ * accelerometer sensor if it exists. </li>
+ * <li>getDefaultSensor({@link Sensor#TYPE_PROXIMITY}, false) returns a non wake-up
+ * proximity sensor if it exists. </li>
+ * <li>getDefaultSensor({@link Sensor#TYPE_PROXIMITY}, true) returns a wake-up proximity
+ * sensor which is the same as the Sensor returned by {@link #getDefaultSensor(int)}. </li>
* </ul>
* </p>
* <p class="note">
@@ -532,8 +535,9 @@
public Sensor getDefaultSensor(int type, boolean wakeUp) {
List<Sensor> l = getSensorList(type);
for (Sensor sensor : l) {
- if (sensor.isWakeUpSensor() == wakeUp)
+ if (sensor.isWakeUpSensor() == wakeUp) {
return sensor;
+ }
}
return null;
}
@@ -842,8 +846,8 @@
* @return <code>true</code> if the sensor is supported and successfully enabled.
* @see #registerListener(SensorEventListener, Sensor, int, int)
*/
- public boolean registerListener(SensorEventListener listener, Sensor sensor, int samplingPeriodUs,
- int maxReportLatencyUs, Handler handler) {
+ public boolean registerListener(SensorEventListener listener, Sensor sensor,
+ int samplingPeriodUs, int maxReportLatencyUs, Handler handler) {
int delayUs = getDelay(samplingPeriodUs);
return registerListenerImpl(listener, sensor, delayUs, handler, maxReportLatencyUs, 0);
}
@@ -953,7 +957,7 @@
* Used for receiving notifications from the SensorManager when dynamic sensors are connected or
* disconnected.
*/
- public static abstract class DynamicSensorCallback {
+ public abstract static class DynamicSensorCallback {
/**
* Called when there is a dynamic sensor being connected to the system.
*
@@ -1180,7 +1184,7 @@
float Ay = gravity[1];
float Az = gravity[2];
- final float normsqA = (Ax*Ax + Ay*Ay + Az*Az);
+ final float normsqA = (Ax * Ax + Ay * Ay + Az * Az);
final float g = 9.81f;
final float freeFallGravitySquared = 0.01f * g * g;
if (normsqA < freeFallGravitySquared) {
@@ -1191,10 +1195,10 @@
final float Ex = geomagnetic[0];
final float Ey = geomagnetic[1];
final float Ez = geomagnetic[2];
- float Hx = Ey*Az - Ez*Ay;
- float Hy = Ez*Ax - Ex*Az;
- float Hz = Ex*Ay - Ey*Ax;
- final float normH = (float)Math.sqrt(Hx*Hx + Hy*Hy + Hz*Hz);
+ float Hx = Ey * Az - Ez * Ay;
+ float Hy = Ez * Ax - Ex * Az;
+ float Hz = Ex * Ay - Ey * Ax;
+ final float normH = (float) Math.sqrt(Hx * Hx + Hy * Hy + Hz * Hz);
if (normH < 0.1f) {
// device is close to free fall (or in space?), or close to
@@ -1205,13 +1209,13 @@
Hx *= invH;
Hy *= invH;
Hz *= invH;
- final float invA = 1.0f / (float)Math.sqrt(Ax*Ax + Ay*Ay + Az*Az);
+ final float invA = 1.0f / (float) Math.sqrt(Ax * Ax + Ay * Ay + Az * Az);
Ax *= invA;
Ay *= invA;
Az *= invA;
- final float Mx = Ay*Hz - Az*Hy;
- final float My = Az*Hx - Ax*Hz;
- final float Mz = Ax*Hy - Ay*Hx;
+ final float Mx = Ay * Hz - Az * Hy;
+ final float My = Az * Hx - Ax * Hz;
+ final float Mz = Ax * Hy - Ay * Hx;
if (R != null) {
if (R.length == 9) {
R[0] = Hx; R[1] = Hy; R[2] = Hz;
@@ -1228,17 +1232,17 @@
// compute the inclination matrix by projecting the geomagnetic
// vector onto the Z (gravity) and X (horizontal component
// of geomagnetic vector) axes.
- final float invE = 1.0f / (float)Math.sqrt(Ex*Ex + Ey*Ey + Ez*Ez);
- final float c = (Ex*Mx + Ey*My + Ez*Mz) * invE;
- final float s = (Ex*Ax + Ey*Ay + Ez*Az) * invE;
+ final float invE = 1.0f / (float) Math.sqrt(Ex * Ex + Ey * Ey + Ez * Ez);
+ final float c = (Ex * Mx + Ey * My + Ez * Mz) * invE;
+ final float s = (Ex * Ax + Ey * Ay + Ez * Az) * invE;
if (I.length == 9) {
I[0] = 1; I[1] = 0; I[2] = 0;
I[3] = 0; I[4] = c; I[5] = s;
- I[6] = 0; I[7] =-s; I[8] = c;
+ I[6] = 0; I[7] = -s; I[8] = c;
} else if (I.length == 16) {
I[0] = 1; I[1] = 0; I[2] = 0;
I[4] = 0; I[5] = c; I[6] = s;
- I[8] = 0; I[9] =-s; I[10]= c;
+ I[8] = 0; I[9] = -s; I[10] = c;
I[3] = I[7] = I[11] = I[12] = I[13] = I[14] = 0;
I[15] = 1;
}
@@ -1262,9 +1266,9 @@
*/
public static float getInclination(float[] I) {
if (I.length == 9) {
- return (float)Math.atan2(I[5], I[4]);
+ return (float) Math.atan2(I[5], I[4]);
} else {
- return (float)Math.atan2(I[6], I[5]);
+ return (float) Math.atan2(I[6], I[5]);
}
}
@@ -1343,17 +1347,16 @@
* @see #getRotationMatrix(float[], float[], float[], float[])
*/
- public static boolean remapCoordinateSystem(float[] inR, int X, int Y,
- float[] outR)
- {
+ public static boolean remapCoordinateSystem(float[] inR, int X, int Y, float[] outR) {
if (inR == outR) {
- final float[] temp = mTempMatrix;
- synchronized(temp) {
+ final float[] temp = sTempMatrix;
+ synchronized (temp) {
// we don't expect to have a lot of contention
if (remapCoordinateSystemImpl(inR, X, Y, temp)) {
final int size = outR.length;
- for (int i=0 ; i<size ; i++)
+ for (int i = 0; i < size; i++) {
outR[i] = temp[i];
+ }
return true;
}
}
@@ -1361,9 +1364,7 @@
return remapCoordinateSystemImpl(inR, X, Y, outR);
}
- private static boolean remapCoordinateSystemImpl(float[] inR, int X, int Y,
- float[] outR)
- {
+ private static boolean remapCoordinateSystemImpl(float[] inR, int X, int Y, float[] outR) {
/*
* X and Y define a rotation matrix 'r':
*
@@ -1376,14 +1377,18 @@
*/
final int length = outR.length;
- if (inR.length != length)
+ if (inR.length != length) {
return false; // invalid parameter
- if ((X & 0x7C)!=0 || (Y & 0x7C)!=0)
+ }
+ if ((X & 0x7C) != 0 || (Y & 0x7C) != 0) {
return false; // invalid parameter
- if (((X & 0x3)==0) || ((Y & 0x3)==0))
+ }
+ if (((X & 0x3) == 0) || ((Y & 0x3) == 0)) {
return false; // no axis specified
- if ((X & 0x3) == (Y & 0x3))
+ }
+ if ((X & 0x3) == (Y & 0x3)) {
return false; // same axis specified
+ }
// Z is "the other" axis, its sign is either +/- sign(X)*sign(Y)
// this can be calculated by exclusive-or'ing X and Y; except for
@@ -1391,28 +1396,29 @@
int Z = X ^ Y;
// extract the axis (remove the sign), offset in the range 0 to 2.
- final int x = (X & 0x3)-1;
- final int y = (Y & 0x3)-1;
- final int z = (Z & 0x3)-1;
+ final int x = (X & 0x3) - 1;
+ final int y = (Y & 0x3) - 1;
+ final int z = (Z & 0x3) - 1;
// compute the sign of Z (whether it needs to be inverted)
- final int axis_y = (z+1)%3;
- final int axis_z = (z+2)%3;
- if (((x^axis_y)|(y^axis_z)) != 0)
+ final int axis_y = (z + 1) % 3;
+ final int axis_z = (z + 2) % 3;
+ if (((x ^ axis_y) | (y ^ axis_z)) != 0) {
Z ^= 0x80;
+ }
- final boolean sx = (X>=0x80);
- final boolean sy = (Y>=0x80);
- final boolean sz = (Z>=0x80);
+ final boolean sx = (X >= 0x80);
+ final boolean sy = (Y >= 0x80);
+ final boolean sz = (Z >= 0x80);
// Perform R * r, in avoiding actual muls and adds.
- final int rowLength = ((length==16)?4:3);
- for (int j=0 ; j<3 ; j++) {
- final int offset = j*rowLength;
- for (int i=0 ; i<3 ; i++) {
- if (x==i) outR[offset+i] = sx ? -inR[offset+0] : inR[offset+0];
- if (y==i) outR[offset+i] = sy ? -inR[offset+1] : inR[offset+1];
- if (z==i) outR[offset+i] = sz ? -inR[offset+2] : inR[offset+2];
+ final int rowLength = ((length == 16) ? 4 : 3);
+ for (int j = 0; j < 3; j++) {
+ final int offset = j * rowLength;
+ for (int i = 0; i < 3; i++) {
+ if (x == i) outR[offset + i] = sx ? -inR[offset + 0] : inR[offset + 0];
+ if (y == i) outR[offset + i] = sy ? -inR[offset + 1] : inR[offset + 1];
+ if (z == i) outR[offset + i] = sz ? -inR[offset + 2] : inR[offset + 2];
}
}
if (length == 16) {
@@ -1466,7 +1472,7 @@
* @see #getRotationMatrix(float[], float[], float[], float[])
* @see GeomagneticField
*/
- public static float[] getOrientation(float[] R, float values[]) {
+ public static float[] getOrientation(float[] R, float[] values) {
/*
* 4x4 (length=16) case:
* / R[ 0] R[ 1] R[ 2] 0 \
@@ -1481,13 +1487,13 @@
*
*/
if (R.length == 9) {
- values[0] = (float)Math.atan2(R[1], R[4]);
- values[1] = (float)Math.asin(-R[7]);
- values[2] = (float)Math.atan2(-R[6], R[8]);
+ values[0] = (float) Math.atan2(R[1], R[4]);
+ values[1] = (float) Math.asin(-R[7]);
+ values[2] = (float) Math.atan2(-R[6], R[8]);
} else {
- values[0] = (float)Math.atan2(R[1], R[5]);
- values[1] = (float)Math.asin(-R[9]);
- values[2] = (float)Math.atan2(-R[8], R[10]);
+ values[0] = (float) Math.atan2(R[1], R[5]);
+ values[1] = (float) Math.asin(-R[9]);
+ values[2] = (float) Math.atan2(-R[8], R[10]);
}
return values;
@@ -1524,7 +1530,7 @@
*/
public static float getAltitude(float p0, float p) {
final float coef = 1.0f / 5.255f;
- return 44330.0f * (1.0f - (float)Math.pow(p/p0, coef));
+ return 44330.0f * (1.0f - (float) Math.pow(p / p0, coef));
}
/** Helper function to compute the angle change between two rotation matrices.
@@ -1557,12 +1563,13 @@
* (in radians) is stored
*/
- public static void getAngleChange( float[] angleChange, float[] R, float[] prevR) {
- float rd1=0,rd4=0, rd6=0,rd7=0, rd8=0;
- float ri0=0,ri1=0,ri2=0,ri3=0,ri4=0,ri5=0,ri6=0,ri7=0,ri8=0;
- float pri0=0, pri1=0, pri2=0, pri3=0, pri4=0, pri5=0, pri6=0, pri7=0, pri8=0;
+ public static void getAngleChange(float[] angleChange, float[] R, float[] prevR) {
+ float rd1 = 0, rd4 = 0, rd6 = 0, rd7 = 0, rd8 = 0;
+ float ri0 = 0, ri1 = 0, ri2 = 0, ri3 = 0, ri4 = 0, ri5 = 0, ri6 = 0, ri7 = 0, ri8 = 0;
+ float pri0 = 0, pri1 = 0, pri2 = 0, pri3 = 0, pri4 = 0;
+ float pri5 = 0, pri6 = 0, pri7 = 0, pri8 = 0;
- if(R.length == 9) {
+ if (R.length == 9) {
ri0 = R[0];
ri1 = R[1];
ri2 = R[2];
@@ -1572,7 +1579,7 @@
ri6 = R[6];
ri7 = R[7];
ri8 = R[8];
- } else if(R.length == 16) {
+ } else if (R.length == 16) {
ri0 = R[0];
ri1 = R[1];
ri2 = R[2];
@@ -1584,7 +1591,7 @@
ri8 = R[10];
}
- if(prevR.length == 9) {
+ if (prevR.length == 9) {
pri0 = prevR[0];
pri1 = prevR[1];
pri2 = prevR[2];
@@ -1594,7 +1601,7 @@
pri6 = prevR[6];
pri7 = prevR[7];
pri8 = prevR[8];
- } else if(prevR.length == 16) {
+ } else if (prevR.length == 16) {
pri0 = prevR[0];
pri1 = prevR[1];
pri2 = prevR[2];
@@ -1615,9 +1622,9 @@
rd7 = pri2 * ri1 + pri5 * ri4 + pri8 * ri7; //rd[2][1]
rd8 = pri2 * ri2 + pri5 * ri5 + pri8 * ri8; //rd[2][2]
- angleChange[0] = (float)Math.atan2(rd1, rd4);
- angleChange[1] = (float)Math.asin(-rd7);
- angleChange[2] = (float)Math.atan2(-rd6, rd8);
+ angleChange[0] = (float) Math.atan2(rd1, rd4);
+ angleChange[1] = (float) Math.asin(-rd7);
+ angleChange[2] = (float) Math.atan2(-rd6, rd8);
}
@@ -1650,8 +1657,8 @@
if (rotationVector.length >= 4) {
q0 = rotationVector[3];
} else {
- q0 = 1 - q1*q1 - q2*q2 - q3*q3;
- q0 = (q0 > 0) ? (float)Math.sqrt(q0) : 0;
+ q0 = 1 - q1 * q1 - q2 * q2 - q3 * q3;
+ q0 = (q0 > 0) ? (float) Math.sqrt(q0) : 0;
}
float sq_q1 = 2 * q1 * q1;
@@ -1664,7 +1671,7 @@
float q2_q3 = 2 * q2 * q3;
float q1_q0 = 2 * q1 * q0;
- if(R.length == 9) {
+ if (R.length == 9) {
R[0] = 1 - sq_q2 - sq_q3;
R[1] = q1_q2 - q3_q0;
R[2] = q1_q3 + q2_q0;
@@ -1707,8 +1714,8 @@
if (rv.length >= 4) {
Q[0] = rv[3];
} else {
- Q[0] = 1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2];
- Q[0] = (Q[0] > 0) ? (float)Math.sqrt(Q[0]) : 0;
+ Q[0] = 1 - rv[0] * rv[0] - rv[1] * rv[1] - rv[2] * rv[2];
+ Q[0] = (Q[0] > 0) ? (float) Math.sqrt(Q[0]) : 0;
}
Q[1] = rv[0];
Q[2] = rv[1];
@@ -1800,7 +1807,7 @@
*/
@SystemApi
public boolean initDataInjection(boolean enable) {
- return initDataInjectionImpl(enable);
+ return initDataInjectionImpl(enable);
}
/**
@@ -1846,9 +1853,9 @@
}
int expectedNumValues = Sensor.getMaxLengthValuesArray(sensor, Build.VERSION_CODES.M);
if (values.length != expectedNumValues) {
- throw new IllegalArgumentException ("Wrong number of values for sensor " +
- sensor.getName() + " actual=" + values.length + " expected=" +
- expectedNumValues);
+ throw new IllegalArgumentException("Wrong number of values for sensor "
+ + sensor.getName() + " actual=" + values.length + " expected="
+ + expectedNumValues);
}
if (accuracy < SENSOR_STATUS_NO_CONTACT || accuracy > SENSOR_STATUS_ACCURACY_HIGH) {
throw new IllegalArgumentException("Invalid sensor accuracy");
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 607788d..1174cb6 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -28,10 +28,11 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
-import dalvik.system.CloseGuard;
import com.android.internal.annotations.GuardedBy;
+import dalvik.system.CloseGuard;
+
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.ref.WeakReference;
@@ -40,7 +41,6 @@
import java.util.List;
import java.util.Map;
-
/**
* Sensor manager implementation that communicates with the built-in
* system sensors.
@@ -101,7 +101,7 @@
/** {@hide} */
public SystemSensorManager(Context context, Looper mainLooper) {
- synchronized(sLock) {
+ synchronized (sLock) {
if (!sNativeClassInited) {
sNativeClassInited = true;
nativeClassInit();
@@ -114,7 +114,7 @@
mNativeInstance = nativeCreate(context.getOpPackageName());
// initialize the sensor list
- for (int index = 0;;++index) {
+ for (int index = 0;; ++index) {
Sensor sensor = new Sensor();
if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break;
mFullSensorsList.add(sensor);
@@ -157,9 +157,9 @@
return false;
}
if (mSensorListeners.size() >= MAX_LISTENER_COUNT) {
- throw new IllegalStateException("register failed, " +
- "the sensor listeners size has exceeded the maximum limit " +
- MAX_LISTENER_COUNT);
+ throw new IllegalStateException("register failed, "
+ + "the sensor listeners size has exceeded the maximum limit "
+ + MAX_LISTENER_COUNT);
}
// Invariants to preserve:
@@ -170,9 +170,10 @@
SensorEventQueue queue = mSensorListeners.get(listener);
if (queue == null) {
Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
- final String fullClassName = listener.getClass().getEnclosingClass() != null ?
- listener.getClass().getEnclosingClass().getName() :
- listener.getClass().getName();
+ final String fullClassName =
+ listener.getClass().getEnclosingClass() != null
+ ? listener.getClass().getEnclosingClass().getName()
+ : listener.getClass().getName();
queue = new SensorEventQueue(listener, looper, this, fullClassName);
if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) {
queue.dispose();
@@ -221,17 +222,18 @@
if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false;
if (mTriggerListeners.size() >= MAX_LISTENER_COUNT) {
- throw new IllegalStateException("request failed, " +
- "the trigger listeners size has exceeded the maximum limit " +
- MAX_LISTENER_COUNT);
+ throw new IllegalStateException("request failed, "
+ + "the trigger listeners size has exceeded the maximum limit "
+ + MAX_LISTENER_COUNT);
}
synchronized (mTriggerListeners) {
TriggerEventQueue queue = mTriggerListeners.get(listener);
if (queue == null) {
- final String fullClassName = listener.getClass().getEnclosingClass() != null ?
- listener.getClass().getEnclosingClass().getName() :
- listener.getClass().getName();
+ final String fullClassName =
+ listener.getClass().getEnclosingClass() != null
+ ? listener.getClass().getEnclosingClass().getName()
+ : listener.getClass().getName();
queue = new TriggerEventQueue(listener, mMainLooper, this, fullClassName);
if (!queue.addSensor(sensor, 0, 0)) {
queue.dispose();
@@ -336,27 +338,27 @@
mHandleToSensor.remove(sensor.getHandle());
if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
- synchronized(mTriggerListeners) {
+ synchronized (mTriggerListeners) {
HashMap<TriggerEventListener, TriggerEventQueue> triggerListeners =
- new HashMap<TriggerEventListener, TriggerEventQueue>(mTriggerListeners);
+ new HashMap<TriggerEventListener, TriggerEventQueue>(mTriggerListeners);
- for (TriggerEventListener l: triggerListeners.keySet()) {
- if (DEBUG_DYNAMIC_SENSOR){
- Log.i(TAG, "removed trigger listener" + l.toString() +
- " due to sensor disconnection");
+ for (TriggerEventListener l : triggerListeners.keySet()) {
+ if (DEBUG_DYNAMIC_SENSOR) {
+ Log.i(TAG, "removed trigger listener" + l.toString()
+ + " due to sensor disconnection");
}
cancelTriggerSensorImpl(l, sensor, true);
}
}
} else {
- synchronized(mSensorListeners) {
+ synchronized (mSensorListeners) {
HashMap<SensorEventListener, SensorEventQueue> sensorListeners =
- new HashMap<SensorEventListener, SensorEventQueue>(mSensorListeners);
+ new HashMap<SensorEventListener, SensorEventQueue>(mSensorListeners);
for (SensorEventListener l: sensorListeners.keySet()) {
- if (DEBUG_DYNAMIC_SENSOR){
- Log.i(TAG, "removed event listener" + l.toString() +
- " due to sensor disconnection");
+ if (DEBUG_DYNAMIC_SENSOR) {
+ Log.i(TAG, "removed event listener" + l.toString()
+ + " due to sensor disconnection");
}
unregisterListenerImpl(l, sensor);
}
@@ -365,7 +367,7 @@
}
private void updateDynamicSensorList() {
- synchronized(mFullDynamicSensorsList) {
+ synchronized (mFullDynamicSensorsList) {
if (mDynamicSensorListDirty) {
List<Sensor> list = new ArrayList<>();
nativeGetDynamicSensors(mNativeInstance, list);
@@ -488,15 +490,15 @@
int i = 0, j = 0;
while (true) {
- if (j < oldList.size() && ( i >= newList.size() ||
- newList.get(i).getHandle() > oldList.get(j).getHandle()) ) {
+ if (j < oldList.size() && (i >= newList.size()
+ || newList.get(i).getHandle() > oldList.get(j).getHandle())) {
changed = true;
if (removed != null) {
removed.add(oldList.get(j));
}
++j;
- } else if (i < newList.size() && ( j >= oldList.size() ||
- newList.get(i).getHandle() < oldList.get(j).getHandle())) {
+ } else if (i < newList.size() && (j >= oldList.size()
+ || newList.get(i).getHandle() < oldList.get(j).getHandle())) {
changed = true;
if (added != null) {
added.add(newList.get(i));
@@ -505,8 +507,8 @@
updated.add(newList.get(i));
}
++i;
- } else if (i < newList.size() && j < oldList.size() &&
- newList.get(i).getHandle() == oldList.get(j).getHandle()) {
+ } else if (i < newList.size() && j < oldList.size()
+ && newList.get(i).getHandle() == oldList.get(j).getHandle()) {
if (updated != null) {
updated.add(oldList.get(j));
}
@@ -623,7 +625,7 @@
* associated with any listener and there is one InjectEventQueue associated with a
* SensorManager instance.
*/
- private static abstract class BaseEventQueue {
+ private abstract static class BaseEventQueue {
private static native long nativeInitBaseEventQueue(long nativeManager,
WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ,
String packageName, int mode, String opPackageName);
@@ -633,9 +635,9 @@
private static native void nativeDestroySensorEventQueue(long eventQ);
private static native int nativeFlushSensor(long eventQ);
private static native int nativeInjectSensorData(long eventQ, int handle,
- float[] values,int accuracy, long timestamp);
+ float[] values, int accuracy, long timestamp);
- private long nSensorEventQueue;
+ private long mNativeSensorEventQueue;
private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
private final CloseGuard mCloseGuard = CloseGuard.get();
@@ -646,7 +648,7 @@
BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) {
if (packageName == null) packageName = "";
- nSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance,
+ mNativeSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance,
new WeakReference<>(this), looper.getQueue(),
packageName, mode, manager.mContext.getOpPackageName());
mCloseGuard.open("dispose");
@@ -668,17 +670,17 @@
addSensorEvent(sensor);
if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) {
// Try continuous mode if batching fails.
- if (maxBatchReportLatencyUs == 0 ||
- maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) {
- removeSensor(sensor, false);
- return false;
+ if (maxBatchReportLatencyUs == 0
+ || maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) {
+ removeSensor(sensor, false);
+ return false;
}
}
return true;
}
public boolean removeAllSensors() {
- for (int i=0 ; i<mActiveSensors.size(); i++) {
+ for (int i = 0; i < mActiveSensors.size(); i++) {
if (mActiveSensors.valueAt(i) == true) {
int handle = mActiveSensors.keyAt(i);
Sensor sensor = mManager.mHandleToSensor.get(handle);
@@ -706,8 +708,8 @@
}
public int flush() {
- if (nSensorEventQueue == 0) throw new NullPointerException();
- return nativeFlushSensor(nSensorEventQueue);
+ if (mNativeSensorEventQueue == 0) throw new NullPointerException();
+ return nativeFlushSensor(mNativeSensorEventQueue);
}
public boolean hasSensors() {
@@ -731,29 +733,30 @@
}
mCloseGuard.close();
}
- if (nSensorEventQueue != 0) {
- nativeDestroySensorEventQueue(nSensorEventQueue);
- nSensorEventQueue = 0;
+ if (mNativeSensorEventQueue != 0) {
+ nativeDestroySensorEventQueue(mNativeSensorEventQueue);
+ mNativeSensorEventQueue = 0;
}
}
private int enableSensor(
Sensor sensor, int rateUs, int maxBatchReportLatencyUs) {
- if (nSensorEventQueue == 0) throw new NullPointerException();
+ if (mNativeSensorEventQueue == 0) throw new NullPointerException();
if (sensor == null) throw new NullPointerException();
- return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs,
+ return nativeEnableSensor(mNativeSensorEventQueue, sensor.getHandle(), rateUs,
maxBatchReportLatencyUs);
}
protected int injectSensorDataBase(int handle, float[] values, int accuracy,
long timestamp) {
- return nativeInjectSensorData(nSensorEventQueue, handle, values, accuracy, timestamp);
+ return nativeInjectSensorData(
+ mNativeSensorEventQueue, handle, values, accuracy, timestamp);
}
private int disableSensor(Sensor sensor) {
- if (nSensorEventQueue == 0) throw new NullPointerException();
+ if (mNativeSensorEventQueue == 0) throw new NullPointerException();
if (sensor == null) throw new NullPointerException();
- return nativeDisableSensor(nSensorEventQueue, sensor.getHandle());
+ return nativeDisableSensor(mNativeSensorEventQueue, sensor.getHandle());
}
protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy,
long timestamp);
@@ -840,7 +843,7 @@
// sensor disconnected
return;
}
- ((SensorEventListener2)mListener).onFlushCompleted(sensor);
+ ((SensorEventListener2) mListener).onFlushCompleted(sensor);
}
return;
}
@@ -858,7 +861,7 @@
}
SensorAdditionalInfo info =
new SensorAdditionalInfo(sensor, type, serial, intValues, floatValues);
- ((SensorEventCallback)mListener).onSensorAdditionalInfo(info);
+ ((SensorEventCallback) mListener).onSensorAdditionalInfo(info);
}
}
}
@@ -930,8 +933,8 @@
super(looper, manager, OPERATING_MODE_DATA_INJECTION, packageName);
}
- int injectSensorData(int handle, float[] values,int accuracy, long timestamp) {
- return injectSensorDataBase(handle, values, accuracy, timestamp);
+ int injectSensorData(int handle, float[] values, int accuracy, long timestamp) {
+ return injectSensorDataBase(handle, values, accuracy, timestamp);
}
@SuppressWarnings("unused")
@@ -959,6 +962,7 @@
int handle = -1;
if (parameter.sensor != null) handle = parameter.sensor.getHandle();
return nativeSetOperationParameter(
- mNativeInstance, handle, parameter.type, parameter.floatValues, parameter.intValues) == 0;
+ mNativeInstance, handle,
+ parameter.type, parameter.floatValues, parameter.intValues) == 0;
}
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 744ee8e..d7ecc81 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2078,16 +2078,30 @@
* {@code ro.tether.denied} system property, Settings.TETHER_SUPPORTED or
* due to device configuration.
*
+ * <p>If this app does not have permission to use this API, it will always
+ * return false rather than throw an exception.</p>
+ *
+ * <p>If the device has a hotspot provisioning app, the caller is required to hold the
+ * {@link android.Manifest.permission.TETHER_PRIVILEGED} permission.</p>
+ *
+ * <p>Otherwise, this method requires the caller to hold the ability to modify system
+ * settings as determined by {@link android.provider.Settings.System#canWrite}.</p>
+ *
* @return a boolean - {@code true} indicating Tethering is supported.
*
* {@hide}
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
+ @RequiresPermission(anyOf = {android.Manifest.permission.TETHER_PRIVILEGED,
+ android.Manifest.permission.WRITE_SETTINGS})
public boolean isTetheringSupported() {
+ String pkgName = mContext.getOpPackageName();
try {
- String pkgName = mContext.getOpPackageName();
return mService.isTetheringSupported(pkgName);
+ } catch (SecurityException e) {
+ // This API is not available to this caller, but for backward-compatibility
+ // this will just return false instead of throwing.
+ return false;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index 5ae3400..ead406c 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -19,15 +19,15 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+
import com.android.internal.util.HexDump;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to
* RFC 4301.
- *
- * @hide
*/
public final class IpSecAlgorithm implements Parcelable {
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 2f791e1..d7908c8 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -25,7 +25,9 @@
import android.os.RemoteException;
import android.util.AndroidException;
import android.util.Log;
+
import dalvik.system.CloseGuard;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.DatagramSocket;
@@ -36,7 +38,9 @@
* This class contains methods for managing IPsec sessions, which will perform kernel-space
* encryption and decryption of socket or Network traffic.
*
- * @hide
+ * <p>An IpSecManager may be obtained by calling {@link
+ * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link
+ * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE}
*/
@SystemService(Context.IPSEC_SERVICE)
public final class IpSecManager {
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index cfbac58b..62fd65b 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -26,9 +26,12 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
+
import dalvik.system.CloseGuard;
+
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -43,8 +46,6 @@
*
* <p>An IpSecTransform may either represent a tunnel mode transform that operates on a wide array
* of traffic or may represent a transport mode transform operating on a Socket or Sockets.
- *
- * @hide
*/
public final class IpSecTransform implements AutoCloseable {
private static final String TAG = "IpSecTransform";
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 0df6361..e9e695b 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -23,7 +23,6 @@
import android.util.Slog;
import com.android.internal.util.FastPrintWriter;
-import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
@@ -202,7 +201,7 @@
* then its own pid is returned.
*/
public static final native int getCallingPid();
-
+
/**
* Return the Linux uid assigned to the process that sent you the
* current transaction that is being processed. This uid can be used with
@@ -335,7 +334,7 @@
* it needs to.
*/
public static final native void flushPendingCommands();
-
+
/**
* Add the calling thread to the IPC thread pool. This function does
* not return until the current process is exiting.
@@ -372,7 +371,7 @@
}
}
}
-
+
/**
* Convenience method for associating a specific interface with the Binder.
* After calling, queryLocalInterface() will be implemented for you
@@ -383,7 +382,7 @@
mOwner = owner;
mDescriptor = descriptor;
}
-
+
/**
* Default implementation returns an empty interface name.
*/
@@ -408,7 +407,7 @@
public boolean isBinderAlive() {
return true;
}
-
+
/**
* Use information supplied to attachInterface() to return the
* associated IInterface if it matches the requested
@@ -630,7 +629,7 @@
}
return r;
}
-
+
/**
* Local implementation is a no-op.
*/
@@ -643,7 +642,7 @@
public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags) {
return true;
}
-
+
protected void finalize() throws Throwable {
try {
destroyBinder();
@@ -730,7 +729,15 @@
}
}
+/**
+ * Java proxy for a native IBinder object.
+ * Allocated and constructed by the native javaObjectforIBinder function. Never allocated
+ * directly from Java code.
+ */
final class BinderProxy implements IBinder {
+ // See android_util_Binder.cpp for the native half of this.
+ // TODO: Consider using NativeAllocationRegistry instead of finalization.
+
// Assume the process-wide default value when created
volatile boolean mWarnOnBlocking = Binder.sWarnOnBlocking;
@@ -789,7 +796,7 @@
reply.recycle();
}
}
-
+
public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -826,7 +833,7 @@
BinderProxy() {
mSelf = new WeakReference(this);
}
-
+
@Override
protected void finalize() throws Throwable {
try {
@@ -835,9 +842,9 @@
super.finalize();
}
}
-
+
private native final void destroy();
-
+
private static final void sendDeathNotice(DeathRecipient recipient) {
if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient);
try {
@@ -848,8 +855,20 @@
exc);
}
}
-
+
+ // This WeakReference to "this" is used only by native code to "attach" to the
+ // native IBinder object.
+ // Using WeakGlobalRefs instead currently appears unsafe, in that they can yield a
+ // non-null value after the BinderProxy is enqueued for finalization.
+ // Used only once immediately after construction.
+ // TODO: Consider making the extra native-to-java call to compute this on the fly.
final private WeakReference mSelf;
+
+ // Native pointer to the wrapped native IBinder object. Counted as strong reference.
private long mObject;
+
+ // Native pointer to native DeathRecipientList. Counted as strong reference.
+ // Basically owned by the JavaProxy object. Reference counted only because DeathRecipients
+ // hold a weak reference that can be temporarily promoted.
private long mOrgue;
}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 0562716..a474b47 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -104,11 +104,6 @@
void setIPv6AddrGenMode(String iface, int mode);
/**
- * Enables or enables IPv6 ND offload.
- */
- void setInterfaceIpv6NdOffload(String iface, boolean enable);
-
- /**
* Add the specified route to the interface.
*/
void addRoute(int netId, in RouteInfo route);
diff --git a/core/java/android/os/IServiceManager.java b/core/java/android/os/IServiceManager.java
index 7b11c28..87c65ec 100644
--- a/core/java/android/os/IServiceManager.java
+++ b/core/java/android/os/IServiceManager.java
@@ -18,12 +18,12 @@
/**
* Basic interface for finding and publishing system services.
- *
+ *
* An implementation of this interface is usually published as the
* global context object, which can be retrieved via
* BinderNative.getContextObject(). An easy way to retrieve this
* is with the static method BnServiceManager.getDefault().
- *
+ *
* @hide
*/
public interface IServiceManager extends IInterface
@@ -33,33 +33,33 @@
* service manager. Blocks for a few seconds waiting for it to be
* published if it does not already exist.
*/
- public IBinder getService(String name) throws RemoteException;
-
+ IBinder getService(String name) throws RemoteException;
+
/**
* Retrieve an existing service called @a name from the
* service manager. Non-blocking.
*/
- public IBinder checkService(String name) throws RemoteException;
+ IBinder checkService(String name) throws RemoteException;
/**
* Place a new @a service called @a name into the service
* manager.
*/
- public void addService(String name, IBinder service, boolean allowIsolated)
+ void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)
throws RemoteException;
/**
* Return a list of all currently running services.
*/
- public String[] listServices() throws RemoteException;
+ String[] listServices(int dumpPriority) throws RemoteException;
/**
* Assign a permission controller to the service manager. After set, this
* interface is checked before any services are added.
*/
- public void setPermissionController(IPermissionController controller)
+ void setPermissionController(IPermissionController controller)
throws RemoteException;
-
+
static final String descriptor = "android.os.IServiceManager";
int GET_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
@@ -68,4 +68,13 @@
int LIST_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
int CHECK_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;
int SET_PERMISSION_CONTROLLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+5;
+
+ /*
+ * Must update values in IServiceManager.h
+ */
+ int DUMP_PRIORITY_CRITICAL = 1 << 0;
+ int DUMP_PRIORITY_HIGH = 1 << 1;
+ int DUMP_PRIORITY_NORMAL = 1 << 2;
+ int DUMP_PRIORITY_ALL = DUMP_PRIORITY_CRITICAL | DUMP_PRIORITY_HIGH
+ | DUMP_PRIORITY_NORMAL;
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 960c9f5..3726f47 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -443,6 +443,20 @@
public static final String SHUTDOWN_USER_REQUESTED = "userrequested";
/**
+ * The value to pass as the 'reason' argument to android_reboot() when battery temperature
+ * is too high.
+ * @hide
+ */
+ public static final String SHUTDOWN_BATTERY_THERMAL_STATE = "thermal,battery";
+
+ /**
+ * The value to pass as the 'reason' argument to android_reboot() when device is running
+ * critically low on battery.
+ * @hide
+ */
+ public static final String SHUTDOWN_LOW_BATTERY = "battery";
+
+ /**
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
@@ -451,7 +465,9 @@
SHUTDOWN_REASON_SHUTDOWN,
SHUTDOWN_REASON_REBOOT,
SHUTDOWN_REASON_USER_REQUESTED,
- SHUTDOWN_REASON_THERMAL_SHUTDOWN
+ SHUTDOWN_REASON_THERMAL_SHUTDOWN,
+ SHUTDOWN_REASON_LOW_BATTERY,
+ SHUTDOWN_REASON_BATTERY_THERMAL
})
public @interface ShutdownReason {}
@@ -485,6 +501,18 @@
*/
public static final int SHUTDOWN_REASON_THERMAL_SHUTDOWN = 4;
+ /**
+ * constant for shutdown reason being low battery.
+ * @hide
+ */
+ public static final int SHUTDOWN_REASON_LOW_BATTERY = 5;
+
+ /**
+ * constant for shutdown reason being critical battery thermal state.
+ * @hide
+ */
+ public static final int SHUTDOWN_REASON_BATTERY_THERMAL = 6;
+
final Context mContext;
final IPowerManager mService;
final Handler mHandler;
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index e11494d..f41848f 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -26,7 +26,6 @@
/** @hide */
public final class ServiceManager {
private static final String TAG = "ServiceManager";
-
private static IServiceManager sServiceManager;
private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();
@@ -43,7 +42,7 @@
/**
* Returns a reference to a service with the given name.
- *
+ *
* @param name the name of the service to get
* @return a reference to the service, or <code>null</code> if the service doesn't exist
*/
@@ -79,35 +78,46 @@
/**
* Place a new @a service called @a name into the service
* manager.
- *
+ *
* @param name the name of the new service
* @param service the service object
*/
public static void addService(String name, IBinder service) {
- try {
- getIServiceManager().addService(name, service, false);
- } catch (RemoteException e) {
- Log.e(TAG, "error in addService", e);
- }
+ addService(name, service, false, IServiceManager.DUMP_PRIORITY_NORMAL);
}
/**
* Place a new @a service called @a name into the service
* manager.
- *
+ *
* @param name the name of the new service
* @param service the service object
* @param allowIsolated set to true to allow isolated sandboxed processes
* to access this service
*/
public static void addService(String name, IBinder service, boolean allowIsolated) {
+ addService(name, service, allowIsolated, IServiceManager.DUMP_PRIORITY_NORMAL);
+ }
+
+ /**
+ * Place a new @a service called @a name into the service
+ * manager.
+ *
+ * @param name the name of the new service
+ * @param service the service object
+ * @param allowIsolated set to true to allow isolated sandboxed processes
+ * @param dumpPriority supported dump priority levels as a bitmask
+ * to access this service
+ */
+ public static void addService(String name, IBinder service, boolean allowIsolated,
+ int dumpPriority) {
try {
- getIServiceManager().addService(name, service, allowIsolated);
+ getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
-
+
/**
* Retrieve an existing service called @a name from the
* service manager. Non-blocking.
@@ -133,7 +143,7 @@
*/
public static String[] listServices() {
try {
- return getIServiceManager().listServices();
+ return getIServiceManager().listServices(IServiceManager.DUMP_PRIORITY_ALL);
} catch (RemoteException e) {
Log.e(TAG, "error in listServices", e);
return null;
@@ -144,7 +154,7 @@
* This is only intended to be called when the process is first being brought
* up and bound by the activity manager. There is only one thread in the process
* at that time, so no locking is done.
- *
+ *
* @param cache the cache of service references
* @hide
*/
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index be24426..589b8c4 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -40,63 +40,65 @@
if (in != null) {
return in;
}
-
+
return new ServiceManagerProxy(obj);
}
-
+
public ServiceManagerNative()
{
attachInterface(this, descriptor);
}
-
+
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
{
try {
switch (code) {
- case IServiceManager.GET_SERVICE_TRANSACTION: {
- data.enforceInterface(IServiceManager.descriptor);
- String name = data.readString();
- IBinder service = getService(name);
- reply.writeStrongBinder(service);
- return true;
- }
-
- case IServiceManager.CHECK_SERVICE_TRANSACTION: {
- data.enforceInterface(IServiceManager.descriptor);
- String name = data.readString();
- IBinder service = checkService(name);
- reply.writeStrongBinder(service);
- return true;
- }
-
- case IServiceManager.ADD_SERVICE_TRANSACTION: {
- data.enforceInterface(IServiceManager.descriptor);
- String name = data.readString();
- IBinder service = data.readStrongBinder();
- boolean allowIsolated = data.readInt() != 0;
- addService(name, service, allowIsolated);
- return true;
- }
-
- case IServiceManager.LIST_SERVICES_TRANSACTION: {
- data.enforceInterface(IServiceManager.descriptor);
- String[] list = listServices();
- reply.writeStringArray(list);
- return true;
- }
-
- case IServiceManager.SET_PERMISSION_CONTROLLER_TRANSACTION: {
- data.enforceInterface(IServiceManager.descriptor);
- IPermissionController controller
- = IPermissionController.Stub.asInterface(
- data.readStrongBinder());
- setPermissionController(controller);
- return true;
- }
+ case IServiceManager.GET_SERVICE_TRANSACTION: {
+ data.enforceInterface(IServiceManager.descriptor);
+ String name = data.readString();
+ IBinder service = getService(name);
+ reply.writeStrongBinder(service);
+ return true;
+ }
+
+ case IServiceManager.CHECK_SERVICE_TRANSACTION: {
+ data.enforceInterface(IServiceManager.descriptor);
+ String name = data.readString();
+ IBinder service = checkService(name);
+ reply.writeStrongBinder(service);
+ return true;
+ }
+
+ case IServiceManager.ADD_SERVICE_TRANSACTION: {
+ data.enforceInterface(IServiceManager.descriptor);
+ String name = data.readString();
+ IBinder service = data.readStrongBinder();
+ boolean allowIsolated = data.readInt() != 0;
+ int dumpPriority = data.readInt();
+ addService(name, service, allowIsolated, dumpPriority);
+ return true;
+ }
+
+ case IServiceManager.LIST_SERVICES_TRANSACTION: {
+ data.enforceInterface(IServiceManager.descriptor);
+ int dumpPriority = data.readInt();
+ String[] list = listServices(dumpPriority);
+ reply.writeStringArray(list);
+ return true;
+ }
+
+ case IServiceManager.SET_PERMISSION_CONTROLLER_TRANSACTION: {
+ data.enforceInterface(IServiceManager.descriptor);
+ IPermissionController controller =
+ IPermissionController.Stub.asInterface(
+ data.readStrongBinder());
+ setPermissionController(controller);
+ return true;
+ }
}
} catch (RemoteException e) {
}
-
+
return false;
}
@@ -110,11 +112,11 @@
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
}
-
+
public IBinder asBinder() {
return mRemote;
}
-
+
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -139,7 +141,7 @@
return binder;
}
- public void addService(String name, IBinder service, boolean allowIsolated)
+ public void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -147,12 +149,13 @@
data.writeString(name);
data.writeStrongBinder(service);
data.writeInt(allowIsolated ? 1 : 0);
+ data.writeInt(dumpPriority);
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
}
-
- public String[] listServices() throws RemoteException {
+
+ public String[] listServices(int dumpPriority) throws RemoteException {
ArrayList<String> services = new ArrayList<String>();
int n = 0;
while (true) {
@@ -160,6 +163,7 @@
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeInt(n);
+ data.writeInt(dumpPriority);
n++;
try {
boolean res = mRemote.transact(LIST_SERVICES_TRANSACTION, data, reply, 0);
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 50855bb..e865ed1 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -45,103 +45,11 @@
*/
void unregisterListener(IStorageEventListener listener) = 1;
/**
- * Returns true if a USB mass storage host is connected
- */
- boolean isUsbMassStorageConnected() = 2;
- /**
- * Enables / disables USB mass storage. The caller should check actual
- * status of enabling/disabling USB mass storage via StorageEventListener.
- */
- void setUsbMassStorageEnabled(boolean enable) = 3;
- /**
- * Returns true if a USB mass storage host is enabled (media is shared)
- */
- boolean isUsbMassStorageEnabled() = 4;
- /**
- * Mount external storage at given mount point. Returns an int consistent
- * with StorageResultCode
- */
- int mountVolume(in String mountPoint) = 5;
- /**
- * Safely unmount external storage at given mount point. The unmount is an
- * asynchronous operation. Applications should register StorageEventListener
- * for storage related status changes.
- * @param mountPoint the mount point
- * @param force whether or not to forcefully unmount it (e.g. even if programs are using this
- * data currently)
- * @param removeEncryption whether or not encryption mapping should be removed from the volume.
- * This value implies {@code force}.
- */
- void unmountVolume(in String mountPoint, boolean force, boolean removeEncryption) = 6;
- /**
- * Format external storage given a mount point. Returns an int consistent
- * with StorageResultCode
- */
- int formatVolume(in String mountPoint) = 7;
- /**
- * Returns an array of pids with open files on the specified path.
- */
- int[] getStorageUsers(in String path) = 8;
- /**
- * Gets the state of a volume via its mountpoint.
- */
- String getVolumeState(in String mountPoint) = 9;
- /*
- * Creates a secure container with the specified parameters. Returns an int
- * consistent with StorageResultCode
- */
- int createSecureContainer(in String id, int sizeMb, in String fstype, in String key,
- int ownerUid, boolean external) = 10;
- /*
- * Finalize a container which has just been created and populated. After
- * finalization, the container is immutable. Returns an int consistent with
- * StorageResultCode
- */
- int finalizeSecureContainer(in String id) = 11;
- /*
- * Destroy a secure container, and free up all resources associated with it.
- * NOTE: Ensure all references are released prior to deleting. Returns an
- * int consistent with StorageResultCode
- */
- int destroySecureContainer(in String id, boolean force) = 12;
- /*
- * Mount a secure container with the specified key and owner UID. Returns an
- * int consistent with StorageResultCode
- */
- int mountSecureContainer(in String id, in String key, int ownerUid, boolean readOnly) = 13;
- /*
- * Unount a secure container. Returns an int consistent with
- * StorageResultCode
- */
- int unmountSecureContainer(in String id, boolean force) = 14;
- /*
- * Returns true if the specified container is mounted
- */
- boolean isSecureContainerMounted(in String id) = 15;
- /*
- * Rename an unmounted secure container. Returns an int consistent with
- * StorageResultCode
- */
- int renameSecureContainer(in String oldId, in String newId) = 16;
- /*
- * Returns the filesystem path of a mounted secure container.
- */
- String getSecureContainerPath(in String id) = 17;
- /**
- * Gets an Array of currently known secure container IDs
- */
- String[] getSecureContainerList() = 18;
- /**
* Shuts down the StorageManagerService and gracefully unmounts all external media.
* Invokes call back once the shutdown is complete.
*/
void shutdown(IStorageShutdownObserver observer) = 19;
/**
- * Call into StorageManagerService by PackageManager to notify that its done
- * processing the media status update request.
- */
- void finishMediaUpdate() = 20;
- /**
* Mounts an Opaque Binary Blob (OBB) with the specified decryption key and
* only allows the calling process's UID access to the contents.
* StorageManagerService will call back to the supplied IObbActionListener to inform
@@ -166,10 +74,6 @@
*/
String getMountedObbPath(in String rawPath) = 24;
/**
- * Returns whether or not the external storage is emulated.
- */
- boolean isExternalStorageEmulated() = 25;
- /**
* Decrypts any encrypted volumes.
*/
int decryptStorage(in String password) = 26;
@@ -186,14 +90,6 @@
*/
StorageVolume[] getVolumeList(int uid, in String packageName, int flags) = 29;
/**
- * Gets the path on the filesystem for the ASEC container itself.
- *
- * @param cid ASEC container ID
- * @return path to filesystem or {@code null} if it's not found
- * @throws RemoteException
- */
- String getSecureContainerFilesystemPath(in String cid) = 30;
- /**
* Determines the encryption state of the volume.
* @return a numerical value. See {@code ENCRYPTION_STATE_*} for possible
* values.
@@ -208,11 +104,6 @@
* may only be called by the system process.
*/
int verifyEncryptionPassword(in String password) = 32;
- /*
- * Fix permissions in a container which has just been created and populated.
- * Returns an int consistent with StorageResultCode
- */
- int fixPermissionsSecureContainer(in String id, int gid, in String filename) = 33;
/**
* Ensure that all directories along given path exist, creating parent
* directories as needed. Validates that given path is absolute and that it
@@ -247,7 +138,6 @@
* @return contents of field
*/
String getField(in String field) = 39;
- int resizeSecureContainer(in String id, int sizeMb, in String key) = 40;
/**
* Report the time of the last maintenance operation such as fstrim.
* @return Timestamp of the last maintenance operation, in the
@@ -260,7 +150,6 @@
* @throws RemoteException
*/
void runMaintenance() = 42;
- void waitForAsecScan() = 43;
DiskInfo[] getDisks() = 44;
VolumeInfo[] getVolumes(int flags) = 45;
VolumeRecord[] getVolumeRecords(int flags) = 46;
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 3e08dcf..045c833 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -305,7 +305,7 @@
* <li>Use the {@link android.app.assist.AssistStructure.ViewNode#getWebDomain()} to get the
* source of the document.
* <li>Get the canonical domain using the
- * <a href="https://publicsuffix.org/>Public Suffix List</a> (see example below).
+ * <a href="https://publicsuffix.org/">Public Suffix List</a> (see example below).
* <li>Use <a href="https://developers.google.com/digital-asset-links/">Digital Asset Links</a>
* to obtain the package name and certificate fingerprint of the package corresponding to
* the canonical domain.
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index ea1100e..ad26f23 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -16,7 +16,12 @@
package android.text;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -24,9 +29,6 @@
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
import java.util.HashMap;
import java.util.Locale;
@@ -37,39 +39,19 @@
* @hide
*/
public class Hyphenator {
- // This class has deliberately simple lifetime management (no finalizer) because in
- // the common case a process will use a very small number of locales.
-
private static String TAG = "Hyphenator";
- // TODO: Confirm that these are the best values. Various sources suggest (1, 1), but
- // that appears too small.
- private static final int INDIC_MIN_PREFIX = 2;
- private static final int INDIC_MIN_SUFFIX = 2;
-
private final static Object sLock = new Object();
@GuardedBy("sLock")
final static HashMap<Locale, Hyphenator> sMap = new HashMap<Locale, Hyphenator>();
- // Reasonable enough values for cases where we have no hyphenation patterns but may be able to
- // do some automatic hyphenation based on characters. These values would be used very rarely.
- private static final int DEFAULT_MIN_PREFIX = 2;
- private static final int DEFAULT_MIN_SUFFIX = 2;
- final static Hyphenator sEmptyHyphenator =
- new Hyphenator(StaticLayout.nLoadHyphenator(
- null, 0, DEFAULT_MIN_PREFIX, DEFAULT_MIN_SUFFIX),
- null);
+ private final long mNativePtr;
+ private final HyphenationData mData;
- final private long mNativePtr;
-
- // We retain a reference to the buffer to keep the memory mapping valid
- @SuppressWarnings("unused")
- final private ByteBuffer mBuffer;
-
- private Hyphenator(long nativePtr, ByteBuffer b) {
+ private Hyphenator(long nativePtr, HyphenationData data) {
mNativePtr = nativePtr;
- mBuffer = b;
+ mData = data;
}
public long getNativePtr() {
@@ -90,8 +72,7 @@
new Locale(locale.getLanguage(), "", variant);
result = sMap.get(languageAndVariantOnlyLocale);
if (result != null) {
- sMap.put(locale, result);
- return result;
+ return putAlias(locale, result);
}
}
@@ -99,8 +80,7 @@
final Locale languageOnlyLocale = new Locale(locale.getLanguage());
result = sMap.get(languageOnlyLocale);
if (result != null) {
- sMap.put(locale, result);
- return result;
+ return putAlias(locale, result);
}
// Fall back to script-only, if available
@@ -112,135 +92,94 @@
.build();
result = sMap.get(scriptOnlyLocale);
if (result != null) {
- sMap.put(locale, result);
- return result;
+ return putAlias(locale, result);
}
}
- sMap.put(locale, sEmptyHyphenator); // To remember we found nothing.
+ return putEmptyAlias(locale);
}
- return sEmptyHyphenator;
}
private static class HyphenationData {
- final String mLanguageTag;
- final int mMinPrefix, mMinSuffix;
+ private static final String SYSTEM_HYPHENATOR_LOCATION = "/system/usr/hyphen-data";
+
+ public final int mMinPrefix, mMinSuffix;
+ public final long mDataAddress;
+
+ // Reasonable enough values for cases where we have no hyphenation patterns but may be able
+ // to do some automatic hyphenation based on characters. These values would be used very
+ // rarely.
+ private static final int DEFAULT_MIN_PREFIX = 2;
+ private static final int DEFAULT_MIN_SUFFIX = 2;
+
+ public static final HyphenationData sEmptyData =
+ new HyphenationData(DEFAULT_MIN_PREFIX, DEFAULT_MIN_SUFFIX);
+
+ // Create empty HyphenationData.
+ private HyphenationData(int minPrefix, int minSuffix) {
+ mMinPrefix = minPrefix;
+ mMinSuffix = minSuffix;
+ mDataAddress = 0;
+ }
+
HyphenationData(String languageTag, int minPrefix, int minSuffix) {
- this.mLanguageTag = languageTag;
- this.mMinPrefix = minPrefix;
- this.mMinSuffix = minSuffix;
- }
- }
+ mMinPrefix = minPrefix;
+ mMinSuffix = minSuffix;
- private static Hyphenator loadHyphenator(HyphenationData data) {
- String patternFilename = "hyph-" + data.mLanguageTag.toLowerCase(Locale.US) + ".hyb";
- File patternFile = new File(getSystemHyphenatorLocation(), patternFilename);
- if (!patternFile.canRead()) {
- Log.e(TAG, "hyphenation patterns for " + patternFile + " not found or unreadable");
- return null;
- }
- try {
- RandomAccessFile f = new RandomAccessFile(patternFile, "r");
- try {
- FileChannel fc = f.getChannel();
- MappedByteBuffer buf = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
- long nativePtr = StaticLayout.nLoadHyphenator(
- buf, 0, data.mMinPrefix, data.mMinSuffix);
- return new Hyphenator(nativePtr, buf);
- } finally {
- f.close();
+ final String patternFilename = "hyph-" + languageTag.toLowerCase(Locale.US) + ".hyb";
+ final File patternFile = new File(SYSTEM_HYPHENATOR_LOCATION, patternFilename);
+ if (!patternFile.canRead()) {
+ Log.e(TAG, "hyphenation patterns for " + patternFile + " not found or unreadable");
+ mDataAddress = 0;
+ } else {
+ long address;
+ try (RandomAccessFile f = new RandomAccessFile(patternFile, "r")) {
+ address = Os.mmap(0, f.length(), OsConstants.PROT_READ,
+ OsConstants.MAP_SHARED, f.getFD(), 0 /* offset */);
+ } catch (IOException | ErrnoException e) {
+ Log.e(TAG, "error loading hyphenation " + patternFile, e);
+ address = 0;
+ }
+ mDataAddress = address;
}
- } catch (IOException e) {
- Log.e(TAG, "error loading hyphenation " + patternFile, e);
- return null;
}
}
- private static File getSystemHyphenatorLocation() {
- return new File("/system/usr/hyphen-data");
+ // Do not call this method outside of init method.
+ private static Hyphenator putNewHyphenator(Locale loc, HyphenationData data) {
+ final Hyphenator hyphenator = new Hyphenator(nBuildHyphenator(
+ data.mDataAddress, loc.getLanguage(), data.mMinPrefix, data.mMinSuffix), data);
+ sMap.put(loc, hyphenator);
+ return hyphenator;
}
- // This array holds pairs of language tags that are used to prefill the map from locale to
- // hyphenation data: The hyphenation data for the first field will be prefilled from the
- // hyphenation data for the second field.
- //
- // The aliases that are computable by the get() method above are not included.
- private static final String[][] LOCALE_FALLBACK_DATA = {
- // English locales that fall back to en-US. The data is
- // from CLDR. It's all English locales, minus the locales whose
- // parent is en-001 (from supplementalData.xml, under <parentLocales>).
- // TODO: Figure out how to get this from ICU.
- {"en-AS", "en-US"}, // English (American Samoa)
- {"en-GU", "en-US"}, // English (Guam)
- {"en-MH", "en-US"}, // English (Marshall Islands)
- {"en-MP", "en-US"}, // English (Northern Mariana Islands)
- {"en-PR", "en-US"}, // English (Puerto Rico)
- {"en-UM", "en-US"}, // English (United States Minor Outlying Islands)
- {"en-VI", "en-US"}, // English (Virgin Islands)
+ // Do not call this method outside of init method.
+ private static void loadData(String langTag, int minPrefix, int maxPrefix) {
+ final HyphenationData data = new HyphenationData(langTag, minPrefix, maxPrefix);
+ putNewHyphenator(Locale.forLanguageTag(langTag), data);
+ }
- // All English locales other than those falling back to en-US are mapped to en-GB.
- {"en", "en-GB"},
+ // Caller must acquire sLock before calling this method.
+ // The Hyphenator for the baseLangTag must exists.
+ private static Hyphenator addAliasByTag(String langTag, String baseLangTag) {
+ return putAlias(Locale.forLanguageTag(langTag),
+ sMap.get(Locale.forLanguageTag(baseLangTag)));
+ }
- // For German, we're assuming the 1996 (and later) orthography by default.
- {"de", "de-1996"},
- // Liechtenstein uses the Swiss hyphenation rules for the 1901 orthography.
- {"de-LI-1901", "de-CH-1901"},
+ // Caller must acquire sLock before calling this method.
+ private static Hyphenator putAlias(Locale locale, Hyphenator base) {
+ return putNewHyphenator(locale, base.mData);
+ }
- // Norwegian is very probably Norwegian Bokmål.
- {"no", "nb"},
+ // Caller must acquire sLock before calling this method.
+ private static Hyphenator putEmptyAlias(Locale locale) {
+ return putNewHyphenator(locale, HyphenationData.sEmptyData);
+ }
- // Use mn-Cyrl. According to CLDR's likelySubtags.xml, mn is most likely to be mn-Cyrl.
- {"mn", "mn-Cyrl"}, // Mongolian
-
- // Fall back to Ethiopic script for languages likely to be written in Ethiopic.
- // Data is from CLDR's likelySubtags.xml.
- // TODO: Convert this to a mechanism using ICU4J's ULocale#addLikelySubtags().
- {"am", "und-Ethi"}, // Amharic
- {"byn", "und-Ethi"}, // Blin
- {"gez", "und-Ethi"}, // Geʻez
- {"ti", "und-Ethi"}, // Tigrinya
- {"wal", "und-Ethi"}, // Wolaytta
- };
-
- private static final HyphenationData[] AVAILABLE_LANGUAGES = {
- new HyphenationData("as", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Assamese
- new HyphenationData("bg", 2, 2), // Bulgarian
- new HyphenationData("bn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Bengali
- new HyphenationData("cu", 1, 2), // Church Slavonic
- new HyphenationData("cy", 2, 3), // Welsh
- new HyphenationData("da", 2, 2), // Danish
- new HyphenationData("de-1901", 2, 2), // German 1901 orthography
- new HyphenationData("de-1996", 2, 2), // German 1996 orthography
- new HyphenationData("de-CH-1901", 2, 2), // Swiss High German 1901 orthography
- new HyphenationData("en-GB", 2, 3), // British English
- new HyphenationData("en-US", 2, 3), // American English
- new HyphenationData("es", 2, 2), // Spanish
- new HyphenationData("et", 2, 3), // Estonian
- new HyphenationData("eu", 2, 2), // Basque
- new HyphenationData("fr", 2, 3), // French
- new HyphenationData("ga", 2, 3), // Irish
- new HyphenationData("gu", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Gujarati
- new HyphenationData("hi", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Hindi
- new HyphenationData("hr", 2, 2), // Croatian
- new HyphenationData("hu", 2, 2), // Hungarian
- // texhyphen sources say Armenian may be (1, 2), but that it needs confirmation.
- // Going with a more conservative value of (2, 2) for now.
- new HyphenationData("hy", 2, 2), // Armenian
- new HyphenationData("kn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Kannada
- new HyphenationData("ml", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Malayalam
- new HyphenationData("mn-Cyrl", 2, 2), // Mongolian in Cyrillic script
- new HyphenationData("mr", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Marathi
- new HyphenationData("nb", 2, 2), // Norwegian Bokmål
- new HyphenationData("nn", 2, 2), // Norwegian Nynorsk
- new HyphenationData("or", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Oriya
- new HyphenationData("pa", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Punjabi
- new HyphenationData("pt", 2, 3), // Portuguese
- new HyphenationData("sl", 2, 2), // Slovenian
- new HyphenationData("ta", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Tamil
- new HyphenationData("te", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Telugu
- new HyphenationData("tk", 2, 2), // Turkmen
- new HyphenationData("und-Ethi", 1, 1), // Any language in Ethiopic script
- };
+ // TODO: Confirm that these are the best values. Various sources suggest (1, 1), but
+ // that appears too small.
+ private static final int INDIC_MIN_PREFIX = 2;
+ private static final int INDIC_MIN_SUFFIX = 2;
/**
* Load hyphenation patterns at initialization time. We want to have patterns
@@ -250,20 +189,85 @@
* @hide
*/
public static void init() {
- sMap.put(null, null);
+ synchronized (sLock) {
+ sMap.put(null, null);
- for (int i = 0; i < AVAILABLE_LANGUAGES.length; i++) {
- HyphenationData data = AVAILABLE_LANGUAGES[i];
- Hyphenator h = loadHyphenator(data);
- if (h != null) {
- sMap.put(Locale.forLanguageTag(data.mLanguageTag), h);
- }
- }
+ loadData("as", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Assamese
+ loadData("bg", 2, 2); // Bulgarian
+ loadData("bn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Bengali
+ loadData("cu", 1, 2); // Church Slavonic
+ loadData("cy", 2, 3); // Welsh
+ loadData("da", 2, 2); // Danish
+ loadData("de-1901", 2, 2); // German 1901 orthography
+ loadData("de-1996", 2, 2); // German 1996 orthography
+ loadData("de-CH-1901", 2, 2); // Swiss High German 1901 orthography
+ loadData("en-GB", 2, 3); // British English
+ loadData("en-US", 2, 3); // American English
+ loadData("es", 2, 2); // Spanish
+ loadData("et", 2, 3); // Estonian
+ loadData("eu", 2, 2); // Basque
+ loadData("fr", 2, 3); // French
+ loadData("ga", 2, 3); // Irish
+ loadData("gu", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Gujarati
+ loadData("hi", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Hindi
+ loadData("hr", 2, 2); // Croatian
+ loadData("hu", 2, 2); // Hungarian
+ // texhyphen sources say Armenian may be (1, 2); but that it needs confirmation.
+ // Going with a more conservative value of (2, 2) for now.
+ loadData("hy", 2, 2); // Armenian
+ loadData("kn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Kannada
+ loadData("ml", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Malayalam
+ loadData("mn-Cyrl", 2, 2); // Mongolian in Cyrillic script
+ loadData("mr", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Marathi
+ loadData("nb", 2, 2); // Norwegian Bokmål
+ loadData("nn", 2, 2); // Norwegian Nynorsk
+ loadData("or", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Oriya
+ loadData("pa", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Punjabi
+ loadData("pt", 2, 3); // Portuguese
+ loadData("sl", 2, 2); // Slovenian
+ loadData("ta", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Tamil
+ loadData("te", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Telugu
+ loadData("tk", 2, 2); // Turkmen
+ loadData("und-Ethi", 1, 1); // Any language in Ethiopic script
- for (int i = 0; i < LOCALE_FALLBACK_DATA.length; i++) {
- String language = LOCALE_FALLBACK_DATA[i][0];
- String fallback = LOCALE_FALLBACK_DATA[i][1];
- sMap.put(Locale.forLanguageTag(language), sMap.get(Locale.forLanguageTag(fallback)));
+ // English locales that fall back to en-US. The data is
+ // from CLDR. It's all English locales, minus the locales whose
+ // parent is en-001 (from supplementalData.xml, under <parentLocales>).
+ // TODO: Figure out how to get this from ICU.
+ addAliasByTag("en-AS", "en-US"); // English (American Samoa)
+ addAliasByTag("en-GU", "en-US"); // English (Guam)
+ addAliasByTag("en-MH", "en-US"); // English (Marshall Islands)
+ addAliasByTag("en-MP", "en-US"); // English (Northern Mariana Islands)
+ addAliasByTag("en-PR", "en-US"); // English (Puerto Rico)
+ addAliasByTag("en-UM", "en-US"); // English (United States Minor Outlying Islands)
+ addAliasByTag("en-VI", "en-US"); // English (Virgin Islands)
+
+ // All English locales other than those falling back to en-US are mapped to en-GB.
+ addAliasByTag("en", "en-GB");
+
+ // For German, we're assuming the 1996 (and later) orthography by default.
+ addAliasByTag("de", "de-1996");
+ // Liechtenstein uses the Swiss hyphenation rules for the 1901 orthography.
+ addAliasByTag("de-LI-1901", "de-CH-1901");
+
+ // Norwegian is very probably Norwegian Bokmål.
+ addAliasByTag("no", "nb");
+
+ // Use mn-Cyrl. According to CLDR's likelySubtags.xml, mn is most likely to be mn-Cyrl.
+ addAliasByTag("mn", "mn-Cyrl"); // Mongolian
+
+ // Fall back to Ethiopic script for languages likely to be written in Ethiopic.
+ // Data is from CLDR's likelySubtags.xml.
+ // TODO: Convert this to a mechanism using ICU4J's ULocale#addLikelySubtags().
+ addAliasByTag("am", "und-Ethi"); // Amharic
+ addAliasByTag("byn", "und-Ethi"); // Blin
+ addAliasByTag("gez", "und-Ethi"); // Geʻez
+ addAliasByTag("ti", "und-Ethi"); // Tigrinya
+ addAliasByTag("wal", "und-Ethi"); // Wolaytta
}
- }
+ };
+
+ private static native long nBuildHyphenator(/* non-zero */ long dataAddress,
+ @NonNull String langTag, @IntRange(from = 1) int minPrefix,
+ @IntRange(from = 1) int minSuffix);
}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 25f791b..60fff73 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1915,8 +1915,7 @@
return margin;
}
- /* package */
- static float measurePara(TextPaint paint, CharSequence text, int start, int end,
+ private static float measurePara(TextPaint paint, CharSequence text, int start, int end,
TextDirectionHeuristic textDir) {
MeasuredText mt = MeasuredText.obtain();
TextLine tl = TextLine.obtain();
@@ -2146,18 +2145,14 @@
* text within the layout of a line.
*/
public static class Directions {
- // Directions represents directional runs within a line of text.
- // Runs are pairs of ints listed in visual order, starting from the
- // leading margin. The first int of each pair is the offset from
- // the first character of the line to the start of the run. The
- // second int represents both the length and level of the run.
- // The length is in the lower bits, accessed by masking with
- // DIR_LENGTH_MASK. The level is in the higher bits, accessed
- // by shifting by DIR_LEVEL_SHIFT and masking by DIR_LEVEL_MASK.
- // To simply test for an RTL direction, test the bit using
- // DIR_RTL_FLAG, if set then the direction is rtl.
-
/**
+ * Directions represents directional runs within a line of text. Runs are pairs of ints
+ * listed in visual order, starting from the leading margin. The first int of each pair is
+ * the offset from the first character of the line to the start of the run. The second int
+ * represents both the length and level of the run. The length is in the lower bits,
+ * accessed by masking with RUN_LENGTH_MASK. The level is in the higher bits, accessed by
+ * shifting by RUN_LEVEL_SHIFT and masking by RUN_LEVEL_MASK. To simply test for an RTL
+ * direction, test the bit using RUN_RTL_FLAG, if set then the direction is rtl.
* @hide
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index ce3e282..2cfec30 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -165,40 +165,26 @@
paint.getFontMetricsInt(fm);
}
- int p = mPos;
+ final int p = mPos;
mPos = p + len;
- // try to do widths measurement in native code, but use Java if paint has been subclassed
- // FIXME: may want to eliminate special case for subclass
- float[] widths = null;
- if (mBuilder == null || paint.getClass() != TextPaint.class) {
- widths = mWidths;
- }
if (mEasy) {
- boolean isRtl = mDir != Layout.DIR_LEFT_TO_RIGHT;
- float width = 0;
- if (widths != null) {
- width = paint.getTextRunAdvances(mChars, p, len, p, len, isRtl, widths, p);
- if (mBuilder != null) {
- mBuilder.addMeasuredRun(p, p + len, widths);
- }
+ final boolean isRtl = mDir != Layout.DIR_LEFT_TO_RIGHT;
+ if (mBuilder == null) {
+ return paint.getTextRunAdvances(mChars, p, len, p, len, isRtl, mWidths, p);
} else {
- width = mBuilder.addStyleRun(paint, p, p + len, isRtl);
+ return mBuilder.addStyleRun(paint, p, p + len, isRtl);
}
- return width;
}
float totalAdvance = 0;
int level = mLevels[p];
for (int q = p, i = p + 1, e = p + len;; ++i) {
if (i == e || mLevels[i] != level) {
- boolean isRtl = (level & 0x1) != 0;
- if (widths != null) {
+ final boolean isRtl = (level & 0x1) != 0;
+ if (mBuilder == null) {
totalAdvance +=
- paint.getTextRunAdvances(mChars, q, i - q, q, i - q, isRtl, widths, q);
- if (mBuilder != null) {
- mBuilder.addMeasuredRun(q, i, widths);
- }
+ paint.getTextRunAdvances(mChars, q, i - q, q, i - q, isRtl, mWidths, q);
} else {
totalAdvance += mBuilder.addStyleRun(paint, q, i, isRtl);
}
@@ -243,7 +229,7 @@
for (int i = mPos + 1, e = mPos + len; i < e; i++)
w[i] = 0;
} else {
- mBuilder.addReplacementRun(mPos, mPos + len, wid);
+ mBuilder.addReplacementRun(paint, mPos, mPos + len, wid);
}
mPos += len;
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 3303b54..e2c31de 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -28,12 +28,12 @@
import android.text.style.MetricAffectingSpan;
import android.text.style.TabStopSpan;
import android.util.Log;
+import android.util.Pair;
import android.util.Pools.SynchronizedPool;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
-import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Locale;
@@ -101,6 +101,7 @@
b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
b.mJustificationMode = Layout.JUSTIFICATION_MODE_NONE;
+ b.mLocales = null;
b.mMeasuredText = MeasuredText.obtain();
return b;
@@ -117,6 +118,9 @@
b.mMeasuredText = null;
b.mLeftIndents = null;
b.mRightIndents = null;
+ b.mLocales = null;
+ b.mLeftPaddings = null;
+ b.mRightPaddings = null;
nFinishBuilder(b.mNativePtr);
sPool.release(b);
}
@@ -128,6 +132,8 @@
mPaint = null;
mLeftIndents = null;
mRightIndents = null;
+ mLeftPaddings = null;
+ mRightPaddings = null;
mMeasuredText.finish();
}
@@ -356,6 +362,28 @@
}
/**
+ * Set available paddings to draw overhanging text on. Arguments are arrays holding the
+ * amount of padding available, one per line, measured in pixels. For lines past the last
+ * element in the array, the last element repeats.
+ *
+ * The individual padding amounts should be non-negative. The result of passing negative
+ * paddings is undefined.
+ *
+ * @param leftPaddings array of amounts of available padding for left margin, in pixels
+ * @param rightPaddings array of amounts of available padding for right margin, in pixels
+ * @return this builder, useful for chaining
+ *
+ * @hide
+ */
+ @NonNull
+ public Builder setAvailablePaddings(@Nullable int[] leftPaddings,
+ @Nullable int[] rightPaddings) {
+ mLeftPaddings = leftPaddings;
+ mRightPaddings = rightPaddings;
+ return this;
+ }
+
+ /**
* Set paragraph justification mode. The default value is
* {@link Layout#JUSTIFICATION_MODE_NONE}. If the last line is too short for justification,
* the last line will be displayed with the alignment set by {@link #setAlignment}.
@@ -401,10 +429,8 @@
* future).
*
* Then, for each run within the paragraph:
- * - setLocales (this must be done at least for the first run, optional afterwards)
* - one of the following, depending on the type of run:
* + addStyleRun (a text run, to be measured in native code)
- * + addMeasuredRun (a run already measured in Java, passed into native code)
* + addReplacementRun (a replacement run, width is given)
*
* After measurement, nGetWidths() is valid if the widths are needed (eg for ellipsis).
@@ -413,24 +439,29 @@
* After all paragraphs, call finish() to release expensive buffers.
*/
- private void setLocales(LocaleList locales) {
+ private Pair<String, long[]> getLocaleAndHyphenatorIfChanged(TextPaint paint) {
+ final LocaleList locales = paint.getTextLocales();
+ final String languageTags;
+ long[] hyphenators;
if (!locales.equals(mLocales)) {
- nSetLocales(mNativePtr, locales.toLanguageTags(), getHyphenators(locales));
mLocales = locales;
+ return new Pair(locales.toLanguageTags(), getHyphenators(locales));
+ } else {
+ // passing null means keep current locale.
+ // TODO: move locale change detection to native.
+ return new Pair(null, null);
}
}
/* package */ float addStyleRun(TextPaint paint, int start, int end, boolean isRtl) {
- setLocales(paint.getTextLocales());
- return nAddStyleRun(mNativePtr, paint.getNativeInstance(), start, end, isRtl);
+ Pair<String, long[]> locHyph = getLocaleAndHyphenatorIfChanged(paint);
+ return nAddStyleRun(mNativePtr, paint.getNativeInstance(), start, end, isRtl,
+ locHyph.first, locHyph.second);
}
- /* package */ void addMeasuredRun(int start, int end, float[] widths) {
- nAddMeasuredRun(mNativePtr, start, end, widths);
- }
-
- /* package */ void addReplacementRun(int start, int end, float width) {
- nAddReplacementRun(mNativePtr, start, end, width);
+ /* package */ void addReplacementRun(TextPaint paint, int start, int end, float width) {
+ Pair<String, long[]> locHyph = getLocaleAndHyphenatorIfChanged(paint);
+ nAddReplacementRun(mNativePtr, start, end, width, locHyph.first, locHyph.second);
}
/**
@@ -478,6 +509,8 @@
private int mHyphenationFrequency;
@Nullable private int[] mLeftIndents;
@Nullable private int[] mRightIndents;
+ @Nullable private int[] mLeftPaddings;
+ @Nullable private int[] mRightPaddings;
private int mJustificationMode;
private boolean mAddLastLineLineSpacing;
@@ -638,6 +671,8 @@
mLeftIndents = b.mLeftIndents;
mRightIndents = b.mRightIndents;
+ mLeftPaddings = b.mLeftPaddings;
+ mRightPaddings = b.mRightPaddings;
setJustificationMode(b.mJustificationMode);
generate(b, b.mIncludePad, b.mIncludePad);
@@ -662,7 +697,6 @@
// store fontMetrics per span range
// must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range)
int[] fmCache = new int[4 * 4];
- b.setLocales(paint.getTextLocales());
mLineCount = 0;
mEllipsized = false;
@@ -776,11 +810,17 @@
}
}
+ // TODO: Move locale tracking code to native.
+ b.mLocales = null; // Reset the locale tracking.
+
nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
firstWidth, firstWidthLineCount, restWidth,
variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency,
// TODO: Support more justification mode, e.g. letter spacing, stretching.
- b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE, indents, mLineCount);
+ b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE,
+ // TODO: indents and paddings don't need to get passed to native code for every
+ // paragraph. Pass them to native code just once.
+ indents, mLeftPaddings, mRightPaddings, mLineCount);
// measurement has to be done before performing line breaking
// but we don't want to recompute fontmetrics or span ranges the
@@ -1491,28 +1531,25 @@
private static native void nFreeBuilder(long nativePtr);
private static native void nFinishBuilder(long nativePtr);
- /* package */ static native long nLoadHyphenator(ByteBuffer buf, int offset,
- int minPrefix, int minSuffix);
-
- private static native void nSetLocales(long nativePtr, String locales,
- long[] nativeHyphenators);
-
// Set up paragraph text and settings; done as one big method to minimize jni crossings
private static native void nSetupParagraph(
- @NonNull long nativePtr, @NonNull char[] text, @IntRange(from = 0) int length,
+ /* non zero */ long nativePtr, @NonNull char[] text, @IntRange(from = 0) int length,
@FloatRange(from = 0.0f) float firstWidth, @IntRange(from = 0) int firstWidthLineCount,
@FloatRange(from = 0.0f) float restWidth, @Nullable int[] variableTabStops,
int defaultTabStop, @BreakStrategy int breakStrategy,
@HyphenationFrequency int hyphenationFrequency, boolean isJustified,
- @Nullable int[] indents, @IntRange(from = 0) int indentsOffset);
+ @Nullable int[] indents, @Nullable int[] leftPaddings, @Nullable int[] rightPaddings,
+ @IntRange(from = 0) int indentsOffset);
- private static native float nAddStyleRun(long nativePtr, long nativePaint, int start, int end,
- boolean isRtl);
+ private static native float nAddStyleRun(
+ /* non-zero */ long nativePtr, /* non-zero */ long nativePaint,
+ @IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean isRtl,
+ @Nullable String languageTags, @Nullable long[] hyphenators);
- private static native void nAddMeasuredRun(long nativePtr,
- int start, int end, float[] widths);
-
- private static native void nAddReplacementRun(long nativePtr, int start, int end, float width);
+ private static native void nAddReplacementRun(/* non-zero */ long nativePtr,
+ @IntRange(from = 0) int start, @IntRange(from = 0) int end,
+ @FloatRange(from = 0.0f) float width, @Nullable String languageTags,
+ @Nullable long[] hyphenators);
private static native void nGetWidths(long nativePtr, float[] widths);
@@ -1590,4 +1627,6 @@
@Nullable private int[] mLeftIndents;
@Nullable private int[] mRightIndents;
+ @Nullable private int[] mLeftPaddings;
+ @Nullable private int[] mRightPaddings;
}
diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java
index 4951237..3306a50 100644
--- a/core/java/android/transition/TransitionUtils.java
+++ b/core/java/android/transition/TransitionUtils.java
@@ -115,7 +115,7 @@
/**
* Get a copy of bitmap of given drawable, return null if intrinsic size is zero
*/
- public static Bitmap createDrawableBitmap(Drawable drawable) {
+ public static Bitmap createDrawableBitmap(Drawable drawable, View hostView) {
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
if (width <= 0 || height <= 0) {
@@ -128,7 +128,7 @@
}
int bitmapWidth = (int) (width * scale);
int bitmapHeight = (int) (height * scale);
- final RenderNode node = RenderNode.create("TransitionUtils", null);
+ final RenderNode node = RenderNode.create("TransitionUtils", hostView);
node.setLeftTopRightBottom(0, 0, width, height);
node.setClipToBounds(false);
final DisplayListCanvas canvas = node.start(width, height);
@@ -159,17 +159,20 @@
* @return A bitmap of the given view or null if bounds has no width or height.
*/
public static Bitmap createViewBitmap(View view, Matrix matrix, RectF bounds) {
+ if (!view.isAttachedToWindow()) {
+ return null;
+ }
Bitmap bitmap = null;
int bitmapWidth = Math.round(bounds.width());
int bitmapHeight = Math.round(bounds.height());
if (bitmapWidth > 0 && bitmapHeight > 0) {
- float scale = Math.min(1f, ((float)MAX_IMAGE_SIZE) / (bitmapWidth * bitmapHeight));
+ float scale = Math.min(1f, ((float) MAX_IMAGE_SIZE) / (bitmapWidth * bitmapHeight));
bitmapWidth *= scale;
bitmapHeight *= scale;
matrix.postTranslate(-bounds.left, -bounds.top);
matrix.postScale(scale, scale);
- final RenderNode node = RenderNode.create("TransitionUtils", null);
+ final RenderNode node = RenderNode.create("TransitionUtils", view);
node.setLeftTopRightBottom(0, 0, bitmapWidth, bitmapHeight);
node.setClipToBounds(false);
final DisplayListCanvas canvas = node.start(bitmapWidth, bitmapHeight);
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 8691136..0299865 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -392,7 +392,7 @@
// and the length of the tag.
// Note: we implicitly accept possible truncation for Modified-UTF8 differences. It
// is too expensive to compute that ahead of time.
- int bufferSize = NoPreloadHolder.LOGGER_ENTRY_MAX_PAYLOAD // Base.
+ int bufferSize = PreloadHolder.LOGGER_ENTRY_MAX_PAYLOAD // Base.
- 2 // Two terminators.
- (tag != null ? tag.length() : 0) // Tag length.
- 32; // Some slack.
@@ -429,10 +429,10 @@
}
/**
- * NoPreloadHelper class. Caches the LOGGER_ENTRY_MAX_PAYLOAD value to avoid
+ * PreloadHelper class. Caches the LOGGER_ENTRY_MAX_PAYLOAD value to avoid
* a JNI call during logging.
*/
- static class NoPreloadHolder {
+ static class PreloadHolder {
public final static int LOGGER_ENTRY_MAX_PAYLOAD =
logger_entry_max_payload_native();
}
diff --git a/core/java/android/util/StatsLogKey.java b/core/java/android/util/StatsLogKey.java
new file mode 100644
index 0000000..9ad0a23
--- /dev/null
+++ b/core/java/android/util/StatsLogKey.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// THIS FILE IS AUTO-GENERATED.
+// DO NOT MODIFY.
+
+package android.util;
+
+/** @hide */
+public class StatsLogKey {
+ private StatsLogKey() {}
+
+ /** Constants for android.os.statsd.ScreenStateChange. */
+
+ /** display_state */
+ public static final int SCREEN_STATE_CHANGE__DISPLAY_STATE = 1;
+
+ /** Constants for android.os.statsd.ProcessStateChange. */
+
+ /** state */
+ public static final int PROCESS_STATE_CHANGE__STATE = 1;
+
+ /** uid */
+ public static final int PROCESS_STATE_CHANGE__UID = 2;
+
+ /** package_name */
+ public static final int PROCESS_STATE_CHANGE__PACKAGE_NAME = 1002;
+
+ /** package_version */
+ public static final int PROCESS_STATE_CHANGE__PACKAGE_VERSION = 3;
+
+ /** package_version_string */
+ public static final int PROCESS_STATE_CHANGE__PACKAGE_VERSION_STRING = 4;
+
+}
diff --git a/core/java/android/util/StatsLogTag.java b/core/java/android/util/StatsLogTag.java
new file mode 100644
index 0000000..5e5a828
--- /dev/null
+++ b/core/java/android/util/StatsLogTag.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// THIS FILE IS AUTO-GENERATED.
+// DO NOT MODIFY.
+
+package android.util;
+
+/** @hide */
+public class StatsLogTag {
+ private StatsLogTag() {}
+
+ /** android.os.statsd.ScreenStateChange. */
+ public static final int SCREEN_STATE_CHANGE = 2;
+
+ /** android.os.statsd.ProcessStateChange. */
+ public static final int PROCESS_STATE_CHANGE = 1112;
+
+}
diff --git a/core/java/android/util/StatsLogValue.java b/core/java/android/util/StatsLogValue.java
new file mode 100644
index 0000000..05b9d93
--- /dev/null
+++ b/core/java/android/util/StatsLogValue.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// THIS FILE IS AUTO-GENERATED.
+// DO NOT MODIFY.
+
+package android.util;
+
+/** @hide */
+public class StatsLogValue {
+ private StatsLogValue() {}
+
+ /** Constants for android.os.statsd.ScreenStateChange. */
+
+ /** display_state: STATE_UNKNOWN */
+ public static final int SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_UNKNOWN = 0;
+
+ /** display_state: STATE_OFF */
+ public static final int SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF = 1;
+
+ /** display_state: STATE_ON */
+ public static final int SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON = 2;
+
+ /** display_state: STATE_DOZE */
+ public static final int SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_DOZE = 3;
+
+ /** display_state: STATE_DOZE_SUSPEND */
+ public static final int SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_DOZE_SUSPEND = 4;
+
+ /** display_state: STATE_VR */
+ public static final int SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_VR = 5;
+
+ /** Constants for android.os.statsd.ProcessStateChange. */
+
+ /** state: START */
+ public static final int PROCESS_STATE_CHANGE__STATE__START = 1;
+
+ /** state: CRASH */
+ public static final int PROCESS_STATE_CHANGE__STATE__CRASH = 2;
+
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index e576a0f..6e49bac 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -358,10 +358,10 @@
* Updates the dim layer used while resizing.
*
* @param visible Whether the dim layer should be visible.
- * @param targetStackId The id of the task stack the dim layer should be placed on.
+ * @param targetWindowingMode The windowing mode of the stack the dim layer should be placed on.
* @param alpha The translucency of the dim layer, between 0 and 1.
*/
- void setResizeDimLayer(boolean visible, int targetStackId, float alpha);
+ void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha);
/**
* Requests Keyboard Shortcuts from the displayed window.
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 3427cff..3426485 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -1427,7 +1427,9 @@
result.append(name).append(' ');
}
}
- result.deleteCharAt(result.length() - 1);
+ if (result.length() > 0) {
+ result.deleteCharAt(result.length() - 1);
+ }
return result.toString();
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 415aad5..d988d66 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -7714,7 +7714,7 @@
public void onAccessibilityStateChanged(boolean enabled) {
if (enabled) {
ensureConnection();
- if (mAttachInfo.mHasWindowFocus) {
+ if (mAttachInfo.mHasWindowFocus && (mView != null)) {
mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
View focusedView = mView.findFocus();
if (focusedView != null && focusedView != mView) {
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 4131fd1..da72535 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -592,9 +592,10 @@
int getDockedDividerInsetsLw();
/**
- * Retrieves the {@param outBounds} from the stack with id {@param stackId}.
+ * Retrieves the {@param outBounds} from the stack matching the {@param windowingMode} and
+ * {@param activityType}.
*/
- void getStackBounds(int stackId, Rect outBounds);
+ void getStackBounds(int windowingMode, int activityType, Rect outBounds);
/**
* Notifies window manager that {@link #isShowingDreamLw} has changed.
diff --git a/core/java/android/view/autofill/AutofillPopupWindow.java b/core/java/android/view/autofill/AutofillPopupWindow.java
index 5f47638..b4688bb 100644
--- a/core/java/android/view/autofill/AutofillPopupWindow.java
+++ b/core/java/android/view/autofill/AutofillPopupWindow.java
@@ -47,6 +47,19 @@
private final WindowPresenter mWindowPresenter;
private WindowManager.LayoutParams mWindowLayoutParams;
+ private final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
+ new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ /* ignore - handled by the super class */
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ dismiss();
+ }
+ };
+
/**
* Creates a popup window with a presenter owning the window and responsible for
* showing/hiding/updating the backing window. This can be useful of the window is
@@ -208,7 +221,21 @@
p.packageName = anchor.getContext().getPackageName();
mWindowPresenter.show(p, getTransitionEpicenter(), isLayoutInsetDecor(),
anchor.getLayoutDirection());
- return;
+ }
+
+ @Override
+ protected void attachToAnchor(View anchor, int xoff, int yoff, int gravity) {
+ super.attachToAnchor(anchor, xoff, yoff, gravity);
+ anchor.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
+ }
+
+ @Override
+ protected void detachFromAnchor() {
+ final View anchor = getAnchor();
+ if (anchor != null) {
+ anchor.removeOnAttachStateChangeListener(mOnAttachStateChangeListener);
+ }
+ super.detachFromAnchor();
}
@Override
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 1849368..8c3b8a2 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -28,6 +28,7 @@
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -41,10 +42,10 @@
static final TextClassification EMPTY = new TextClassification.Builder().build();
@NonNull private final String mText;
- @Nullable private final Drawable mIcon;
- @Nullable private final String mLabel;
- @Nullable private final Intent mIntent;
- @Nullable private final OnClickListener mOnClickListener;
+ @NonNull private final List<Drawable> mIcons;
+ @NonNull private final List<String> mLabels;
+ @NonNull private final List<Intent> mIntents;
+ @NonNull private final List<OnClickListener> mOnClickListeners;
@NonNull private final EntityConfidence<String> mEntityConfidence;
@NonNull private final List<String> mEntities;
private int mLogType;
@@ -52,18 +53,21 @@
private TextClassification(
@Nullable String text,
- @Nullable Drawable icon,
- @Nullable String label,
- @Nullable Intent intent,
- @Nullable OnClickListener onClickListener,
+ @NonNull List<Drawable> icons,
+ @NonNull List<String> labels,
+ @NonNull List<Intent> intents,
+ @NonNull List<OnClickListener> onClickListeners,
@NonNull EntityConfidence<String> entityConfidence,
int logType,
@NonNull String versionInfo) {
+ Preconditions.checkArgument(labels.size() == intents.size());
+ Preconditions.checkArgument(icons.size() == intents.size());
+ Preconditions.checkArgument(onClickListeners.size() == intents.size());
mText = text;
- mIcon = icon;
- mLabel = label;
- mIntent = intent;
- mOnClickListener = onClickListener;
+ mIcons = icons;
+ mLabels = labels;
+ mIntents = intents;
+ mOnClickListeners = onClickListeners;
mEntityConfidence = new EntityConfidence<>(entityConfidence);
mEntities = mEntityConfidence.getEntities();
mLogType = logType;
@@ -109,35 +113,106 @@
}
/**
- * Returns an icon that may be rendered on a widget used to act on the classified text.
+ * Returns the number of actions that are available to act on the classified text.
+ * @see #getIntent(int)
+ * @see #getLabel(int)
+ * @see #getIcon(int)
+ * @see #getOnClickListener(int)
+ */
+ @IntRange(from = 0)
+ public int getActionCount() {
+ return mIntents.size();
+ }
+
+ /**
+ * Returns one of the icons that maybe rendered on a widget used to act on the classified text.
+ * @param index Index of the action to get the icon for.
+ * @throws IndexOutOfBoundsException if the specified index is out of range.
+ * @see #getActionCount() for the number of entities available.
+ * @see #getIntent(int)
+ * @see #getLabel(int)
+ * @see #getOnClickListener(int)
+ */
+ @Nullable
+ public Drawable getIcon(int index) {
+ return mIcons.get(index);
+ }
+
+ /**
+ * Returns an icon for the default intent that may be rendered on a widget used to act on the
+ * classified text.
*/
@Nullable
public Drawable getIcon() {
- return mIcon;
+ return mIcons.isEmpty() ? null : mIcons.get(0);
}
/**
- * Returns a label that may be rendered on a widget used to act on the classified text.
+ * Returns one of the labels that may be rendered on a widget used to act on the classified
+ * text.
+ * @param index Index of the action to get the label for.
+ * @throws IndexOutOfBoundsException if the specified index is out of range.
+ * @see #getActionCount()
+ * @see #getIntent(int)
+ * @see #getIcon(int)
+ * @see #getOnClickListener(int)
+ */
+ @Nullable
+ public CharSequence getLabel(int index) {
+ return mLabels.get(index);
+ }
+
+ /**
+ * Returns a label for the default intent that may be rendered on a widget used to act on the
+ * classified text.
*/
@Nullable
public CharSequence getLabel() {
- return mLabel;
+ return mLabels.isEmpty() ? null : mLabels.get(0);
}
/**
- * Returns an intent that may be fired to act on the classified text.
+ * Returns one of the intents that may be fired to act on the classified text.
+ * @param index Index of the action to get the intent for.
+ * @throws IndexOutOfBoundsException if the specified index is out of range.
+ * @see #getActionCount()
+ * @see #getLabel(int)
+ * @see #getIcon(int)
+ * @see #getOnClickListener(int)
+ */
+ @Nullable
+ public Intent getIntent(int index) {
+ return mIntents.get(index);
+ }
+
+ /**
+ * Returns the default intent that may be fired to act on the classified text.
*/
@Nullable
public Intent getIntent() {
- return mIntent;
+ return mIntents.isEmpty() ? null : mIntents.get(0);
}
/**
- * Returns an OnClickListener that may be triggered to act on the classified text.
+ * Returns one of the OnClickListeners that may be triggered to act on the classified text.
+ * @param index Index of the action to get the click listener for.
+ * @throws IndexOutOfBoundsException if the specified index is out of range.
+ * @see #getActionCount()
+ * @see #getIntent(int)
+ * @see #getLabel(int)
+ * @see #getIcon(int)
+ */
+ @Nullable
+ public OnClickListener getOnClickListener(int index) {
+ return mOnClickListeners.get(index);
+ }
+
+ /**
+ * Returns the default OnClickListener that may be triggered to act on the classified text.
*/
@Nullable
public OnClickListener getOnClickListener() {
- return mOnClickListener;
+ return mOnClickListeners.isEmpty() ? null : mOnClickListeners.get(0);
}
/**
@@ -160,8 +235,8 @@
@Override
public String toString() {
return String.format("TextClassification {"
- + "text=%s, entities=%s, label=%s, intent=%s}",
- mText, mEntityConfidence, mLabel, mIntent);
+ + "text=%s, entities=%s, labels=%s, intents=%s}",
+ mText, mEntityConfidence, mLabels, mIntents);
}
/**
@@ -184,10 +259,10 @@
public static final class Builder {
@NonNull private String mText;
- @Nullable private Drawable mIcon;
- @Nullable private String mLabel;
- @Nullable private Intent mIntent;
- @Nullable private OnClickListener mOnClickListener;
+ @NonNull private final List<Drawable> mIcons = new ArrayList<>();
+ @NonNull private final List<String> mLabels = new ArrayList<>();
+ @NonNull private final List<Intent> mIntents = new ArrayList<>();
+ @NonNull private final List<OnClickListener> mOnClickListeners = new ArrayList<>();
@NonNull private final EntityConfidence<String> mEntityConfidence =
new EntityConfidence<>();
private int mLogType;
@@ -216,26 +291,57 @@
}
/**
- * Sets an icon that may be rendered on a widget used to act on the classified text.
+ * Adds an action that may be performed on the classified text. The label and icon are used
+ * for rendering of widgets that offer the intent. Actions should be added in order of
+ * priority and the first one will be treated as the default.
+ */
+ public Builder addAction(
+ Intent intent, @Nullable String label, @Nullable Drawable icon,
+ @Nullable OnClickListener onClickListener) {
+ mIntents.add(intent);
+ mLabels.add(label);
+ mIcons.add(icon);
+ mOnClickListeners.add(onClickListener);
+ return this;
+ }
+
+ /**
+ * Removes all actions.
+ */
+ public Builder clearActions() {
+ mIntents.clear();
+ mOnClickListeners.clear();
+ mLabels.clear();
+ mIcons.clear();
+ return this;
+ }
+
+ /**
+ * Sets the icon for the default action that may be rendered on a widget used to act on the
+ * classified text.
*/
public Builder setIcon(@Nullable Drawable icon) {
- mIcon = icon;
+ ensureDefaultActionAvailable();
+ mIcons.set(0, icon);
return this;
}
/**
- * Sets a label that may be rendered on a widget used to act on the classified text.
+ * Sets the label for the default action that may be rendered on a widget used to act on the
+ * classified text.
*/
public Builder setLabel(@Nullable String label) {
- mLabel = label;
+ ensureDefaultActionAvailable();
+ mLabels.set(0, label);
return this;
}
/**
- * Sets an intent that may be fired to act on the classified text.
+ * Sets the intent for the default action that may be fired to act on the classified text.
*/
public Builder setIntent(@Nullable Intent intent) {
- mIntent = intent;
+ ensureDefaultActionAvailable();
+ mIntents.set(0, intent);
return this;
}
@@ -249,10 +355,12 @@
}
/**
- * Sets an OnClickListener that may be triggered to act on the classified text.
+ * Sets the OnClickListener for the default action that may be triggered to act on the
+ * classified text.
*/
public Builder setOnClickListener(@Nullable OnClickListener onClickListener) {
- mOnClickListener = onClickListener;
+ ensureDefaultActionAvailable();
+ mOnClickListeners.set(0, onClickListener);
return this;
}
@@ -266,11 +374,21 @@
}
/**
+ * Ensures that we have at we have storage for the default action.
+ */
+ private void ensureDefaultActionAvailable() {
+ if (mIntents.isEmpty()) mIntents.add(null);
+ if (mLabels.isEmpty()) mLabels.add(null);
+ if (mIcons.isEmpty()) mIcons.add(null);
+ if (mOnClickListeners.isEmpty()) mOnClickListeners.add(null);
+ }
+
+ /**
* Builds and returns a {@link TextClassification} object.
*/
public TextClassification build() {
return new TextClassification(
- mText, mIcon, mLabel, mIntent, mOnClickListener, mEntityConfidence,
+ mText, mIcons, mLabels, mIntents, mOnClickListeners, mEntityConfidence,
mLogType, mVersionInfo);
}
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 7e93b78..2aa81a2 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -29,6 +29,7 @@
import android.os.LocaleList;
import android.os.ParcelFileDescriptor;
import android.provider.Browser;
+import android.provider.ContactsContract;
import android.text.Spannable;
import android.text.TextUtils;
import android.text.method.WordIterator;
@@ -356,7 +357,16 @@
final String type = getHighestScoringType(classifications);
builder.setLogType(IntentFactory.getLogType(type));
- final Intent intent = IntentFactory.create(mContext, type, text.toString());
+ final List<Intent> intents = IntentFactory.create(mContext, type, text.toString());
+ for (Intent intent : intents) {
+ extendClassificationWithIntent(intent, builder);
+ }
+
+ return builder.setVersionInfo(getVersionInfo()).build();
+ }
+
+ /** Extends the classification with the intent if it can be resolved. */
+ private void extendClassificationWithIntent(Intent intent, TextClassification.Builder builder) {
final PackageManager pm;
final ResolveInfo resolveInfo;
if (intent != null) {
@@ -367,30 +377,29 @@
resolveInfo = null;
}
if (resolveInfo != null && resolveInfo.activityInfo != null) {
- builder.setIntent(intent)
- .setOnClickListener(TextClassification.createStartActivityOnClickListener(
- mContext, intent));
-
final String packageName = resolveInfo.activityInfo.packageName;
+ CharSequence label;
+ Drawable icon;
if ("android".equals(packageName)) {
// Requires the chooser to find an activity to handle the intent.
- builder.setLabel(IntentFactory.getLabel(mContext, type));
+ label = IntentFactory.getLabel(mContext, intent);
+ icon = null;
} else {
// A default activity will handle the intent.
intent.setComponent(new ComponentName(packageName, resolveInfo.activityInfo.name));
- Drawable icon = resolveInfo.activityInfo.loadIcon(pm);
+ icon = resolveInfo.activityInfo.loadIcon(pm);
if (icon == null) {
icon = resolveInfo.loadIcon(pm);
}
- builder.setIcon(icon);
- CharSequence label = resolveInfo.activityInfo.loadLabel(pm);
+ label = resolveInfo.activityInfo.loadLabel(pm);
if (label == null) {
label = resolveInfo.loadLabel(pm);
}
- builder.setLabel(label != null ? label.toString() : null);
}
+ builder.addAction(
+ intent, label != null ? label.toString() : null, icon,
+ TextClassification.createStartActivityOnClickListener(mContext, intent));
}
- return builder.setVersionInfo(getVersionInfo()).build();
}
private static int getHintFlags(CharSequence text, int start, int end) {
@@ -477,10 +486,11 @@
if (results.length > 0) {
final String type = getHighestScoringType(results);
if (matches(type, linkMask)) {
- final Intent intent = IntentFactory.create(
+ // For links without disambiguation, we simply use the default intent.
+ final List<Intent> intents = IntentFactory.create(
context, type, text.substring(selectionStart, selectionEnd));
- if (hasActivityHandler(context, intent)) {
- final ClickableSpan span = createSpan(context, intent);
+ if (!intents.isEmpty() && hasActivityHandler(context, intents.get(0))) {
+ final ClickableSpan span = createSpan(context, intents.get(0));
spans.add(new SpanSpec(selectionStart, selectionEnd, span));
}
}
@@ -564,7 +574,7 @@
};
}
- private static boolean hasActivityHandler(Context context, @Nullable Intent intent) {
+ private static boolean hasActivityHandler(Context context, Intent intent) {
if (intent == null) {
return false;
}
@@ -625,20 +635,32 @@
private IntentFactory() {}
- @Nullable
- public static Intent create(Context context, String type, String text) {
+ @NonNull
+ public static List<Intent> create(Context context, String type, String text) {
+ final List<Intent> intents = new ArrayList<>();
type = type.trim().toLowerCase(Locale.ENGLISH);
text = text.trim();
switch (type) {
case TextClassifier.TYPE_EMAIL:
- return new Intent(Intent.ACTION_SENDTO)
- .setData(Uri.parse(String.format("mailto:%s", text)));
+ intents.add(new Intent(Intent.ACTION_SENDTO)
+ .setData(Uri.parse(String.format("mailto:%s", text))));
+ intents.add(new Intent(Intent.ACTION_INSERT_OR_EDIT)
+ .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
+ .putExtra(ContactsContract.Intents.Insert.EMAIL, text));
+ break;
case TextClassifier.TYPE_PHONE:
- return new Intent(Intent.ACTION_DIAL)
- .setData(Uri.parse(String.format("tel:%s", text)));
+ intents.add(new Intent(Intent.ACTION_DIAL)
+ .setData(Uri.parse(String.format("tel:%s", text))));
+ intents.add(new Intent(Intent.ACTION_INSERT_OR_EDIT)
+ .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
+ .putExtra(ContactsContract.Intents.Insert.PHONE, text));
+ intents.add(new Intent(Intent.ACTION_SENDTO)
+ .setData(Uri.parse(String.format("smsto:%s", text))));
+ break;
case TextClassifier.TYPE_ADDRESS:
- return new Intent(Intent.ACTION_VIEW)
- .setData(Uri.parse(String.format("geo:0,0?q=%s", text)));
+ intents.add(new Intent(Intent.ACTION_VIEW)
+ .setData(Uri.parse(String.format("geo:0,0?q=%s", text))));
+ break;
case TextClassifier.TYPE_URL:
final String httpPrefix = "http://";
final String httpsPrefix = "https://";
@@ -649,25 +671,47 @@
} else {
text = httpPrefix + text;
}
- return new Intent(Intent.ACTION_VIEW, Uri.parse(text))
- .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
- default:
- return null;
+ intents.add(new Intent(Intent.ACTION_VIEW, Uri.parse(text))
+ .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()));
+ break;
}
+ return intents;
}
@Nullable
- public static String getLabel(Context context, String type) {
- type = type.trim().toLowerCase(Locale.ENGLISH);
- switch (type) {
- case TextClassifier.TYPE_EMAIL:
- return context.getString(com.android.internal.R.string.email);
- case TextClassifier.TYPE_PHONE:
+ public static String getLabel(Context context, @Nullable Intent intent) {
+ if (intent == null || intent.getAction() == null) {
+ return null;
+ }
+ switch (intent.getAction()) {
+ case Intent.ACTION_DIAL:
return context.getString(com.android.internal.R.string.dial);
- case TextClassifier.TYPE_ADDRESS:
- return context.getString(com.android.internal.R.string.map);
- case TextClassifier.TYPE_URL:
- return context.getString(com.android.internal.R.string.browse);
+ case Intent.ACTION_SENDTO:
+ switch (intent.getScheme()) {
+ case "mailto":
+ return context.getString(com.android.internal.R.string.email);
+ case "smsto":
+ return context.getString(com.android.internal.R.string.sms);
+ default:
+ return null;
+ }
+ case Intent.ACTION_INSERT_OR_EDIT:
+ switch (intent.getDataString()) {
+ case ContactsContract.Contacts.CONTENT_ITEM_TYPE:
+ return context.getString(com.android.internal.R.string.add_contact);
+ default:
+ return null;
+ }
+ case Intent.ACTION_VIEW:
+ switch (intent.getScheme()) {
+ case "geo":
+ return context.getString(com.android.internal.R.string.map);
+ case "http": // fall through
+ case "https":
+ return context.getString(com.android.internal.R.string.browse);
+ default:
+ return null;
+ }
default:
return null;
}
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index b839420..fc76029 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -16,13 +16,14 @@
package android.webkit;
+import android.annotation.Nullable;
+
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
-
/**
* Manages the HTTP cache used by an application's {@link WebView} instances.
* @deprecated Access to the HTTP cache will be removed in a future release.
@@ -233,6 +234,7 @@
* @deprecated This method no longer has any effect and always returns {@code null}.
*/
@Deprecated
+ @Nullable
public static File getCacheFileBaseDir() {
return null;
}
@@ -287,6 +289,7 @@
* @deprecated This method no longer has any effect and always returns {@code null}.
*/
@Deprecated
+ @Nullable
public static CacheResult getCacheFile(String url,
Map<String, String> headers) {
return null;
diff --git a/core/java/android/webkit/ClientCertRequest.java b/core/java/android/webkit/ClientCertRequest.java
index de17534..0fc47f1 100644
--- a/core/java/android/webkit/ClientCertRequest.java
+++ b/core/java/android/webkit/ClientCertRequest.java
@@ -16,6 +16,8 @@
package android.webkit;
+import android.annotation.Nullable;
+
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
@@ -42,14 +44,16 @@
public ClientCertRequest() { }
/**
- * Returns the acceptable types of asymmetric keys (can be {@code null}).
+ * Returns the acceptable types of asymmetric keys.
*/
+ @Nullable
public abstract String[] getKeyTypes();
/**
* Returns the acceptable certificate issuers for the certificate
- * matching the private key (can be {@code null}).
+ * matching the private key.
*/
+ @Nullable
public abstract Principal[] getPrincipals();
/**
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 8989293..ae6a2fd 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.WebAddress;
@@ -116,7 +117,8 @@
* HTTP response header
* @param callback a callback to be executed when the cookie has been set
*/
- public abstract void setCookie(String url, String value, ValueCallback<Boolean> callback);
+ public abstract void setCookie(String url, String value, @Nullable ValueCallback<Boolean>
+ callback);
/**
* Gets the cookies for the given URL.
@@ -175,7 +177,7 @@
* method from a thread without a Looper.
* @param callback a callback which is executed when the session cookies have been removed
*/
- public abstract void removeSessionCookies(ValueCallback<Boolean> callback);
+ public abstract void removeSessionCookies(@Nullable ValueCallback<Boolean> callback);
/**
* Removes all cookies.
@@ -197,7 +199,7 @@
* method from a thread without a Looper.
* @param callback a callback which is executed when the cookies have been removed
*/
- public abstract void removeAllCookies(ValueCallback<Boolean> callback);
+ public abstract void removeAllCookies(@Nullable ValueCallback<Boolean> callback);
/**
* Gets whether there are stored cookies.
diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java
index 71f85d7..e011d51 100644
--- a/core/java/android/webkit/FindActionModeCallback.java
+++ b/core/java/android/webkit/FindActionModeCallback.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.res.Resources;
@@ -69,7 +70,7 @@
mActionMode.finish();
}
- /*
+ /**
* Place text in the text field so it can be searched for. Need to press
* the find next or find previous button to find all of the matches.
*/
@@ -87,10 +88,12 @@
mMatchesFound = false;
}
- /*
- * Set the WebView to search. Must be non null.
+ /**
+ * Set the WebView to search.
+ *
+ * @param webView an implementation of WebView
*/
- public void setWebView(WebView webView) {
+ public void setWebView(@NonNull WebView webView) {
if (null == webView) {
throw new AssertionError("WebView supplied to "
+ "FindActionModeCallback cannot be null");
@@ -107,7 +110,7 @@
}
}
- /*
+ /**
* Move the highlight to the next match.
* @param next If {@code true}, find the next match further down in the document.
* If {@code false}, find the previous match, up in the document.
@@ -130,7 +133,7 @@
updateMatchesString();
}
- /*
+ /**
* Highlight all the instances of the string from mEditText in mWebView.
*/
public void findAll() {
@@ -169,7 +172,7 @@
}
}
- /*
+ /**
* Update the string which tells the user how many matches were found, and
* which match is currently highlighted.
*/
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
index e172c02..39874e8 100644
--- a/core/java/android/webkit/MimeTypeMap.java
+++ b/core/java/android/webkit/MimeTypeMap.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.annotation.Nullable;
import android.text.TextUtils;
import libcore.net.MimeUtils;
@@ -86,6 +87,7 @@
* @param extension A file extension without the leading '.'
* @return The MIME type for the given extension or {@code null} iff there is none.
*/
+ @Nullable
public String getMimeTypeFromExtension(String extension) {
return MimeUtils.guessMimeTypeFromExtension(extension);
}
@@ -111,6 +113,7 @@
* @param mimeType A MIME type (i.e. text/plain)
* @return The extension for the given MIME type or {@code null} iff there is none.
*/
+ @Nullable
public String getExtensionFromMimeType(String mimeType) {
return MimeUtils.guessExtensionFromMimeType(mimeType);
}
@@ -125,7 +128,7 @@
* @param contentDisposition Content-disposition header given by the server.
* @return The MIME type that should be used for this data.
*/
- /* package */ String remapGenericMimeType(String mimeType, String url,
+ /* package */ String remapGenericMimeType(@Nullable String mimeType, String url,
String contentDisposition) {
// If we have one of "generic" MIME types, try to deduce
// the right MIME type from the file extension (if any):
diff --git a/core/java/android/webkit/Plugin.java b/core/java/android/webkit/Plugin.java
index 072e02a..29a5edc 100644
--- a/core/java/android/webkit/Plugin.java
+++ b/core/java/android/webkit/Plugin.java
@@ -16,12 +16,12 @@
package android.webkit;
-import com.android.internal.R;
-
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
+import com.android.internal.R;
+
/**
* Represents a plugin (Java equivalent of the PluginPackageAndroid
* C++ class in libs/WebKitLib/WebKit/WebCore/plugins/android/)
@@ -32,13 +32,13 @@
*/
@Deprecated
public class Plugin {
- /*
+ /**
* @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
public interface PreferencesClickHandler {
- /*
+ /**
* @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
diff --git a/core/java/android/webkit/ServiceWorkerClient.java b/core/java/android/webkit/ServiceWorkerClient.java
index b4964fd..d6e8f36 100644
--- a/core/java/android/webkit/ServiceWorkerClient.java
+++ b/core/java/android/webkit/ServiceWorkerClient.java
@@ -16,6 +16,8 @@
package android.webkit;
+import android.annotation.Nullable;
+
/**
* Base class for clients to capture Service Worker related callbacks,
* see {@link ServiceWorkerController} for usage example.
@@ -37,6 +39,7 @@
* resource itself.
* @see WebViewClient#shouldInterceptRequest(WebView, WebResourceRequest)
*/
+ @Nullable
public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) {
return null;
}
diff --git a/core/java/android/webkit/TokenBindingService.java b/core/java/android/webkit/TokenBindingService.java
index 43565c2..b37e1b8 100644
--- a/core/java/android/webkit/TokenBindingService.java
+++ b/core/java/android/webkit/TokenBindingService.java
@@ -16,6 +16,8 @@
package android.webkit;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.Uri;
@@ -84,31 +86,30 @@
* The user can pass {@code null} if any algorithm is acceptable.
*
* @param origin The origin for the server.
- * @param algorithm The list of algorithms. Can be {@code null}. An
- * IllegalArgumentException is thrown if array is empty.
+ * @param algorithm The list of algorithms. An IllegalArgumentException is thrown if array is
+ * empty.
* @param callback The callback that will be called when key is available.
- * Cannot be {@code null}.
*/
public abstract void getKey(Uri origin,
- String[] algorithm,
- ValueCallback<TokenBindingKey> callback);
+ @Nullable String[] algorithm,
+ @NonNull ValueCallback<TokenBindingKey> callback);
/**
* Deletes specified key (for use when associated cookie is cleared).
*
* @param origin The origin of the server.
* @param callback The callback that will be called when key is deleted. The
* callback parameter (Boolean) will indicate if operation is
- * successful or if failed. The callback can be {@code null}.
+ * successful or if failed.
*/
public abstract void deleteKey(Uri origin,
- ValueCallback<Boolean> callback);
+ @Nullable ValueCallback<Boolean> callback);
/**
* Deletes all the keys (for use when cookies are cleared).
*
* @param callback The callback that will be called when keys are deleted.
* The callback parameter (Boolean) will indicate if operation is
- * successful or if failed. The callback can be {@code null}.
+ * successful or if failed.
*/
- public abstract void deleteAllKeys(ValueCallback<Boolean> callback);
+ public abstract void deleteAllKeys(@Nullable ValueCallback<Boolean> callback);
}
diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
index c8bfb77..c2f121a 100644
--- a/core/java/android/webkit/URLUtil.java
+++ b/core/java/android/webkit/URLUtil.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.annotation.Nullable;
import android.net.ParseException;
import android.net.Uri;
import android.net.WebAddress;
@@ -300,8 +301,8 @@
*/
public static final String guessFileName(
String url,
- String contentDisposition,
- String mimeType) {
+ @Nullable String contentDisposition,
+ @Nullable String mimeType) {
String filename = null;
String extension = null;
@@ -388,7 +389,7 @@
Pattern.compile("attachment;\\s*filename\\s*=\\s*(\"?)([^\"]*)\\1\\s*$",
Pattern.CASE_INSENSITIVE);
- /*
+ /**
* Parse the Content-Disposition HTTP Header. The format of the header
* is defined here: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html
* This header provides a filename for content that is going to be
diff --git a/core/java/android/webkit/UrlInterceptHandler.java b/core/java/android/webkit/UrlInterceptHandler.java
index aa5c6dc..0a6e51f 100644
--- a/core/java/android/webkit/UrlInterceptHandler.java
+++ b/core/java/android/webkit/UrlInterceptHandler.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.annotation.Nullable;
import android.webkit.CacheManager.CacheResult;
import android.webkit.PluginData;
@@ -35,14 +36,15 @@
* not interested.
*
* @param url URL string.
- * @param headers The headers associated with the request. May be {@code null}.
+ * @param headers The headers associated with the request.
* @return The CacheResult containing the surrogate response.
*
* @hide
* @deprecated Do not use, this interface is deprecated.
*/
@Deprecated
- public CacheResult service(String url, Map<String, String> headers);
+ @Nullable
+ CacheResult service(String url, @Nullable Map<String, String> headers);
/**
* Given an URL, returns the PluginData which contains the
@@ -50,12 +52,13 @@
* not interested.
*
* @param url URL string.
- * @param headers The headers associated with the request. May be {@code null}.
+ * @param headers The headers associated with the request.
* @return The PluginData containing the surrogate response.
*
* @hide
* @deprecated Do not use, this interface is deprecated.
*/
@Deprecated
- public PluginData getPluginData(String url, Map<String, String> headers);
+ @Nullable
+ PluginData getPluginData(String url, @Nullable Map<String, String> headers);
}
diff --git a/core/java/android/webkit/UrlInterceptRegistry.java b/core/java/android/webkit/UrlInterceptRegistry.java
index 67af2ad..700d6d9 100644
--- a/core/java/android/webkit/UrlInterceptRegistry.java
+++ b/core/java/android/webkit/UrlInterceptRegistry.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.annotation.Nullable;
import android.webkit.CacheManager.CacheResult;
import android.webkit.PluginData;
import android.webkit.UrlInterceptHandler;
@@ -121,6 +122,7 @@
* deprecated, so is this class.
*/
@Deprecated
+ @Nullable
public static synchronized CacheResult getSurrogate(
String url, Map<String, String> headers) {
if (urlInterceptDisabled()) {
@@ -149,6 +151,7 @@
* deprecated, so is this class.
*/
@Deprecated
+ @Nullable
public static synchronized PluginData getPluginData(
String url, Map<String, String> headers) {
if (urlInterceptDisabled()) {
diff --git a/core/java/android/webkit/WebBackForwardList.java b/core/java/android/webkit/WebBackForwardList.java
index 3349b06..0c34e3c 100644
--- a/core/java/android/webkit/WebBackForwardList.java
+++ b/core/java/android/webkit/WebBackForwardList.java
@@ -16,6 +16,8 @@
package android.webkit;
+import android.annotation.Nullable;
+
import java.io.Serializable;
/**
@@ -29,6 +31,7 @@
* empty.
* @return The current history item.
*/
+ @Nullable
public abstract WebHistoryItem getCurrentItem();
/**
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 742daa9..4aa1c4a 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -383,6 +384,7 @@
* @return Bitmap The image to use as a default poster, or {@code null} if no such image is
* available.
*/
+ @Nullable
public Bitmap getDefaultVideoPoster() {
return null;
}
@@ -394,6 +396,7 @@
*
* @return View The View to be displayed whilst the video is loading.
*/
+ @Nullable
public View getVideoLoadingProgressView() {
return null;
}
@@ -452,6 +455,7 @@
* @return the Uris of selected file(s) or {@code null} if the resultCode indicates
* activity canceled or any other error.
*/
+ @Nullable
public static Uri[] parseResult(int resultCode, Intent data) {
return WebViewFactory.getProvider().getStatics().parseFileChooserResult(resultCode, data);
}
@@ -477,14 +481,16 @@
public abstract boolean isCaptureEnabled();
/**
- * Returns the title to use for this file selector, or null. If {@code null} a default
- * title should be used.
+ * Returns the title to use for this file selector. If {@code null} a default title should
+ * be used.
*/
+ @Nullable
public abstract CharSequence getTitle();
/**
* The file name of a default selection if specified, or {@code null}.
*/
+ @Nullable
public abstract String getFilenameHint();
/**
diff --git a/core/java/android/webkit/WebHistoryItem.java b/core/java/android/webkit/WebHistoryItem.java
index 1591833..74db039 100644
--- a/core/java/android/webkit/WebHistoryItem.java
+++ b/core/java/android/webkit/WebHistoryItem.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.graphics.Bitmap;
@@ -70,6 +71,7 @@
* Note: The VM ensures 32-bit atomic read/write operations so we don't have
* to synchronize this method.
*/
+ @Nullable
public abstract Bitmap getFavicon();
/**
diff --git a/core/java/android/webkit/WebMessage.java b/core/java/android/webkit/WebMessage.java
index 7fe66dc..bfc00e7 100644
--- a/core/java/android/webkit/WebMessage.java
+++ b/core/java/android/webkit/WebMessage.java
@@ -16,6 +16,8 @@
package android.webkit;
+import android.annotation.Nullable;
+
/**
* The Java representation of the HTML5 PostMessage event. See
* https://html.spec.whatwg.org/multipage/comms.html#the-messageevent-interfaces
@@ -56,6 +58,7 @@
* Returns the ports that are sent with the message, or {@code null} if no port
* is sent.
*/
+ @Nullable
public WebMessagePort[] getPorts() {
return mPorts;
}
diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java
index 80c43c1..7bc7b07 100644
--- a/core/java/android/webkit/WebResourceResponse.java
+++ b/core/java/android/webkit/WebResourceResponse.java
@@ -16,12 +16,13 @@
package android.webkit;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
import java.io.InputStream;
import java.io.StringBufferInputStream;
import java.util.Map;
-import android.annotation.SystemApi;
-
/**
* Encapsulates a resource response. Applications can return an instance of this
* class from {@link WebViewClient#shouldInterceptRequest} to provide a custom
@@ -63,15 +64,15 @@
* @param encoding the resource response's encoding
* @param statusCode the status code needs to be in the ranges [100, 299], [400, 599].
* Causing a redirect by specifying a 3xx code is not supported.
- * @param reasonPhrase the phrase describing the status code, for example "OK". Must be non-null
- * and not empty.
+ * @param reasonPhrase the phrase describing the status code, for example "OK". Must be
+ * non-empty.
* @param responseHeaders the resource response's headers represented as a mapping of header
* name -> header value.
* @param data the input stream that provides the resource response's data. Must not be a
* StringBufferInputStream.
*/
public WebResourceResponse(String mimeType, String encoding, int statusCode,
- String reasonPhrase, Map<String, String> responseHeaders, InputStream data) {
+ @NonNull String reasonPhrase, Map<String, String> responseHeaders, InputStream data) {
this(mimeType, encoding, data);
setStatusCodeAndReasonPhrase(statusCode, reasonPhrase);
setResponseHeaders(responseHeaders);
@@ -121,10 +122,10 @@
*
* @param statusCode the status code needs to be in the ranges [100, 299], [400, 599].
* Causing a redirect by specifying a 3xx code is not supported.
- * @param reasonPhrase the phrase describing the status code, for example "OK". Must be non-null
- * and not empty.
+ * @param reasonPhrase the phrase describing the status code, for example "OK". Must be
+ * non-empty.
*/
- public void setStatusCodeAndReasonPhrase(int statusCode, String reasonPhrase) {
+ public void setStatusCodeAndReasonPhrase(int statusCode, @NonNull String reasonPhrase) {
checkImmutable();
if (statusCode < 100)
throw new IllegalArgumentException("statusCode can't be less than 100.");
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 22d8561..203de9c 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
@@ -1238,7 +1239,7 @@
*
* @param ua new user-agent string
*/
- public abstract void setUserAgentString(String ua);
+ public abstract void setUserAgentString(@Nullable String ua);
/**
* Gets the WebView's user-agent string.
diff --git a/core/java/android/webkit/WebSyncManager.java b/core/java/android/webkit/WebSyncManager.java
index 801be12..03b94e7 100644
--- a/core/java/android/webkit/WebSyncManager.java
+++ b/core/java/android/webkit/WebSyncManager.java
@@ -18,7 +18,7 @@
import android.content.Context;
-/*
+/**
* @deprecated The WebSyncManager no longer does anything.
*/
@Deprecated
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 3a4bfd6..077a901 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -438,7 +438,7 @@
* @deprecated Deprecated due to internal changes.
*/
@Deprecated
- public void onNewPicture(WebView view, Picture picture);
+ void onNewPicture(WebView view, @Nullable Picture picture);
}
public static class HitTestResult {
@@ -529,6 +529,7 @@
*
* @return additional type-dependant information about the result
*/
+ @Nullable
public String getExtra() {
return mExtra;
}
@@ -717,6 +718,7 @@
*
* @return the SSL certificate for the main top-level page
*/
+ @Nullable
public SslCertificate getCertificate() {
checkThread();
return mProvider.getCertificate();
@@ -785,6 +787,7 @@
* @deprecated Use {@link WebViewDatabase#getHttpAuthUsernamePassword} instead
*/
@Deprecated
+ @Nullable
public String[] getHttpAuthUsernamePassword(String host, String realm) {
checkThread();
return mProvider.getHttpAuthUsernamePassword(host, realm);
@@ -853,9 +856,10 @@
* called.
*
* @param outState the Bundle to store this WebView's state
- * @return the same copy of the back/forward list used to save the state. If
- * saveState fails, the returned list will be {@code null}.
+ * @return the same copy of the back/forward list used to save the state, {@code null} if the
+ * method fails.
*/
+ @Nullable
public WebBackForwardList saveState(Bundle outState) {
checkThread();
return mProvider.saveState(outState);
@@ -906,6 +910,7 @@
* @param inState the incoming Bundle of state
* @return the restored back/forward list or {@code null} if restoreState failed
*/
+ @Nullable
public WebBackForwardList restoreState(Bundle inState) {
checkThread();
return mProvider.restoreState(inState);
@@ -985,10 +990,11 @@
* always overrides that specified in the HTML or XML document itself.
*
* @param data a String of data in the given encoding
- * @param mimeType the MIME type of the data, e.g. 'text/html'
+ * @param mimeType the MIMEType of the data, e.g. 'text/html'. If {@code null},
+ * defaults to 'text/html'.
* @param encoding the encoding of the data
*/
- public void loadData(String data, String mimeType, String encoding) {
+ public void loadData(String data, @Nullable String mimeType, @Nullable String encoding) {
checkThread();
mProvider.loadData(data, mimeType, encoding);
}
@@ -1022,8 +1028,8 @@
* @param historyUrl the URL to use as the history entry. If {@code null} defaults
* to 'about:blank'. If non-null, this must be a valid URL.
*/
- public void loadDataWithBaseURL(String baseUrl, String data,
- String mimeType, String encoding, String historyUrl) {
+ public void loadDataWithBaseURL(@Nullable String baseUrl, String data,
+ @Nullable String mimeType, @Nullable String encoding, @Nullable String historyUrl) {
checkThread();
mProvider.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
}
@@ -1045,7 +1051,7 @@
* completes with the result of the execution (if any).
* May be {@code null} if no notification of the result is required.
*/
- public void evaluateJavascript(String script, ValueCallback<String> resultCallback) {
+ public void evaluateJavascript(String script, @Nullable ValueCallback<String> resultCallback) {
checkThread();
mProvider.evaluateJavaScript(script, resultCallback);
}
@@ -1072,7 +1078,8 @@
* under which the file was saved, or {@code null} if saving the
* file failed.
*/
- public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) {
+ public void saveWebArchive(String basename, boolean autoname, @Nullable ValueCallback<String>
+ callback) {
checkThread();
mProvider.saveWebArchive(basename, autoname, callback);
}
@@ -1395,7 +1402,7 @@
* returns the anchor's href attribute. "title" returns the
* anchor's text. "src" returns the image's src attribute.
*/
- public void requestFocusNodeHref(Message hrefMsg) {
+ public void requestFocusNodeHref(@Nullable Message hrefMsg) {
checkThread();
mProvider.requestFocusNodeHref(hrefMsg);
}
@@ -1615,10 +1622,9 @@
* shared by all the WebViews that are created by the embedder application.
*
* @param onCleared A runnable to be invoked when client certs are cleared.
- * The embedder can pass {@code null} if not interested in the
- * callback. The runnable will be called in UI thread.
+ * The runnable will be called in UI thread.
*/
- public static void clearClientCertPreferences(Runnable onCleared) {
+ public static void clearClientCertPreferences(@Nullable Runnable onCleared) {
getFactory().getStatics().clearClientCertPreferences(onCleared);
}
@@ -1640,7 +1646,8 @@
* @param callback will be called on the UI thread with {@code true} if initialization is
* successful, {@code false} otherwise.
*/
- public static void startSafeBrowsing(Context context, ValueCallback<Boolean> callback) {
+ public static void startSafeBrowsing(Context context,
+ @Nullable ValueCallback<Boolean> callback) {
getFactory().getStatics().initSafeBrowsing(context, callback);
}
@@ -1764,7 +1771,7 @@
* provides a more robust solution.
*/
@Deprecated
- public boolean showFindDialog(String text, boolean showIme) {
+ public boolean showFindDialog(@Nullable String text, boolean showIme) {
checkThread();
return mProvider.showFindDialog(text, showIme);
}
@@ -1791,6 +1798,7 @@
* @param addr the string to search for addresses
* @return the address, or if no address is found, {@code null}
*/
+ @Nullable
public static String findAddress(String addr) {
// TODO: Rewrite this in Java so it is not needed to start up chromium
// Could also be deprecated
@@ -1891,6 +1899,7 @@
* @return the WebChromeClient, or {@code null} if not yet set
* @see #setWebChromeClient
*/
+ @Nullable
public WebChromeClient getWebChromeClient() {
checkThread();
return mProvider.getWebChromeClient();
@@ -1973,7 +1982,7 @@
*
* @param name the name used to expose the object in JavaScript
*/
- public void removeJavascriptInterface(String name) {
+ public void removeJavascriptInterface(@NonNull String name) {
checkThread();
mProvider.removeJavascriptInterface(name);
}
@@ -2956,6 +2965,7 @@
* next time the app starts and loads WebView it will use the new WebView package instead.
* @return the current WebView package, or {@code null} if there is none.
*/
+ @Nullable
public static PackageInfo getCurrentWebViewPackage() {
PackageInfo webviewPackage = WebViewFactory.getLoadedPackageInfo();
if (webviewPackage != null) {
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index af7026d..c5b64eb 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.Message;
@@ -167,6 +168,7 @@
* shouldInterceptRequest(WebView, WebResourceRequest)} instead.
*/
@Deprecated
+ @Nullable
public WebResourceResponse shouldInterceptRequest(WebView view,
String url) {
return null;
@@ -191,6 +193,7 @@
* response information or {@code null} if the WebView should load the
* resource itself.
*/
+ @Nullable
public WebResourceResponse shouldInterceptRequest(WebView view,
WebResourceRequest request) {
return shouldInterceptRequest(view, request.getUrl().toString());
@@ -496,7 +499,7 @@
* @param args Authenticator specific arguments used to log in the user.
*/
public void onReceivedLoginRequest(WebView view, String realm,
- String account, String args) {
+ @Nullable String account, String args) {
}
/**
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index de75d5d0..f6166c5 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.annotation.Nullable;
import android.content.Context;
/**
@@ -135,6 +136,7 @@
* @see #hasHttpAuthUsernamePassword
* @see #clearHttpAuthUsernamePassword
*/
+ @Nullable
public abstract String[] getHttpAuthUsernamePassword(String host, String realm);
/**
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index bf25915..23ebadb 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -2296,8 +2296,8 @@
}
/** @hide */
- protected final void detachFromAnchor() {
- final View anchor = mAnchor != null ? mAnchor.get() : null;
+ protected void detachFromAnchor() {
+ final View anchor = getAnchor();
if (anchor != null) {
final ViewTreeObserver vto = anchor.getViewTreeObserver();
vto.removeOnScrollChangedListener(mOnScrollChangedListener);
@@ -2316,7 +2316,7 @@
}
/** @hide */
- protected final void attachToAnchor(View anchor, int xoff, int yoff, int gravity) {
+ protected void attachToAnchor(View anchor, int xoff, int yoff, int gravity) {
detachFromAnchor();
final ViewTreeObserver vto = anchor.getViewTreeObserver();
@@ -2339,6 +2339,11 @@
mAnchoredGravity = gravity;
}
+ /** @hide */
+ protected @Nullable View getAnchor() {
+ return mAnchor != null ? mAnchor.get() : null;
+ }
+
private void alignToAnchor() {
final View anchor = mAnchor != null ? mAnchor.get() : null;
if (anchor != null && anchor.isAttachedToWindow() && hasDecorView()) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 1653afd..1b26f8e 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -20,6 +20,7 @@
import android.annotation.ColorInt;
import android.annotation.DimenRes;
+import android.annotation.NonNull;
import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.Application;
@@ -108,9 +109,9 @@
// The unique identifiers for each custom {@link Action}.
private static final int SET_ON_CLICK_PENDING_INTENT_TAG = 1;
private static final int REFLECTION_ACTION_TAG = 2;
- private static final int SET_DRAWABLE_PARAMETERS_TAG = 3;
+ private static final int SET_DRAWABLE_TINT_TAG = 3;
private static final int VIEW_GROUP_ACTION_ADD_TAG = 4;
- private static final int SET_REFLECTION_ACTION_WITHOUT_PARAMS_TAG = 5;
+ private static final int VIEW_CONTENT_NAVIGATION_TAG = 5;
private static final int SET_EMPTY_VIEW_ACTION_TAG = 6;
private static final int VIEW_GROUP_ACTION_REMOVE_TAG = 7;
private static final int SET_PENDING_INTENT_TEMPLATE_TAG = 8;
@@ -121,7 +122,6 @@
private static final int TEXT_VIEW_SIZE_ACTION_TAG = 13;
private static final int VIEW_PADDING_ACTION_TAG = 14;
private static final int SET_REMOTE_VIEW_ADAPTER_LIST_TAG = 15;
- private static final int TEXT_VIEW_DRAWABLE_COLOR_FILTER_ACTION_TAG = 17;
private static final int SET_REMOTE_INPUTS_ACTION_TAG = 18;
private static final int LAYOUT_PARAM_ACTION_TAG = 19;
private static final int OVERRIDE_TEXT_COLORS_TAG = 20;
@@ -389,10 +389,10 @@
return MERGE_REPLACE;
}
- public abstract String getActionName();
+ public abstract int getActionTag();
public String getUniqueKey() {
- return (getActionName() + viewId);
+ return (getActionTag() + "_" + viewId);
}
/**
@@ -424,8 +424,8 @@
*/
private static abstract class RuntimeAction extends Action {
@Override
- public final String getActionName() {
- return "RuntimeAction";
+ public final int getActionTag() {
+ return 0;
}
@Override
@@ -514,7 +514,6 @@
}
private class SetEmptyView extends Action {
- int viewId;
int emptyViewId;
SetEmptyView(int viewId, int emptyViewId) {
@@ -528,7 +527,6 @@
}
public void writeToParcel(Parcel out, int flags) {
- out.writeInt(SET_EMPTY_VIEW_ACTION_TAG);
out.writeInt(this.viewId);
out.writeInt(this.emptyViewId);
}
@@ -546,8 +544,9 @@
adapterView.setEmptyView(emptyView);
}
- public String getActionName() {
- return "SetEmptyView";
+ @Override
+ public int getActionTag() {
+ return SET_EMPTY_VIEW_ACTION_TAG;
}
}
@@ -559,13 +558,12 @@
public SetOnClickFillInIntent(Parcel parcel) {
viewId = parcel.readInt();
- fillInIntent = Intent.CREATOR.createFromParcel(parcel);
+ fillInIntent = parcel.readTypedObject(Intent.CREATOR);
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(SET_ON_CLICK_FILL_IN_INTENT_TAG);
dest.writeInt(viewId);
- fillInIntent.writeToParcel(dest, 0 /* no flags */);
+ dest.writeTypedObject(fillInIntent, 0 /* no flags */);
}
@Override
@@ -624,8 +622,9 @@
}
}
- public String getActionName() {
- return "SetOnClickFillInIntent";
+ @Override
+ public int getActionTag() {
+ return SET_ON_CLICK_FILL_IN_INTENT_TAG;
}
Intent fillInIntent;
@@ -643,9 +642,8 @@
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(SET_PENDING_INTENT_TEMPLATE_TAG);
dest.writeInt(viewId);
- pendingIntentTemplate.writeToParcel(dest, 0 /* no flags */);
+ PendingIntent.writePendingIntentOrNullToParcel(pendingIntentTemplate, dest);
}
@Override
@@ -699,8 +697,9 @@
}
}
- public String getActionName() {
- return "SetPendingIntentTemplate";
+ @Override
+ public int getActionTag() {
+ return SET_PENDING_INTENT_TEMPLATE_TAG;
}
PendingIntent pendingIntentTemplate;
@@ -716,30 +715,13 @@
public SetRemoteViewsAdapterList(Parcel parcel) {
viewId = parcel.readInt();
viewTypeCount = parcel.readInt();
- int count = parcel.readInt();
- list = new ArrayList<RemoteViews>();
-
- for (int i = 0; i < count; i++) {
- RemoteViews rv = RemoteViews.CREATOR.createFromParcel(parcel);
- list.add(rv);
- }
+ list = parcel.createTypedArrayList(RemoteViews.CREATOR);
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(SET_REMOTE_VIEW_ADAPTER_LIST_TAG);
dest.writeInt(viewId);
dest.writeInt(viewTypeCount);
-
- if (list == null || list.size() == 0) {
- dest.writeInt(0);
- } else {
- int count = list.size();
- dest.writeInt(count);
- for (int i = 0; i < count; i++) {
- RemoteViews rv = list.get(i);
- rv.writeToParcel(dest, flags);
- }
- }
+ dest.writeTypedList(list, flags);
}
@Override
@@ -779,8 +761,9 @@
}
}
- public String getActionName() {
- return "SetRemoteViewsAdapterList";
+ @Override
+ public int getActionTag() {
+ return SET_REMOTE_VIEW_ADAPTER_LIST_TAG;
}
int viewTypeCount;
@@ -795,13 +778,12 @@
public SetRemoteViewsAdapterIntent(Parcel parcel) {
viewId = parcel.readInt();
- intent = Intent.CREATOR.createFromParcel(parcel);
+ intent = parcel.readTypedObject(Intent.CREATOR);
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(SET_REMOTE_VIEW_ADAPTER_INTENT_TAG);
dest.writeInt(viewId);
- intent.writeToParcel(dest, flags);
+ dest.writeTypedObject(intent, flags);
}
@Override
@@ -845,8 +827,9 @@
return copy;
}
- public String getActionName() {
- return "SetRemoteViewsAdapterIntent";
+ @Override
+ public int getActionTag() {
+ return SET_REMOTE_VIEW_ADAPTER_INTENT_TAG;
}
Intent intent;
@@ -866,22 +849,12 @@
public SetOnClickPendingIntent(Parcel parcel) {
viewId = parcel.readInt();
-
- // We check a flag to determine if the parcel contains a PendingIntent.
- if (parcel.readInt() != 0) {
- pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
- }
+ pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(SET_ON_CLICK_PENDING_INTENT_TAG);
dest.writeInt(viewId);
-
- // We use a flag to indicate whether the parcel contains a valid object.
- dest.writeInt(pendingIntent != null ? 1 : 0);
- if (pendingIntent != null) {
- pendingIntent.writeToParcel(dest, 0 /* no flags */);
- }
+ PendingIntent.writePendingIntentOrNullToParcel(pendingIntent, dest);
}
@Override
@@ -922,8 +895,9 @@
target.setOnClickListener(listener);
}
- public String getActionName() {
- return "SetOnClickPendingIntent";
+ @Override
+ public int getActionTag() {
+ return SET_ON_CLICK_PENDING_INTENT_TAG;
}
PendingIntent pendingIntent;
@@ -1012,55 +986,37 @@
}
/**
- * Equivalent to calling a combination of {@link Drawable#setAlpha(int)},
+ * Equivalent to calling
* {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)},
- * and/or {@link Drawable#setLevel(int)} on the {@link Drawable} of a given view.
+ * on the {@link Drawable} of a given view.
* <p>
- * These operations will be performed on the {@link Drawable} returned by the
+ * The operation will be performed on the {@link Drawable} returned by the
* target {@link View#getBackground()} by default. If targetBackground is false,
* we assume the target is an {@link ImageView} and try applying the operations
* to {@link ImageView#getDrawable()}.
* <p>
- * You can omit specific calls by marking their values with null or -1.
*/
- private class SetDrawableParameters extends Action {
- public SetDrawableParameters(int id, boolean targetBackground, int alpha,
- int colorFilter, PorterDuff.Mode mode, int level) {
+ private class SetDrawableTint extends Action {
+ SetDrawableTint(int id, boolean targetBackground,
+ int colorFilter, @NonNull PorterDuff.Mode mode) {
this.viewId = id;
this.targetBackground = targetBackground;
- this.alpha = alpha;
this.colorFilter = colorFilter;
this.filterMode = mode;
- this.level = level;
}
- public SetDrawableParameters(Parcel parcel) {
+ SetDrawableTint(Parcel parcel) {
viewId = parcel.readInt();
targetBackground = parcel.readInt() != 0;
- alpha = parcel.readInt();
colorFilter = parcel.readInt();
- boolean hasMode = parcel.readInt() != 0;
- if (hasMode) {
- filterMode = PorterDuff.Mode.valueOf(parcel.readString());
- } else {
- filterMode = null;
- }
- level = parcel.readInt();
+ filterMode = PorterDuff.intToMode(parcel.readInt());
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(SET_DRAWABLE_PARAMETERS_TAG);
dest.writeInt(viewId);
dest.writeInt(targetBackground ? 1 : 0);
- dest.writeInt(alpha);
dest.writeInt(colorFilter);
- if (filterMode != null) {
- dest.writeInt(1);
- dest.writeString(filterMode.toString());
- } else {
- dest.writeInt(0);
- }
- dest.writeInt(level);
+ dest.writeInt(PorterDuff.modeToInt(filterMode));
}
@Override
@@ -1078,47 +1034,36 @@
}
if (targetDrawable != null) {
- // Perform modifications only if values are set correctly
- if (alpha != -1) {
- targetDrawable.mutate().setAlpha(alpha);
- }
- if (filterMode != null) {
- targetDrawable.mutate().setColorFilter(colorFilter, filterMode);
- }
- if (level != -1) {
- targetDrawable.mutate().setLevel(level);
- }
+ targetDrawable.mutate().setColorFilter(colorFilter, filterMode);
}
}
- public String getActionName() {
- return "SetDrawableParameters";
+ @Override
+ public int getActionTag() {
+ return SET_DRAWABLE_TINT_TAG;
}
boolean targetBackground;
- int alpha;
int colorFilter;
PorterDuff.Mode filterMode;
- int level;
}
- private final class ReflectionActionWithoutParams extends Action {
- final String methodName;
+ private final class ViewContentNavigation extends Action {
+ final boolean mNext;
- ReflectionActionWithoutParams(int viewId, String methodName) {
+ ViewContentNavigation(int viewId, boolean next) {
this.viewId = viewId;
- this.methodName = methodName;
+ this.mNext = next;
}
- ReflectionActionWithoutParams(Parcel in) {
+ ViewContentNavigation(Parcel in) {
this.viewId = in.readInt();
- this.methodName = in.readString();
+ this.mNext = in.readBoolean();
}
public void writeToParcel(Parcel out, int flags) {
- out.writeInt(SET_REFLECTION_ACTION_WITHOUT_PARAMS_TAG);
out.writeInt(this.viewId);
- out.writeString(this.methodName);
+ out.writeBoolean(this.mNext);
}
@Override
@@ -1127,23 +1072,20 @@
if (view == null) return;
try {
- getMethod(view, this.methodName, null, false /* async */).invoke(view);
+ getMethod(view,
+ mNext ? "showNext" : "showPrevious", null, false /* async */).invoke(view);
} catch (Throwable ex) {
throw new ActionException(ex);
}
}
public int mergeBehavior() {
- // we don't need to build up showNext or showPrevious calls
- if (methodName.equals("showNext") || methodName.equals("showPrevious")) {
- return MERGE_IGNORE;
- } else {
- return MERGE_REPLACE;
- }
+ return MERGE_IGNORE;
}
- public String getActionName() {
- return "ReflectionActionWithoutParams";
+ @Override
+ public int getActionTag() {
+ return VIEW_CONTENT_NAVIGATION_TAG;
}
}
@@ -1157,12 +1099,7 @@
}
public BitmapCache(Parcel source) {
- int count = source.readInt();
- mBitmaps = new ArrayList<>(count);
- for (int i = 0; i < count; i++) {
- Bitmap b = Bitmap.CREATOR.createFromParcel(source);
- mBitmaps.add(b);
- }
+ mBitmaps = source.createTypedArrayList(Bitmap.CREATOR);
}
public int getBitmapId(Bitmap b) {
@@ -1188,11 +1125,7 @@
}
public void writeBitmapsToParcel(Parcel dest, int flags) {
- int count = mBitmaps.size();
- dest.writeInt(count);
- for (int i = 0; i < count; i++) {
- mBitmaps.get(i).writeToParcel(dest, flags);
- }
+ dest.writeTypedList(mBitmaps, flags);
}
public int getBitmapMemory() {
@@ -1228,7 +1161,6 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(BITMAP_REFLECTION_ACTION_TAG);
dest.writeInt(viewId);
dest.writeString(methodName);
dest.writeInt(bitmapId);
@@ -1247,8 +1179,9 @@
bitmapId = bitmapCache.getBitmapId(bitmap);
}
- public String getActionName() {
- return "BitmapReflectionAction";
+ @Override
+ public int getActionTag() {
+ return BITMAP_REFLECTION_ACTION_TAG;
}
}
@@ -1300,7 +1233,7 @@
// written to the parcel.
switch (this.type) {
case BOOLEAN:
- this.value = in.readInt() != 0;
+ this.value = in.readBoolean();
break;
case BYTE:
this.value = in.readByte();
@@ -1330,39 +1263,28 @@
this.value = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
break;
case URI:
- if (in.readInt() != 0) {
- this.value = Uri.CREATOR.createFromParcel(in);
- }
+ this.value = in.readTypedObject(Uri.CREATOR);
break;
case BITMAP:
- if (in.readInt() != 0) {
- this.value = Bitmap.CREATOR.createFromParcel(in);
- }
+ this.value = in.readTypedObject(Bitmap.CREATOR);
break;
case BUNDLE:
this.value = in.readBundle();
break;
case INTENT:
- if (in.readInt() != 0) {
- this.value = Intent.CREATOR.createFromParcel(in);
- }
+ this.value = in.readTypedObject(Intent.CREATOR);
break;
case COLOR_STATE_LIST:
- if (in.readInt() != 0) {
- this.value = ColorStateList.CREATOR.createFromParcel(in);
- }
+ this.value = in.readTypedObject(ColorStateList.CREATOR);
break;
case ICON:
- if (in.readInt() != 0) {
- this.value = Icon.CREATOR.createFromParcel(in);
- }
+ this.value = in.readTypedObject(Icon.CREATOR);
default:
break;
}
}
public void writeToParcel(Parcel out, int flags) {
- out.writeInt(REFLECTION_ACTION_TAG);
out.writeInt(this.viewId);
out.writeString(this.methodName);
out.writeInt(this.type);
@@ -1376,7 +1298,7 @@
// we have written a valid value to the parcel.
switch (this.type) {
case BOOLEAN:
- out.writeInt((Boolean) this.value ? 1 : 0);
+ out.writeBoolean((Boolean) this.value);
break;
case BYTE:
out.writeByte((Byte) this.value);
@@ -1413,10 +1335,7 @@
case INTENT:
case COLOR_STATE_LIST:
case ICON:
- out.writeInt(this.value != null ? 1 : 0);
- if (this.value != null) {
- ((Parcelable) this.value).writeToParcel(out, flags);
- }
+ out.writeTypedObject((Parcelable) this.value, flags);
break;
default:
break;
@@ -1522,10 +1441,16 @@
}
}
- public String getActionName() {
+ @Override
+ public int getActionTag() {
+ return REFLECTION_ACTION_TAG;
+ }
+
+ @Override
+ public String getUniqueKey() {
// Each type of reflection action corresponds to a setter, so each should be seen as
// unique from the standpoint of merging.
- return "ReflectionAction" + this.methodName + this.type;
+ return super.getUniqueKey() + this.methodName + this.type;
}
@Override
@@ -1587,7 +1512,6 @@
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(VIEW_GROUP_ACTION_ADD_TAG);
dest.writeInt(viewId);
dest.writeInt(mIndex);
mNestedViews.writeToParcel(dest, flags);
@@ -1662,10 +1586,9 @@
return mNestedViews.prefersAsyncApply();
}
-
@Override
- public String getActionName() {
- return "ViewGroupActionAdd";
+ public int getActionTag() {
+ return VIEW_GROUP_ACTION_ADD_TAG;
}
}
@@ -1697,7 +1620,6 @@
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(VIEW_GROUP_ACTION_REMOVE_TAG);
dest.writeInt(viewId);
dest.writeInt(mViewIdToKeep);
}
@@ -1763,8 +1685,8 @@
}
@Override
- public String getActionName() {
- return "ViewGroupActionRemove";
+ public int getActionTag() {
+ return VIEW_GROUP_ACTION_REMOVE_TAG;
}
@Override
@@ -1804,18 +1726,10 @@
isRelative = (parcel.readInt() != 0);
useIcons = (parcel.readInt() != 0);
if (useIcons) {
- if (parcel.readInt() != 0) {
- i1 = Icon.CREATOR.createFromParcel(parcel);
- }
- if (parcel.readInt() != 0) {
- i2 = Icon.CREATOR.createFromParcel(parcel);
- }
- if (parcel.readInt() != 0) {
- i3 = Icon.CREATOR.createFromParcel(parcel);
- }
- if (parcel.readInt() != 0) {
- i4 = Icon.CREATOR.createFromParcel(parcel);
- }
+ i1 = parcel.readTypedObject(Icon.CREATOR);
+ i2 = parcel.readTypedObject(Icon.CREATOR);
+ i3 = parcel.readTypedObject(Icon.CREATOR);
+ i4 = parcel.readTypedObject(Icon.CREATOR);
} else {
d1 = parcel.readInt();
d2 = parcel.readInt();
@@ -1825,35 +1739,14 @@
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(TEXT_VIEW_DRAWABLE_ACTION_TAG);
dest.writeInt(viewId);
dest.writeInt(isRelative ? 1 : 0);
dest.writeInt(useIcons ? 1 : 0);
if (useIcons) {
- if (i1 != null) {
- dest.writeInt(1);
- i1.writeToParcel(dest, 0);
- } else {
- dest.writeInt(0);
- }
- if (i2 != null) {
- dest.writeInt(1);
- i2.writeToParcel(dest, 0);
- } else {
- dest.writeInt(0);
- }
- if (i3 != null) {
- dest.writeInt(1);
- i3.writeToParcel(dest, 0);
- } else {
- dest.writeInt(0);
- }
- if (i4 != null) {
- dest.writeInt(1);
- i4.writeToParcel(dest, 0);
- } else {
- dest.writeInt(0);
- }
+ dest.writeTypedObject(i1, 0);
+ dest.writeTypedObject(i2, 0);
+ dest.writeTypedObject(i3, 0);
+ dest.writeTypedObject(i4, 0);
} else {
dest.writeInt(d1);
dest.writeInt(d2);
@@ -1924,8 +1817,9 @@
return useIcons;
}
- public String getActionName() {
- return "TextViewDrawableAction";
+ @Override
+ public int getActionTag() {
+ return TEXT_VIEW_DRAWABLE_ACTION_TAG;
}
boolean isRelative = false;
@@ -1954,7 +1848,6 @@
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(TEXT_VIEW_SIZE_ACTION_TAG);
dest.writeInt(viewId);
dest.writeInt(units);
dest.writeFloat(size);
@@ -1967,8 +1860,9 @@
target.setTextSize(units, size);
}
- public String getActionName() {
- return "TextViewSizeAction";
+ @Override
+ public int getActionTag() {
+ return TEXT_VIEW_SIZE_ACTION_TAG;
}
int units;
@@ -1996,7 +1890,6 @@
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(VIEW_PADDING_ACTION_TAG);
dest.writeInt(viewId);
dest.writeInt(left);
dest.writeInt(top);
@@ -2011,8 +1904,9 @@
target.setPadding(left, top, right, bottom);
}
- public String getActionName() {
- return "ViewPaddingAction";
+ @Override
+ public int getActionTag() {
+ return VIEW_PADDING_ACTION_TAG;
}
int left, top, right, bottom;
@@ -2029,6 +1923,9 @@
public static final int LAYOUT_WIDTH = 2;
public static final int LAYOUT_MARGIN_BOTTOM_DIMEN = 3;
+ final int mProperty;
+ final int mValue;
+
/**
* @param viewId ID of the view alter
* @param property which layout parameter to alter
@@ -2036,21 +1933,20 @@
*/
public LayoutParamAction(int viewId, int property, int value) {
this.viewId = viewId;
- this.property = property;
- this.value = value;
+ this.mProperty = property;
+ this.mValue = value;
}
public LayoutParamAction(Parcel parcel) {
viewId = parcel.readInt();
- property = parcel.readInt();
- value = parcel.readInt();
+ mProperty = parcel.readInt();
+ mValue = parcel.readInt();
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(LAYOUT_PARAM_ACTION_TAG);
dest.writeInt(viewId);
- dest.writeInt(property);
- dest.writeInt(value);
+ dest.writeInt(mProperty);
+ dest.writeInt(mValue);
}
@Override
@@ -2063,27 +1959,27 @@
if (layoutParams == null) {
return;
}
- switch (property) {
+ switch (mProperty) {
case LAYOUT_MARGIN_END_DIMEN:
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
- int resolved = resolveDimenPixelOffset(target, value);
+ int resolved = resolveDimenPixelOffset(target, mValue);
((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(resolved);
target.setLayoutParams(layoutParams);
}
break;
case LAYOUT_MARGIN_BOTTOM_DIMEN:
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
- int resolved = resolveDimenPixelOffset(target, value);
+ int resolved = resolveDimenPixelOffset(target, mValue);
((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin = resolved;
target.setLayoutParams(layoutParams);
}
break;
case LAYOUT_WIDTH:
- layoutParams.width = value;
+ layoutParams.width = mValue;
target.setLayoutParams(layoutParams);
break;
default:
- throw new IllegalArgumentException("Unknown property " + property);
+ throw new IllegalArgumentException("Unknown property " + mProperty);
}
}
@@ -2094,79 +1990,15 @@
return target.getContext().getResources().getDimensionPixelOffset(value);
}
- public String getActionName() {
- return "LayoutParamAction" + property + ".";
- }
-
- int property;
- int value;
- }
-
- /**
- * Helper action to set a color filter on a compound drawable on a TextView. Supports relative
- * (s/t/e/b) or cardinal (l/t/r/b) arrangement.
- */
- private class TextViewDrawableColorFilterAction extends Action {
- public TextViewDrawableColorFilterAction(int viewId, boolean isRelative, int index,
- int color, PorterDuff.Mode mode) {
- this.viewId = viewId;
- this.isRelative = isRelative;
- this.index = index;
- this.color = color;
- this.mode = mode;
- }
-
- public TextViewDrawableColorFilterAction(Parcel parcel) {
- viewId = parcel.readInt();
- isRelative = (parcel.readInt() != 0);
- index = parcel.readInt();
- color = parcel.readInt();
- mode = readPorterDuffMode(parcel);
- }
-
- private PorterDuff.Mode readPorterDuffMode(Parcel parcel) {
- int mode = parcel.readInt();
- if (mode >= 0 && mode < PorterDuff.Mode.values().length) {
- return PorterDuff.Mode.values()[mode];
- } else {
- return PorterDuff.Mode.CLEAR;
- }
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(TEXT_VIEW_DRAWABLE_COLOR_FILTER_ACTION_TAG);
- dest.writeInt(viewId);
- dest.writeInt(isRelative ? 1 : 0);
- dest.writeInt(index);
- dest.writeInt(color);
- dest.writeInt(mode.ordinal());
+ @Override
+ public int getActionTag() {
+ return LAYOUT_PARAM_ACTION_TAG;
}
@Override
- public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
- final TextView target = root.findViewById(viewId);
- if (target == null) return;
- Drawable[] drawables = isRelative
- ? target.getCompoundDrawablesRelative()
- : target.getCompoundDrawables();
- if (index < 0 || index >= 4) {
- throw new IllegalStateException("index must be in range [0, 3].");
- }
- Drawable d = drawables[index];
- if (d != null) {
- d.mutate();
- d.setColorFilter(color, mode);
- }
+ public String getUniqueKey() {
+ return super.getUniqueKey() + mProperty;
}
-
- public String getActionName() {
- return "TextViewDrawableColorFilterAction";
- }
-
- final boolean isRelative;
- final int index;
- final int color;
- final PorterDuff.Mode mode;
}
/**
@@ -2185,7 +2017,6 @@
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(SET_REMOTE_INPUTS_ACTION_TAG);
dest.writeInt(viewId);
dest.writeTypedArray(remoteInputs, flags);
}
@@ -2198,8 +2029,9 @@
target.setTagInternal(R.id.remote_input_tag, remoteInputs);
}
- public String getActionName() {
- return "SetRemoteInputsAction";
+ @Override
+ public int getActionTag() {
+ return SET_REMOTE_INPUTS_ACTION_TAG;
}
final Parcelable[] remoteInputs;
@@ -2221,7 +2053,6 @@
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(OVERRIDE_TEXT_COLORS_TAG);
dest.writeInt(textColor);
}
@@ -2246,8 +2077,9 @@
}
}
- public String getActionName() {
- return "OverrideTextColorsAction";
+ @Override
+ public int getActionTag() {
+ return OVERRIDE_TEXT_COLORS_TAG;
}
}
@@ -2340,7 +2172,7 @@
if (src.mActions != null) {
Parcel p = Parcel.obtain();
- writeActionsToParcel(p);
+ src.writeActionsToParcel(p);
p.setDataPosition(0);
// Since src is already in memory, we do not care about stack overflow as it has
// already been read once.
@@ -2411,16 +2243,16 @@
switch (tag) {
case SET_ON_CLICK_PENDING_INTENT_TAG:
return new SetOnClickPendingIntent(parcel);
- case SET_DRAWABLE_PARAMETERS_TAG:
- return new SetDrawableParameters(parcel);
+ case SET_DRAWABLE_TINT_TAG:
+ return new SetDrawableTint(parcel);
case REFLECTION_ACTION_TAG:
return new ReflectionAction(parcel);
case VIEW_GROUP_ACTION_ADD_TAG:
return new ViewGroupActionAdd(parcel, mBitmapCache, mApplication, depth);
case VIEW_GROUP_ACTION_REMOVE_TAG:
return new ViewGroupActionRemove(parcel);
- case SET_REFLECTION_ACTION_WITHOUT_PARAMS_TAG:
- return new ReflectionActionWithoutParams(parcel);
+ case VIEW_CONTENT_NAVIGATION_TAG:
+ return new ViewContentNavigation(parcel);
case SET_EMPTY_VIEW_ACTION_TAG:
return new SetEmptyView(parcel);
case SET_PENDING_INTENT_TEMPLATE_TAG:
@@ -2439,8 +2271,6 @@
return new BitmapReflectionAction(parcel);
case SET_REMOTE_VIEW_ADAPTER_LIST_TAG:
return new SetRemoteViewsAdapterList(parcel);
- case TEXT_VIEW_DRAWABLE_COLOR_FILTER_ACTION_TAG:
- return new TextViewDrawableColorFilterAction(parcel);
case SET_REMOTE_INPUTS_ACTION_TAG:
return new SetRemoteInputsAction(parcel);
case LAYOUT_PARAM_ACTION_TAG:
@@ -2597,7 +2427,7 @@
* @param viewId The id of the view on which to call {@link AdapterViewAnimator#showNext()}
*/
public void showNext(int viewId) {
- addAction(new ReflectionActionWithoutParams(viewId, "showNext"));
+ addAction(new ViewContentNavigation(viewId, true /* next */));
}
/**
@@ -2606,7 +2436,7 @@
* @param viewId The id of the view on which to call {@link AdapterViewAnimator#showPrevious()}
*/
public void showPrevious(int viewId) {
- addAction(new ReflectionActionWithoutParams(viewId, "showPrevious"));
+ addAction(new ViewContentNavigation(viewId, false /* next */));
}
/**
@@ -2680,28 +2510,6 @@
}
/**
- * Equivalent to applying a color filter on one of the drawables in
- * {@link android.widget.TextView#getCompoundDrawablesRelative()}.
- *
- * @param viewId The id of the view whose text should change.
- * @param index The index of the drawable in the array of
- * {@link android.widget.TextView#getCompoundDrawablesRelative()} to set the color
- * filter on. Must be in [0, 3].
- * @param color The color of the color filter. See
- * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}.
- * @param mode The mode of the color filter. See
- * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}.
- * @hide
- */
- public void setTextViewCompoundDrawablesRelativeColorFilter(int viewId,
- int index, int color, PorterDuff.Mode mode) {
- if (index < 0 || index >= 4) {
- throw new IllegalArgumentException("index must be in range [0, 3].");
- }
- addAction(new TextViewDrawableColorFilterAction(viewId, true, index, color, mode));
- }
-
- /**
* Equivalent to calling {@link
* TextView#setCompoundDrawablesWithIntrinsicBounds(Drawable, Drawable, Drawable, Drawable)}
* using the drawables yielded by {@link Icon#loadDrawable(Context)}.
@@ -2898,12 +2706,10 @@
/**
* @hide
- * Equivalent to calling a combination of {@link Drawable#setAlpha(int)},
+ * Equivalent to calling
* {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)},
- * and/or {@link Drawable#setLevel(int)} on the {@link Drawable} of a given
- * view.
+ * on the {@link Drawable} of a given view.
* <p>
- * You can omit specific calls by marking their values with null or -1.
*
* @param viewId The id of the view that contains the target
* {@link Drawable}
@@ -2912,20 +2718,15 @@
* {@link android.view.View#getBackground()}. Otherwise, assume
* the target view is an {@link ImageView} and apply them to
* {@link ImageView#getDrawable()}.
- * @param alpha Specify an alpha value for the drawable, or -1 to leave
- * unchanged.
* @param colorFilter Specify a color for a
* {@link android.graphics.ColorFilter} for this drawable. This will be ignored if
* {@code mode} is {@code null}.
* @param mode Specify a PorterDuff mode for this drawable, or null to leave
* unchanged.
- * @param level Specify the level for the drawable, or -1 to leave
- * unchanged.
*/
- public void setDrawableParameters(int viewId, boolean targetBackground, int alpha,
- int colorFilter, PorterDuff.Mode mode, int level) {
- addAction(new SetDrawableParameters(viewId, targetBackground, alpha,
- colorFilter, mode, level));
+ public void setDrawableTint(int viewId, boolean targetBackground,
+ int colorFilter, @NonNull PorterDuff.Mode mode) {
+ addAction(new SetDrawableTint(viewId, targetBackground, colorFilter, mode));
}
/**
@@ -3717,6 +3518,7 @@
parcel.writeInt(count);
for (int i = 0; i < count; i++) {
Action a = mActions.get(i);
+ parcel.writeInt(a.getActionTag());
a.writeToParcel(parcel, a.hasSameAppInfo(mApplication)
? PARCELABLE_ELIDE_DUPLICATES : 0);
}
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 1b93352..3be42a5 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -43,9 +43,11 @@
import java.text.BreakIterator;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Pattern;
@@ -60,12 +62,6 @@
private static final String LOG_TAG = "SelectActionModeHelper";
- /**
- * Maximum time (in milliseconds) to wait for a result before timing out.
- */
- // TODO: Consider making this a ViewConfiguration.
- private static final int TIMEOUT_DURATION = 200;
-
private static final boolean SMART_SELECT_ANIMATION_ENABLED = true;
private final Editor mEditor;
@@ -85,7 +81,8 @@
mEditor = Preconditions.checkNotNull(editor);
mTextView = mEditor.getTextView();
mTextClassificationHelper = new TextClassificationHelper(
- mTextView.getTextClassifier(), mTextView.getText(),
+ mTextView.getTextClassifier(),
+ getText(mTextView),
0, 1, mTextView.getTextLocales());
mSelectionTracker = new SelectionTracker(mTextView);
@@ -99,7 +96,7 @@
public void startActionModeAsync(boolean adjustSelection) {
mSelectionTracker.onOriginalSelection(
- mTextView.getText(),
+ getText(mTextView),
mTextView.getSelectionStart(),
mTextView.getSelectionEnd(),
mTextView.isTextEditable());
@@ -110,7 +107,7 @@
resetTextClassificationHelper();
mTextClassificationAsyncTask = new TextClassificationAsyncTask(
mTextView,
- TIMEOUT_DURATION,
+ mTextClassificationHelper.getTimeoutDuration(),
adjustSelection
? mTextClassificationHelper::suggestSelection
: mTextClassificationHelper::classifyText,
@@ -129,7 +126,7 @@
resetTextClassificationHelper();
mTextClassificationAsyncTask = new TextClassificationAsyncTask(
mTextView,
- TIMEOUT_DURATION,
+ mTextClassificationHelper.getTimeoutDuration(),
mTextClassificationHelper::classifyText,
this::invalidateActionMode)
.execute();
@@ -197,7 +194,7 @@
}
private void startActionMode(@Nullable SelectionResult result) {
- final CharSequence text = mTextView.getText();
+ final CharSequence text = getText(mTextView);
if (result != null && text instanceof Spannable) {
Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
mTextClassification = result.mClassification;
@@ -231,7 +228,7 @@
return;
}
- final List<RectF> selectionRectangles =
+ final List<SmartSelectSprite.RectangleWithTextSelectionLayout> selectionRectangles =
convertSelectionToRectangles(layout, result.mStart, result.mEnd);
final PointF touchPoint = new PointF(
@@ -239,7 +236,8 @@
mEditor.getLastUpPositionY());
final PointF animationStartPoint =
- movePointInsideNearestRectangle(touchPoint, selectionRectangles);
+ movePointInsideNearestRectangle(touchPoint, selectionRectangles,
+ SmartSelectSprite.RectangleWithTextSelectionLayout::getRectangle);
mSmartSelectSprite.startAnimation(
animationStartPoint,
@@ -247,38 +245,58 @@
onAnimationEndCallback);
}
- private List<RectF> convertSelectionToRectangles(final Layout layout, final int start,
- final int end) {
- final List<RectF> result = new ArrayList<>();
- layout.getSelection(start, end, (left, top, right, bottom, textSelectionLayout) ->
- mergeRectangleIntoList(result, new RectF(left, top, right, bottom)));
+ private List<SmartSelectSprite.RectangleWithTextSelectionLayout> convertSelectionToRectangles(
+ final Layout layout, final int start, final int end) {
+ final List<SmartSelectSprite.RectangleWithTextSelectionLayout> result = new ArrayList<>();
- result.sort(SmartSelectSprite.RECTANGLE_COMPARATOR);
+ final Layout.SelectionRectangleConsumer consumer =
+ (left, top, right, bottom, textSelectionLayout) -> mergeRectangleIntoList(
+ result,
+ new RectF(left, top, right, bottom),
+ SmartSelectSprite.RectangleWithTextSelectionLayout::getRectangle,
+ r -> new SmartSelectSprite.RectangleWithTextSelectionLayout(r,
+ textSelectionLayout)
+ );
+
+ layout.getSelection(start, end, consumer);
+
+ result.sort(Comparator.comparing(
+ SmartSelectSprite.RectangleWithTextSelectionLayout::getRectangle,
+ SmartSelectSprite.RECTANGLE_COMPARATOR));
+
return result;
}
+ // TODO: Move public pure functions out of this class and make it package-private.
/**
- * Merges a {@link RectF} into an existing list of rectangles. While merging, this method
- * makes sure that:
+ * Merges a {@link RectF} into an existing list of any objects which contain a rectangle.
+ * While merging, this method makes sure that:
*
* <ol>
* <li>No rectangle is redundant (contained within a bigger rectangle)</li>
* <li>Rectangles of the same height and vertical position that intersect get merged</li>
* </ol>
*
- * @param list the list of rectangles to merge the new rectangle in
+ * @param list the list of rectangles (or other rectangle containers) to merge the new
+ * rectangle into
* @param candidate the {@link RectF} to merge into the list
+ * @param extractor a function that can extract a {@link RectF} from an element of the given
+ * list
+ * @param packer a function that can wrap the resulting {@link RectF} into an element that
+ * the list contains
* @hide
*/
@VisibleForTesting
- public static void mergeRectangleIntoList(List<RectF> list, RectF candidate) {
+ public static <T> void mergeRectangleIntoList(final List<T> list,
+ final RectF candidate, final Function<T, RectF> extractor,
+ final Function<RectF, T> packer) {
if (candidate.isEmpty()) {
return;
}
final int elementCount = list.size();
for (int index = 0; index < elementCount; ++index) {
- final RectF existingRectangle = list.get(index);
+ final RectF existingRectangle = extractor.apply(list.get(index));
if (existingRectangle.contains(candidate)) {
return;
}
@@ -301,26 +319,27 @@
}
for (int index = elementCount - 1; index >= 0; --index) {
- if (list.get(index).isEmpty()) {
+ final RectF rectangle = extractor.apply(list.get(index));
+ if (rectangle.isEmpty()) {
list.remove(index);
}
}
- list.add(candidate);
+ list.add(packer.apply(candidate));
}
/** @hide */
@VisibleForTesting
- public static PointF movePointInsideNearestRectangle(final PointF point,
- final List<RectF> rectangles) {
+ public static <T> PointF movePointInsideNearestRectangle(final PointF point,
+ final List<T> list, final Function<T, RectF> extractor) {
float bestX = -1;
float bestY = -1;
double bestDistance = Double.MAX_VALUE;
- final int elementCount = rectangles.size();
+ final int elementCount = list.size();
for (int index = 0; index < elementCount; ++index) {
- final RectF rectangle = rectangles.get(index);
+ final RectF rectangle = extractor.apply(list.get(index));
final float candidateY = rectangle.centerY();
final float candidateX;
@@ -358,7 +377,9 @@
}
private void resetTextClassificationHelper() {
- mTextClassificationHelper.reset(mTextView.getTextClassifier(), mTextView.getText(),
+ mTextClassificationHelper.reset(
+ mTextView.getTextClassifier(),
+ getText(mTextView),
mTextView.getSelectionStart(), mTextView.getSelectionEnd(),
mTextView.getTextLocales());
}
@@ -467,7 +488,7 @@
if (isSelectionStarted()
&& mAllowReset
&& textIndex >= mSelectionStart && textIndex <= mSelectionEnd
- && textView.getText() instanceof Spannable) {
+ && getText(textView) instanceof Spannable) {
mAllowReset = false;
boolean selected = editor.selectCurrentWord();
if (selected) {
@@ -723,7 +744,7 @@
mSelectionResultSupplier = Preconditions.checkNotNull(selectionResultSupplier);
mSelectionResultCallback = Preconditions.checkNotNull(selectionResultCallback);
// Make a copy of the original text.
- mOriginalText = mTextView.getText().toString();
+ mOriginalText = getText(mTextView).toString();
}
@Override
@@ -739,7 +760,7 @@
@Override
@UiThread
protected void onPostExecute(SelectionResult result) {
- result = TextUtils.equals(mOriginalText, mTextView.getText()) ? result : null;
+ result = TextUtils.equals(mOriginalText, getText(mTextView)) ? result : null;
mSelectionResultCallback.accept(result);
}
@@ -786,6 +807,9 @@
private LocaleList mLastClassificationLocales;
private SelectionResult mLastClassificationResult;
+ /** Whether the TextClassifier has been initialized. */
+ private boolean mHot;
+
TextClassificationHelper(TextClassifier textClassifier,
CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
reset(textClassifier, text, selectionStart, selectionEnd, locales);
@@ -805,11 +829,13 @@
@WorkerThread
public SelectionResult classifyText() {
+ mHot = true;
return performClassification(null /* selection */);
}
@WorkerThread
public SelectionResult suggestSelection() {
+ mHot = true;
trimText();
final TextSelection selection = mTextClassifier.suggestSelection(
mTrimmedText, mRelativeStart, mRelativeEnd, mLocales);
@@ -818,6 +844,22 @@
return performClassification(selection);
}
+ /**
+ * Maximum time (in milliseconds) to wait for a textclassifier result before timing out.
+ */
+ // TODO: Consider making this a ViewConfiguration.
+ public int getTimeoutDuration() {
+ if (mHot) {
+ return 200;
+ } else {
+ // Return a slightly larger number than usual when the TextClassifier is first
+ // initialized. Initialization would usually take longer than subsequent calls to
+ // the TextClassifier. The impact of this on the UI is that we do not show the
+ // selection handles or toolbar until after this timeout.
+ return 500;
+ }
+ }
+
private SelectionResult performClassification(@Nullable TextSelection selection) {
if (!Objects.equals(mText, mLastClassificationText)
|| mSelectionStart != mLastClassificationSelectionStart
@@ -888,4 +930,14 @@
return SelectionEvent.ActionType.OTHER;
}
}
+
+ private static CharSequence getText(TextView textView) {
+ // Extracts the textView's text.
+ // TODO: Investigate why/when TextView.getText() is null.
+ final CharSequence text = textView.getText();
+ if (text != null) {
+ return text;
+ }
+ return "";
+ }
}
diff --git a/core/java/android/widget/SmartSelectSprite.java b/core/java/android/widget/SmartSelectSprite.java
index 27b93bc..7cbc494b 100644
--- a/core/java/android/widget/SmartSelectSprite.java
+++ b/core/java/android/widget/SmartSelectSprite.java
@@ -35,6 +35,7 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.Shape;
+import android.text.Layout;
import android.util.TypedValue;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -42,9 +43,9 @@
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
-import java.util.LinkedList;
import java.util.List;
/**
@@ -76,6 +77,26 @@
private Drawable mExistingDrawable = null;
private RectangleList mExistingRectangleList = null;
+ static final class RectangleWithTextSelectionLayout {
+ private final RectF mRectangle;
+ @Layout.TextSelectionLayout
+ private final int mTextSelectionLayout;
+
+ RectangleWithTextSelectionLayout(RectF rectangle, int textSelectionLayout) {
+ mRectangle = Preconditions.checkNotNull(rectangle);
+ mTextSelectionLayout = textSelectionLayout;
+ }
+
+ public RectF getRectangle() {
+ return mRectangle;
+ }
+
+ @Layout.TextSelectionLayout
+ public int getTextSelectionLayout() {
+ return mTextSelectionLayout;
+ }
+ }
+
/**
* A rounded rectangle with a configurable corner radius and the ability to expand outside of
* its bounding rectangle and clip against it.
@@ -84,12 +105,23 @@
private static final String PROPERTY_ROUND_RATIO = "roundRatio";
+ /**
+ * The direction in which the rectangle will perform its expansion. A rectangle can expand
+ * from its left edge, its right edge or from the center (or, more precisely, the user's
+ * touch point). For example, in left-to-right text, a selection spanning two lines with the
+ * user's action being on the first line will have the top rectangle and expansion direction
+ * of CENTER, while the bottom one will have an expansion direction of RIGHT.
+ */
@Retention(SOURCE)
@IntDef({ExpansionDirection.LEFT, ExpansionDirection.CENTER, ExpansionDirection.RIGHT})
private @interface ExpansionDirection {
- int LEFT = 0;
- int CENTER = 1;
- int RIGHT = 2;
+ int LEFT = -1;
+ int CENTER = 0;
+ int RIGHT = 1;
+ }
+
+ private static @ExpansionDirection int invert(@ExpansionDirection int expansionDirection) {
+ return expansionDirection * -1;
}
@Retention(SOURCE)
@@ -114,20 +146,33 @@
private final RectF mClipRect = new RectF();
private final Path mClipPath = new Path();
- /** How far offset the left edge of the rectangle is from the bounding box. */
+ /** How offset the left edge of the rectangle is from the left side of the bounding box. */
private float mLeftBoundary = 0;
- /** How far offset the right edge of the rectangle is from the bounding box. */
+ /** How offset the right edge of the rectangle is from the left side of the bounding box. */
private float mRightBoundary = 0;
+ /** Whether the horizontal bounds are inverted (for RTL scenarios). */
+ private final boolean mInverted;
+
+ private final float mBoundingWidth;
+
private RoundedRectangleShape(
final RectF boundingRectangle,
final @ExpansionDirection int expansionDirection,
final @RectangleBorderType int rectangleBorderType,
+ final boolean inverted,
final float strokeWidth) {
mBoundingRectangle = new RectF(boundingRectangle);
- mExpansionDirection = expansionDirection;
+ mBoundingWidth = boundingRectangle.width();
mRectangleBorderType = rectangleBorderType;
mStrokeWidth = strokeWidth;
+ mInverted = inverted && expansionDirection != ExpansionDirection.CENTER;
+
+ if (inverted) {
+ mExpansionDirection = invert(expansionDirection);
+ } else {
+ mExpansionDirection = expansionDirection;
+ }
if (boundingRectangle.height() > boundingRectangle.width()) {
setRoundRatio(0.0f);
@@ -148,6 +193,10 @@
*/
@Override
public void draw(Canvas canvas, Paint paint) {
+ if (mLeftBoundary == mRightBoundary) {
+ return;
+ }
+
final float cornerRadius = getCornerRadius();
final float adjustedCornerRadius = getAdjustedCornerRadius();
@@ -173,7 +222,7 @@
canvas.save();
mClipRect.set(mBoundingRectangle);
- mClipRect.inset(-mStrokeWidth, -mStrokeWidth);
+ mClipRect.inset(-mStrokeWidth / 2, -mStrokeWidth / 2);
canvas.clipRect(mClipRect);
canvas.drawRoundRect(mDrawRect, adjustedCornerRadius, adjustedCornerRadius, paint);
canvas.restore();
@@ -190,20 +239,28 @@
canvas.restore();
}
- public void setRoundRatio(@FloatRange(from = 0.0, to = 1.0) final float roundRatio) {
+ void setRoundRatio(@FloatRange(from = 0.0, to = 1.0) final float roundRatio) {
mRoundRatio = roundRatio;
}
- public float getRoundRatio() {
+ float getRoundRatio() {
return mRoundRatio;
}
- private void setLeftBoundary(final float leftBoundary) {
- mLeftBoundary = leftBoundary;
+ private void setStartBoundary(final float startBoundary) {
+ if (mInverted) {
+ mRightBoundary = mBoundingWidth - startBoundary;
+ } else {
+ mLeftBoundary = startBoundary;
+ }
}
- private void setRightBoundary(final float rightBoundary) {
- mRightBoundary = rightBoundary;
+ private void setEndBoundary(final float endBoundary) {
+ if (mInverted) {
+ mLeftBoundary = mBoundingWidth - endBoundary;
+ } else {
+ mRightBoundary = endBoundary;
+ }
}
private float getCornerRadius() {
@@ -247,8 +304,8 @@
private @DisplayType int mDisplayType = DisplayType.RECTANGLES;
private RectangleList(final List<RoundedRectangleShape> rectangles) {
- mRectangles = new LinkedList<>(rectangles);
- mReversedRectangles = new LinkedList<>(rectangles);
+ mRectangles = new ArrayList<>(rectangles);
+ mReversedRectangles = new ArrayList<>(rectangles);
Collections.reverse(mReversedRectangles);
mOutlinePolygonPath = generateOutlinePolygonPath(rectangles);
}
@@ -258,11 +315,11 @@
for (RoundedRectangleShape rectangle : mReversedRectangles) {
final float rectangleLeftBoundary = boundarySoFar - rectangle.getBoundingWidth();
if (leftBoundary < rectangleLeftBoundary) {
- rectangle.setLeftBoundary(0);
+ rectangle.setStartBoundary(0);
} else if (leftBoundary > boundarySoFar) {
- rectangle.setLeftBoundary(rectangle.getBoundingWidth());
+ rectangle.setStartBoundary(rectangle.getBoundingWidth());
} else {
- rectangle.setLeftBoundary(
+ rectangle.setStartBoundary(
rectangle.getBoundingWidth() - boundarySoFar + leftBoundary);
}
@@ -275,11 +332,11 @@
for (RoundedRectangleShape rectangle : mRectangles) {
final float rectangleRightBoundary = rectangle.getBoundingWidth() + boundarySoFar;
if (rectangleRightBoundary < rightBoundary) {
- rectangle.setRightBoundary(rectangle.getBoundingWidth());
+ rectangle.setEndBoundary(rectangle.getBoundingWidth());
} else if (boundarySoFar > rightBoundary) {
- rectangle.setRightBoundary(0);
+ rectangle.setEndBoundary(0);
} else {
- rectangle.setRightBoundary(rightBoundary - boundarySoFar);
+ rectangle.setEndBoundary(rightBoundary - boundarySoFar);
}
boundarySoFar = rectangleRightBoundary;
@@ -331,8 +388,8 @@
}
/**
- * @param context The {@link Context} in which the animation will run
- * @param invalidator A {@link Runnable} which will be called every time the animation updates,
+ * @param context the {@link Context} in which the animation will run
+ * @param invalidator a {@link Runnable} which will be called every time the animation updates,
* indicating that the view drawing the animation should invalidate itself
*/
SmartSelectSprite(final Context context, final Runnable invalidator) {
@@ -356,42 +413,48 @@
* "selection" and finally join them into a single polygon. In
* order to get the correct visual behavior, these rectangles
* should be sorted according to {@link #RECTANGLE_COMPARATOR}.
- * @param onAnimationEnd The callback which will be invoked once the whole animation
- * completes.
+ * @param onAnimationEnd the callback which will be invoked once the whole animation
+ * completes
* @throws IllegalArgumentException if the given start point is not in any of the
- * destinationRectangles.
+ * destinationRectangles
* @see #cancelAnimation()
*/
+ // TODO nullability checks on parameters
public void startAnimation(
final PointF start,
- final List<RectF> destinationRectangles,
- final Runnable onAnimationEnd) throws IllegalArgumentException {
+ final List<RectangleWithTextSelectionLayout> destinationRectangles,
+ final Runnable onAnimationEnd) {
cancelAnimation();
final ValueAnimator.AnimatorUpdateListener updateListener =
valueAnimator -> mInvalidator.run();
- final List<RoundedRectangleShape> shapes = new LinkedList<>();
- final List<Animator> cornerAnimators = new LinkedList<>();
+ final int rectangleCount = destinationRectangles.size();
- final RectF centerRectangle = destinationRectangles
- .stream()
- .filter((r) -> contains(r, start))
- .findFirst()
- .orElseThrow(() -> new IllegalArgumentException(
- "Center point is not inside any of the rectangles!"));
+ final List<RoundedRectangleShape> shapes = new ArrayList<>(rectangleCount);
+ final List<Animator> cornerAnimators = new ArrayList<>(rectangleCount);
+
+ RectangleWithTextSelectionLayout centerRectangle = null;
int startingOffset = 0;
- for (RectF rectangle : destinationRectangles) {
- if (rectangle.equals(centerRectangle)) {
+ for (int index = 0; index < rectangleCount; ++index) {
+ final RectangleWithTextSelectionLayout rectangleWithTextSelectionLayout =
+ destinationRectangles.get(index);
+ final RectF rectangle = rectangleWithTextSelectionLayout.getRectangle();
+ if (contains(rectangle, start)) {
+ centerRectangle = rectangleWithTextSelectionLayout;
break;
}
startingOffset += rectangle.width();
}
- startingOffset += start.x - centerRectangle.left;
+ if (centerRectangle == null) {
+ throw new IllegalArgumentException("Center point is not inside any of the rectangles!");
+ }
- final float centerRectangleHalfHeight = centerRectangle.height() / 2;
+ startingOffset += start.x - centerRectangle.getRectangle().left;
+
+ final float centerRectangleHalfHeight = centerRectangle.getRectangle().height() / 2;
final float startingOffsetLeft = startingOffset - centerRectangleHalfHeight;
final float startingOffsetRight = startingOffset + centerRectangleHalfHeight;
@@ -399,19 +462,21 @@
generateDirections(centerRectangle, destinationRectangles);
final @RoundedRectangleShape.RectangleBorderType int[] rectangleBorderTypes =
- generateBorderTypes(destinationRectangles);
+ generateBorderTypes(rectangleCount);
- int index = 0;
-
- for (RectF rectangle : destinationRectangles) {
+ for (int index = 0; index < rectangleCount; ++index) {
+ final RectangleWithTextSelectionLayout rectangleWithTextSelectionLayout =
+ destinationRectangles.get(index);
+ final RectF rectangle = rectangleWithTextSelectionLayout.getRectangle();
final RoundedRectangleShape shape = new RoundedRectangleShape(
rectangle,
expansionDirections[index],
rectangleBorderTypes[index],
+ rectangleWithTextSelectionLayout.getTextSelectionLayout()
+ == Layout.TEXT_SELECTION_LAYOUT_RIGHT_TO_LEFT,
mStrokeWidth);
cornerAnimators.add(createCornerAnimator(shape, updateListener));
shapes.add(shape);
- index++;
}
final RectangleList rectangleList = new RectangleList(shapes);
@@ -511,7 +576,8 @@
}
private static @RoundedRectangleShape.ExpansionDirection int[] generateDirections(
- final RectF centerRectangle, final List<RectF> rectangles) {
+ final RectangleWithTextSelectionLayout centerRectangle,
+ final List<RectangleWithTextSelectionLayout> rectangles) {
final @RoundedRectangleShape.ExpansionDirection int[] result = new int[rectangles.size()];
final int centerRectangleIndex = rectangles.indexOf(centerRectangle);
@@ -538,8 +604,8 @@
}
private static @RoundedRectangleShape.RectangleBorderType int[] generateBorderTypes(
- final List<RectF> rectangles) {
- final @RoundedRectangleShape.RectangleBorderType int[] result = new int[rectangles.size()];
+ final int numberOfRectangles) {
+ final @RoundedRectangleShape.RectangleBorderType int[] result = new int[numberOfRectangles];
for (int i = 1; i < result.length - 1; ++i) {
result[i] = RoundedRectangleShape.RectangleBorderType.OVERSHOOT;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 2cab009..eb639bd 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1450,11 +1450,16 @@
getFirstRowPosition(rowPosition + 1));
int serviceSpacing = holder.row.getContext().getResources()
.getDimensionPixelSize(R.dimen.chooser_service_spacing);
- int top = rowPosition == 0 ? serviceSpacing : 0;
- if (nextStartType != ChooserListAdapter.TARGET_SERVICE) {
- setVertPadding(holder, top, serviceSpacing);
+ if (rowPosition == 0 && nextStartType != ChooserListAdapter.TARGET_SERVICE) {
+ // if the row is the only row for target service
+ setVertPadding(holder, 0, 0);
} else {
- setVertPadding(holder, top, 0);
+ int top = rowPosition == 0 ? serviceSpacing : 0;
+ if (nextStartType != ChooserListAdapter.TARGET_SERVICE) {
+ setVertPadding(holder, top, serviceSpacing);
+ } else {
+ setVertPadding(holder, top, 0);
+ }
}
} else {
holder.row.setBackgroundColor(Color.TRANSPARENT);
diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl
index 36e4c1c6..ef30cd1 100644
--- a/core/java/com/android/internal/app/IMediaContainerService.aidl
+++ b/core/java/com/android/internal/app/IMediaContainerService.aidl
@@ -21,12 +21,10 @@
import android.content.res.ObbInfo;
interface IMediaContainerService {
- String copyPackageToContainer(String packagePath, String containerId, String key,
- boolean isExternal, boolean isForwardLocked, String abiOverride);
int copyPackage(String packagePath, in IParcelFileDescriptorFactory target);
PackageInfoLite getMinimalPackageInfo(String packagePath, int flags, String abiOverride);
ObbInfo getObbInfo(String filename);
void clearDirectory(String directory);
- long calculateInstalledSize(String packagePath, boolean isForwardLocked, String abiOverride);
+ long calculateInstalledSize(String packagePath, String abiOverride);
}
diff --git a/core/java/com/android/internal/app/ShutdownActivity.java b/core/java/com/android/internal/app/ShutdownActivity.java
index 745d28f..f81e838 100644
--- a/core/java/com/android/internal/app/ShutdownActivity.java
+++ b/core/java/com/android/internal/app/ShutdownActivity.java
@@ -41,6 +41,9 @@
mReboot = Intent.ACTION_REBOOT.equals(intent.getAction());
mConfirm = intent.getBooleanExtra(Intent.EXTRA_KEY_CONFIRM, false);
mUserRequested = intent.getBooleanExtra(Intent.EXTRA_USER_REQUESTED_SHUTDOWN, false);
+ final String reason = mUserRequested
+ ? PowerManager.SHUTDOWN_USER_REQUESTED
+ : intent.getStringExtra(Intent.EXTRA_REASON);
Slog.i(TAG, "onCreate(): confirm=" + mConfirm);
Thread thr = new Thread("ShutdownActivity") {
@@ -52,9 +55,7 @@
if (mReboot) {
pm.reboot(mConfirm, null, false);
} else {
- pm.shutdown(mConfirm,
- mUserRequested ? PowerManager.SHUTDOWN_USER_REQUESTED : null,
- false);
+ pm.shutdown(mConfirm, reason, false);
}
} catch (RemoteException e) {
}
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index e923223..59a7995 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -16,7 +16,6 @@
package com.android.internal.content;
-import static android.net.TrafficStats.MB_IN_BYTES;
import static android.os.storage.VolumeInfo.ID_PRIVATE_INTERNAL;
import android.content.Context;
@@ -27,13 +26,11 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageParser.PackageLite;
import android.os.Environment;
-import android.os.FileUtils;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
-import android.os.storage.StorageResultCode;
import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
import android.provider.Settings;
@@ -45,15 +42,9 @@
import libcore.io.IoUtils;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collections;
import java.util.Objects;
import java.util.UUID;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipOutputStream;
/**
* Constants used internally between the PackageManager
@@ -72,7 +63,6 @@
public static final int RECOMMEND_FAILED_INVALID_URI = -6;
public static final int RECOMMEND_FAILED_VERSION_DOWNGRADE = -7;
- private static final boolean localLOGV = false;
private static final String TAG = "PackageHelper";
// App installation location settings values
public static final int APP_INSTALL_AUTO = 0;
@@ -91,259 +81,6 @@
}
}
- public static String createSdDir(long sizeBytes, String cid, String sdEncKey, int uid,
- boolean isExternal) {
- // Round up to nearest MB, plus another MB for filesystem overhead
- final int sizeMb = (int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES) + 1;
- try {
- IStorageManager storageManager = getStorageManager();
-
- if (localLOGV)
- Log.i(TAG, "Size of container " + sizeMb + " MB");
-
- int rc = storageManager.createSecureContainer(cid, sizeMb, "ext4", sdEncKey, uid,
- isExternal);
- if (rc != StorageResultCode.OperationSucceeded) {
- Log.e(TAG, "Failed to create secure container " + cid);
- return null;
- }
- String cachePath = storageManager.getSecureContainerPath(cid);
- if (localLOGV) Log.i(TAG, "Created secure container " + cid +
- " at " + cachePath);
- return cachePath;
- } catch (RemoteException e) {
- Log.e(TAG, "StorageManagerService running?");
- }
- return null;
- }
-
- public static boolean resizeSdDir(long sizeBytes, String cid, String sdEncKey) {
- // Round up to nearest MB, plus another MB for filesystem overhead
- final int sizeMb = (int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES) + 1;
- try {
- IStorageManager storageManager = getStorageManager();
- int rc = storageManager.resizeSecureContainer(cid, sizeMb, sdEncKey);
- if (rc == StorageResultCode.OperationSucceeded) {
- return true;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "StorageManagerService running?");
- }
- Log.e(TAG, "Failed to create secure container " + cid);
- return false;
- }
-
- public static String mountSdDir(String cid, String key, int ownerUid) {
- return mountSdDir(cid, key, ownerUid, true);
- }
-
- public static String mountSdDir(String cid, String key, int ownerUid, boolean readOnly) {
- try {
- int rc = getStorageManager().mountSecureContainer(cid, key, ownerUid, readOnly);
- if (rc != StorageResultCode.OperationSucceeded) {
- Log.i(TAG, "Failed to mount container " + cid + " rc : " + rc);
- return null;
- }
- return getStorageManager().getSecureContainerPath(cid);
- } catch (RemoteException e) {
- Log.e(TAG, "StorageManagerService running?");
- }
- return null;
- }
-
- public static boolean unMountSdDir(String cid) {
- try {
- int rc = getStorageManager().unmountSecureContainer(cid, true);
- if (rc != StorageResultCode.OperationSucceeded) {
- Log.e(TAG, "Failed to unmount " + cid + " with rc " + rc);
- return false;
- }
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "StorageManagerService running?");
- }
- return false;
- }
-
- public static boolean renameSdDir(String oldId, String newId) {
- try {
- int rc = getStorageManager().renameSecureContainer(oldId, newId);
- if (rc != StorageResultCode.OperationSucceeded) {
- Log.e(TAG, "Failed to rename " + oldId + " to " +
- newId + "with rc " + rc);
- return false;
- }
- return true;
- } catch (RemoteException e) {
- Log.i(TAG, "Failed ot rename " + oldId + " to " + newId +
- " with exception : " + e);
- }
- return false;
- }
-
- public static String getSdDir(String cid) {
- try {
- return getStorageManager().getSecureContainerPath(cid);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to get container path for " + cid +
- " with exception " + e);
- }
- return null;
- }
-
- public static String getSdFilesystem(String cid) {
- try {
- return getStorageManager().getSecureContainerFilesystemPath(cid);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to get container path for " + cid +
- " with exception " + e);
- }
- return null;
- }
-
- public static boolean finalizeSdDir(String cid) {
- try {
- int rc = getStorageManager().finalizeSecureContainer(cid);
- if (rc != StorageResultCode.OperationSucceeded) {
- Log.i(TAG, "Failed to finalize container " + cid);
- return false;
- }
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to finalize container " + cid +
- " with exception " + e);
- }
- return false;
- }
-
- public static boolean destroySdDir(String cid) {
- try {
- if (localLOGV) Log.i(TAG, "Forcibly destroying container " + cid);
- int rc = getStorageManager().destroySecureContainer(cid, true);
- if (rc != StorageResultCode.OperationSucceeded) {
- Log.i(TAG, "Failed to destroy container " + cid);
- return false;
- }
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to destroy container " + cid +
- " with exception " + e);
- }
- return false;
- }
-
- public static String[] getSecureContainerList() {
- try {
- return getStorageManager().getSecureContainerList();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to get secure container list with exception" +
- e);
- }
- return null;
- }
-
- public static boolean isContainerMounted(String cid) {
- try {
- return getStorageManager().isSecureContainerMounted(cid);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to find out if container " + cid + " mounted");
- }
- return false;
- }
-
- /**
- * Extract public files for the single given APK.
- */
- public static long extractPublicFiles(File apkFile, File publicZipFile)
- throws IOException {
- final FileOutputStream fstr;
- final ZipOutputStream publicZipOutStream;
-
- if (publicZipFile == null) {
- fstr = null;
- publicZipOutStream = null;
- } else {
- fstr = new FileOutputStream(publicZipFile);
- publicZipOutStream = new ZipOutputStream(fstr);
- Log.d(TAG, "Extracting " + apkFile + " to " + publicZipFile);
- }
-
- long size = 0L;
-
- try {
- final ZipFile privateZip = new ZipFile(apkFile.getAbsolutePath());
- try {
- // Copy manifest, resources.arsc and res directory to public zip
- for (final ZipEntry zipEntry : Collections.list(privateZip.entries())) {
- final String zipEntryName = zipEntry.getName();
- if ("AndroidManifest.xml".equals(zipEntryName)
- || "resources.arsc".equals(zipEntryName)
- || zipEntryName.startsWith("res/")) {
- size += zipEntry.getSize();
- if (publicZipFile != null) {
- copyZipEntry(zipEntry, privateZip, publicZipOutStream);
- }
- }
- }
- } finally {
- try { privateZip.close(); } catch (IOException e) {}
- }
-
- if (publicZipFile != null) {
- publicZipOutStream.finish();
- publicZipOutStream.flush();
- FileUtils.sync(fstr);
- publicZipOutStream.close();
- FileUtils.setPermissions(publicZipFile.getAbsolutePath(), FileUtils.S_IRUSR
- | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IROTH, -1, -1);
- }
- } finally {
- IoUtils.closeQuietly(publicZipOutStream);
- }
-
- return size;
- }
-
- private static void copyZipEntry(ZipEntry zipEntry, ZipFile inZipFile,
- ZipOutputStream outZipStream) throws IOException {
- byte[] buffer = new byte[4096];
- int num;
-
- ZipEntry newEntry;
- if (zipEntry.getMethod() == ZipEntry.STORED) {
- // Preserve the STORED method of the input entry.
- newEntry = new ZipEntry(zipEntry);
- } else {
- // Create a new entry so that the compressed len is recomputed.
- newEntry = new ZipEntry(zipEntry.getName());
- }
- outZipStream.putNextEntry(newEntry);
-
- final InputStream data = inZipFile.getInputStream(zipEntry);
- try {
- while ((num = data.read(buffer)) > 0) {
- outZipStream.write(buffer, 0, num);
- }
- outZipStream.flush();
- } finally {
- IoUtils.closeQuietly(data);
- }
- }
-
- public static boolean fixSdPermissions(String cid, int gid, String filename) {
- try {
- int rc = getStorageManager().fixPermissionsSecureContainer(cid, gid, filename);
- if (rc != StorageResultCode.OperationSucceeded) {
- Log.i(TAG, "Failed to fixperms container " + cid);
- return false;
- }
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to fixperms container " + cid + " with exception " + e);
- }
- return false;
- }
-
/**
* A group of external dependencies used in
* {@link #resolveInstallVolume(Context, String, int, long)}. It can be backed by real values
@@ -638,29 +375,37 @@
return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
+ @Deprecated
public static long calculateInstalledSize(PackageLite pkg, boolean isForwardLocked,
String abiOverride) throws IOException {
+ return calculateInstalledSize(pkg, abiOverride);
+ }
+
+ public static long calculateInstalledSize(PackageLite pkg, String abiOverride)
+ throws IOException {
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(pkg);
- return calculateInstalledSize(pkg, handle, isForwardLocked, abiOverride);
+ return calculateInstalledSize(pkg, handle, abiOverride);
} finally {
IoUtils.closeQuietly(handle);
}
}
+ @Deprecated
+ public static long calculateInstalledSize(PackageLite pkg, boolean isForwardLocked,
+ NativeLibraryHelper.Handle handle, String abiOverride) throws IOException {
+ return calculateInstalledSize(pkg, handle, abiOverride);
+ }
+
public static long calculateInstalledSize(PackageLite pkg, NativeLibraryHelper.Handle handle,
- boolean isForwardLocked, String abiOverride) throws IOException {
+ String abiOverride) throws IOException {
long sizeBytes = 0;
// Include raw APKs, and possibly unpacked resources
for (String codePath : pkg.getAllCodePaths()) {
final File codeFile = new File(codePath);
sizeBytes += codeFile.length();
-
- if (isForwardLocked) {
- sizeBytes += PackageHelper.extractPublicFiles(codeFile, null);
- }
}
// Include all relevant native code
diff --git a/core/java/com/android/internal/util/RingBuffer.java b/core/java/com/android/internal/util/RingBuffer.java
new file mode 100644
index 0000000..ad84353
--- /dev/null
+++ b/core/java/com/android/internal/util/RingBuffer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import static com.android.internal.util.Preconditions.checkArgumentPositive;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+
+/**
+ * A simple ring buffer structure with bounded capacity backed by an array.
+ * Events can always be added at the logical end of the buffer. If the buffer is
+ * full, oldest events are dropped when new events are added.
+ * {@hide}
+ */
+public class RingBuffer<T> {
+
+ // Array for storing events.
+ private final T[] mBuffer;
+ // Cursor keeping track of the logical end of the array. This cursor never
+ // wraps and instead keeps track of the total number of append() operations.
+ private long mCursor = 0;
+
+ public RingBuffer(Class<T> c, int capacity) {
+ checkArgumentPositive(capacity, "A RingBuffer cannot have 0 capacity");
+ // Java cannot create generic arrays without a runtime hint.
+ mBuffer = (T[]) Array.newInstance(c, capacity);
+ }
+
+ public int size() {
+ return (int) Math.min(mBuffer.length, (long) mCursor);
+ }
+
+ public void append(T t) {
+ mBuffer[indexOf(mCursor++)] = t;
+ }
+
+ public T[] toArray() {
+ // Only generic way to create a T[] from another T[]
+ T[] out = Arrays.copyOf(mBuffer, size(), (Class<T[]>) mBuffer.getClass());
+ // Reverse iteration from youngest event to oldest event.
+ long inCursor = mCursor - 1;
+ int outIdx = out.length - 1;
+ while (outIdx >= 0) {
+ out[outIdx--] = (T) mBuffer[indexOf(inCursor--)];
+ }
+ return out;
+ }
+
+ private int indexOf(long cursor) {
+ return (int) Math.abs(cursor % mBuffer.length);
+ }
+}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index b8ef82b..4be6b28 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -303,7 +303,7 @@
}
public void reportFailedPasswordAttempt(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled()) {
+ if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
return;
}
getDevicePolicyManager().reportFailedPasswordAttempt(userId);
@@ -311,7 +311,7 @@
}
public void reportSuccessfulPasswordAttempt(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled()) {
+ if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
return;
}
getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
@@ -319,21 +319,21 @@
}
public void reportPasswordLockout(int timeoutMs, int userId) {
- if (userId == USER_FRP && frpCredentialEnabled()) {
+ if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
return;
}
getTrustManager().reportUnlockLockout(timeoutMs, userId);
}
public int getCurrentFailedPasswordAttempts(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled()) {
+ if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
return 0;
}
return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
}
public int getMaximumFailedPasswordsForWipe(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled()) {
+ if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
return 0;
}
return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
@@ -1774,11 +1774,12 @@
return getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM) != 0;
}
- public static boolean userOwnsFrpCredential(UserInfo info) {
- return info != null && info.isPrimary() && info.isAdmin() && frpCredentialEnabled();
+ public static boolean userOwnsFrpCredential(Context context, UserInfo info) {
+ return info != null && info.isPrimary() && info.isAdmin() && frpCredentialEnabled(context);
}
- public static boolean frpCredentialEnabled() {
- return FRP_CREDENTIAL_ENABLED;
+ public static boolean frpCredentialEnabled(Context context) {
+ return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableCredentialFactoryResetProtection);
}
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 016c0c8..256b920 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -78,6 +78,7 @@
"android_view_VelocityTracker.cpp",
"android_text_AndroidCharacter.cpp",
"android_text_AndroidBidi.cpp",
+ "android_text_Hyphenator.cpp",
"android_text_StaticLayout.cpp",
"android_os_Debug.cpp",
"android_os_GraphicsEnvironment.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 02c9848..deb4d5a 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -173,6 +173,7 @@
extern int register_android_net_NetworkUtils(JNIEnv* env);
extern int register_android_net_TrafficStats(JNIEnv* env);
extern int register_android_text_AndroidCharacter(JNIEnv *env);
+extern int register_android_text_Hyphenator(JNIEnv *env);
extern int register_android_text_StaticLayout(JNIEnv *env);
extern int register_android_text_AndroidBidi(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
@@ -1321,6 +1322,7 @@
REG_JNI(register_android_content_StringBlock),
REG_JNI(register_android_content_XmlBlock),
REG_JNI(register_android_text_AndroidCharacter),
+ REG_JNI(register_android_text_Hyphenator),
REG_JNI(register_android_text_StaticLayout),
REG_JNI(register_android_text_AndroidBidi),
REG_JNI(register_android_view_InputDevice),
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 0ba27f6..c6801bf 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -97,21 +97,21 @@
static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex,
jint givenWeight, jint givenItalic) {
- uirenderer::FatVector<SkFontMgr::FontParameters::Axis, 2> skiaAxes;
+ uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes;
for (const auto& axis : builder->axes) {
- skiaAxes.emplace_back(SkFontMgr::FontParameters::Axis{axis.axisTag, axis.value});
+ skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
}
const size_t fontSize = data->size();
const void* fontPtr = data->data();
std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
- SkFontMgr::FontParameters params;
+ SkFontArguments params;
params.setCollectionIndex(ttcIndex);
params.setAxes(skiaAxes.data(), skiaAxes.size());
sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
- sk_sp<SkTypeface> face(fm->createFromStream(fontData.release(), params));
+ sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), params));
if (face == NULL) {
ALOGE("addFont failed to create font, invalid request");
builder->axes.clear();
diff --git a/core/jni/android/graphics/FontUtils.cpp b/core/jni/android/graphics/FontUtils.cpp
index 3bcf0c7..0cf61b9 100644
--- a/core/jni/android/graphics/FontUtils.cpp
+++ b/core/jni/android/graphics/FontUtils.cpp
@@ -16,7 +16,7 @@
#include "FontUtils.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include <core_jni_helpers.h>
namespace android {
diff --git a/core/jni/android/graphics/GraphicBuffer.cpp b/core/jni/android/graphics/GraphicBuffer.cpp
index 1017cba..ae6fd38 100644
--- a/core/jni/android/graphics/GraphicBuffer.cpp
+++ b/core/jni/android/graphics/GraphicBuffer.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "GraphicBuffer"
#include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include <inttypes.h>
#include "android_os_Parcel.h"
diff --git a/core/jni/android/graphics/pdf/PdfUtils.cpp b/core/jni/android/graphics/pdf/PdfUtils.cpp
index dacca78..36355eb 100644
--- a/core/jni/android/graphics/pdf/PdfUtils.cpp
+++ b/core/jni/android/graphics/pdf/PdfUtils.cpp
@@ -17,7 +17,7 @@
#include "PdfUtils.h"
#include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include "fpdfview.h"
diff --git a/core/jni/android_hardware_HardwareBuffer.cpp b/core/jni/android_hardware_HardwareBuffer.cpp
index ba23450..8174a41 100644
--- a/core/jni/android_hardware_HardwareBuffer.cpp
+++ b/core/jni/android_hardware_HardwareBuffer.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "HardwareBuffer"
#include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include "android_os_Parcel.h"
#include "android/graphics/GraphicsJNI.h"
diff --git a/core/jni/android_hardware_display_DisplayViewport.cpp b/core/jni/android_hardware_display_DisplayViewport.cpp
index 2d2837c..23c3877 100644
--- a/core/jni/android_hardware_display_DisplayViewport.cpp
+++ b/core/jni/android_hardware_display_DisplayViewport.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "DisplayViewport-JNI"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include "core_jni_helpers.h"
#include <android_hardware_display_DisplayViewport.h>
diff --git a/core/jni/android_os_SharedMemory.cpp b/core/jni/android_os_SharedMemory.cpp
index 1d29908..f6e5c7a 100644
--- a/core/jni/android_os_SharedMemory.cpp
+++ b/core/jni/android_os_SharedMemory.cpp
@@ -20,7 +20,7 @@
#include <cutils/ashmem.h>
#include <utils/Log.h>
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include <nativehelper/JniConstants.h>
#include <nativehelper/ScopedLocalRef.h>
diff --git a/core/jni/android_os_VintfRuntimeInfo.cpp b/core/jni/android_os_VintfRuntimeInfo.cpp
index 315eac1..9379ea6 100644
--- a/core/jni/android_os_VintfRuntimeInfo.cpp
+++ b/core/jni/android_os_VintfRuntimeInfo.cpp
@@ -29,28 +29,33 @@
using vintf::RuntimeInfo;
using vintf::VintfObject;
-#define MAP_STRING_METHOD(javaMethod, cppString) \
+#define MAP_STRING_METHOD(javaMethod, cppString, flags) \
static jstring android_os_VintfRuntimeInfo_##javaMethod(JNIEnv* env, jclass clazz) \
{ \
- std::shared_ptr<const RuntimeInfo> info = VintfObject::GetRuntimeInfo(); \
+ std::shared_ptr<const RuntimeInfo> info = VintfObject::GetRuntimeInfo( \
+ false /* skipCache */, flags); \
if (info == nullptr) return nullptr; \
return env->NewStringUTF((cppString).c_str()); \
} \
-MAP_STRING_METHOD(getCpuInfo, info->cpuInfo());
-MAP_STRING_METHOD(getOsName, info->osName());
-MAP_STRING_METHOD(getNodeName, info->nodeName());
-MAP_STRING_METHOD(getOsRelease, info->osRelease());
-MAP_STRING_METHOD(getOsVersion, info->osVersion());
-MAP_STRING_METHOD(getHardwareId, info->hardwareId());
-MAP_STRING_METHOD(getKernelVersion, vintf::to_string(info->kernelVersion()));
-MAP_STRING_METHOD(getBootAvbVersion, vintf::to_string(info->bootAvbVersion()));
-MAP_STRING_METHOD(getBootVbmetaAvbVersion, vintf::to_string(info->bootVbmetaAvbVersion()));
+MAP_STRING_METHOD(getCpuInfo, info->cpuInfo(), RuntimeInfo::FetchFlag::CPU_INFO);
+MAP_STRING_METHOD(getOsName, info->osName(), RuntimeInfo::FetchFlag::CPU_VERSION);
+MAP_STRING_METHOD(getNodeName, info->nodeName(), RuntimeInfo::FetchFlag::CPU_VERSION);
+MAP_STRING_METHOD(getOsRelease, info->osRelease(), RuntimeInfo::FetchFlag::CPU_VERSION);
+MAP_STRING_METHOD(getOsVersion, info->osVersion(), RuntimeInfo::FetchFlag::CPU_VERSION);
+MAP_STRING_METHOD(getHardwareId, info->hardwareId(), RuntimeInfo::FetchFlag::CPU_VERSION);
+MAP_STRING_METHOD(getKernelVersion, vintf::to_string(info->kernelVersion()),
+ RuntimeInfo::FetchFlag::CPU_VERSION);
+MAP_STRING_METHOD(getBootAvbVersion, vintf::to_string(info->bootAvbVersion()),
+ RuntimeInfo::FetchFlag::AVB);
+MAP_STRING_METHOD(getBootVbmetaAvbVersion, vintf::to_string(info->bootVbmetaAvbVersion()),
+ RuntimeInfo::FetchFlag::AVB);
static jlong android_os_VintfRuntimeInfo_getKernelSepolicyVersion(JNIEnv *env, jclass clazz)
{
- std::shared_ptr<const RuntimeInfo> info = VintfObject::GetRuntimeInfo();
+ std::shared_ptr<const RuntimeInfo> info = VintfObject::GetRuntimeInfo(
+ false /* skipCache */, RuntimeInfo::FetchFlag::POLICYVERS);
if (info == nullptr) return 0;
return static_cast<jlong>(info->kernelSepolicyVersion());
}
diff --git a/core/jni/android_text_Hyphenator.cpp b/core/jni/android_text_Hyphenator.cpp
new file mode 100644
index 0000000..da025da
--- /dev/null
+++ b/core/jni/android_text_Hyphenator.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstdint>
+#include <core_jni_helpers.h>
+#include <minikin/Hyphenator.h>
+#include <nativehelper/ScopedUtfChars.h>
+
+namespace android {
+
+static jlong nBuildHyphenator(JNIEnv* env, jclass, jlong dataAddress, jstring lang,
+ jint minPrefix, jint minSuffix) {
+ const uint8_t* bytebuf = reinterpret_cast<const uint8_t*>(dataAddress); // null allowed.
+ ScopedUtfChars language(env, lang);
+ minikin::Hyphenator* hyphenator = minikin::Hyphenator::loadBinary(
+ bytebuf, minPrefix, minSuffix, language.c_str(), language.size());
+ return reinterpret_cast<jlong>(hyphenator);
+}
+
+static const JNINativeMethod gMethods[] = {
+ {"nBuildHyphenator", "(JLjava/lang/String;II)J", (void*) nBuildHyphenator},
+};
+
+int register_android_text_Hyphenator(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "android/text/Hyphenator", gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 7442fa2..bcc7752 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -55,39 +55,64 @@
class JNILineBreakerLineWidth : public minikin::LineBreaker::LineWidthDelegate {
public:
JNILineBreakerLineWidth(float firstWidth, int32_t firstLineCount, float restWidth,
- std::vector<float>&& indents, int32_t indentsOffset)
+ std::vector<float>&& indents, std::vector<float>&& leftPaddings,
+ std::vector<float>&& rightPaddings, int32_t indentsAndPaddingsOffset)
: mFirstWidth(firstWidth), mFirstLineCount(firstLineCount), mRestWidth(restWidth),
- mIndents(std::move(indents)), mIndentsOffset(indentsOffset) {}
+ mIndents(std::move(indents)), mLeftPaddings(std::move(leftPaddings)),
+ mRightPaddings(std::move(rightPaddings)), mOffset(indentsAndPaddingsOffset) {}
float getLineWidth(size_t lineNo) override {
const float width = ((ssize_t)lineNo < (ssize_t)mFirstLineCount)
? mFirstWidth : mRestWidth;
- if (mIndents.empty()) {
- return width;
- }
+ return width - get(mIndents, lineNo);
+ }
- const size_t indentIndex = lineNo + mIndentsOffset;
- if (indentIndex < mIndents.size()) {
- return width - mIndents[indentIndex];
- } else {
- return width - mIndents.back();
- }
+ float getLeftPadding(size_t lineNo) override {
+ return get(mLeftPaddings, lineNo);
+ }
+
+ float getRightPadding(size_t lineNo) override {
+ return get(mRightPaddings, lineNo);
}
private:
+ float get(const std::vector<float>& vec, size_t lineNo) {
+ if (vec.empty()) {
+ return 0;
+ }
+ const size_t index = lineNo + mOffset;
+ if (index < vec.size()) {
+ return vec[index];
+ } else {
+ return vec.back();
+ }
+ }
+
const float mFirstWidth;
const int32_t mFirstLineCount;
const float mRestWidth;
const std::vector<float> mIndents;
- const int32_t mIndentsOffset;
+ const std::vector<float> mLeftPaddings;
+ const std::vector<float> mRightPaddings;
+ const int32_t mOffset;
};
+static inline std::vector<float> jintArrayToFloatVector(JNIEnv* env, jintArray javaArray) {
+ if (javaArray == nullptr) {
+ return std::vector<float>();
+ } else {
+ ScopedIntArrayRO intArr(env, javaArray);
+ return std::vector<float>(intArr.get(), intArr.get() + intArr.size());
+ }
+}
+
// set text and set a number of parameters for creating a layout (width, tabstops, strategy,
// hyphenFrequency)
static void nSetupParagraph(JNIEnv* env, jclass, jlong nativePtr, jcharArray text, jint length,
jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
jintArray variableTabStops, jint defaultTabStop, jint strategy, jint hyphenFrequency,
- jboolean isJustified, jintArray indents, jint indentsOffset) {
+ jboolean isJustified, jintArray indents, jintArray leftPaddings, jintArray rightPaddings,
+ jint indentsAndPaddingsOffset) {
minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
b->resize(length);
env->GetCharArrayRegion(text, 0, length, b->buffer());
@@ -102,14 +127,11 @@
b->setHyphenationFrequency(static_cast<minikin::HyphenationFrequency>(hyphenFrequency));
b->setJustified(isJustified);
- std::vector<float> indentVec;
- // TODO: copy indents only once when LineBreaker is started to be used.
- if (indents != nullptr) {
- ScopedIntArrayRO indentArr(env, indents);
- indentVec.assign(indentArr.get(), indentArr.get() + indentArr.size());
- }
+ // TODO: copy indents and paddings only once when LineBreaker is started to be used.
b->setLineWidthDelegate(std::make_unique<JNILineBreakerLineWidth>(
- firstWidth, firstWidthLineLimit, restWidth, std::move(indentVec), indentsOffset));
+ firstWidth, firstWidthLineLimit, restWidth, jintArrayToFloatVector(env, indents),
+ jintArrayToFloatVector(env, leftPaddings), jintArrayToFloatVector(env, rightPaddings),
+ indentsAndPaddingsOffset));
}
static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
@@ -171,40 +193,49 @@
b->finish();
}
-static jlong nLoadHyphenator(JNIEnv* env, jclass, jobject buffer, jint offset,
- jint minPrefix, jint minSuffix) {
- const uint8_t* bytebuf = nullptr;
- if (buffer != nullptr) {
- void* rawbuf = env->GetDirectBufferAddress(buffer);
- if (rawbuf != nullptr) {
- bytebuf = reinterpret_cast<const uint8_t*>(rawbuf) + offset;
+class ScopedNullableUtfString {
+public:
+ ScopedNullableUtfString(JNIEnv* env, jstring s) : mEnv(env), mStr(s) {
+ if (s == nullptr) {
+ mUtf8Chars = nullptr;
} else {
- ALOGE("failed to get direct buffer address");
+ mUtf8Chars = mEnv->GetStringUTFChars(s, nullptr);
}
}
- minikin::Hyphenator* hyphenator = minikin::Hyphenator::loadBinary(
- bytebuf, minPrefix, minSuffix);
- return reinterpret_cast<jlong>(hyphenator);
-}
-static void nSetLocales(JNIEnv* env, jclass, jlong nativePtr, jstring javaLocaleNames,
- jlongArray nativeHyphenators) {
- minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
-
- ScopedUtfChars localeNames(env, javaLocaleNames);
- ScopedLongArrayRO hyphArr(env, nativeHyphenators);
- const size_t numLocales = hyphArr.size();
- std::vector<minikin::Hyphenator*> hyphVec;
- hyphVec.reserve(numLocales);
- for (size_t i = 0; i < numLocales; i++) {
- hyphVec.push_back(reinterpret_cast<minikin::Hyphenator*>(hyphArr[i]));
+ ~ScopedNullableUtfString() {
+ if (mUtf8Chars != nullptr) {
+ mEnv->ReleaseStringUTFChars(mStr, mUtf8Chars);
+ }
}
- b->setLocales(localeNames.c_str(), hyphVec);
+
+ const char* get() const {
+ return mUtf8Chars;
+ }
+
+private:
+ JNIEnv* mEnv;
+ jstring mStr;
+ const char* mUtf8Chars;
+};
+
+static std::vector<minikin::Hyphenator*> makeHyphenators(JNIEnv* env, jlongArray hyphenators) {
+ std::vector<minikin::Hyphenator*> out;
+ if (hyphenators == nullptr) {
+ return out;
+ }
+ ScopedLongArrayRO longArray(env, hyphenators);
+ size_t size = longArray.size();
+ out.reserve(size);
+ for (size_t i = 0; i < size; i++) {
+ out.push_back(reinterpret_cast<minikin::Hyphenator*>(longArray[i]));
+ }
+ return out;
}
// Basically similar to Paint.getTextRunAdvances but with C++ interface
static jfloat nAddStyleRun(JNIEnv* env, jclass, jlong nativePtr, jlong nativePaint, jint start,
- jint end, jboolean isRtl) {
+ jint end, jboolean isRtl, jstring langTags, jlongArray hyphenators) {
minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
Paint* paint = reinterpret_cast<Paint*>(nativePaint);
const Typeface* typeface = paint->getAndroidTypeface();
@@ -212,22 +243,18 @@
const Typeface* resolvedTypeface = Typeface::resolveDefault(typeface);
minikin::FontStyle style = MinikinUtils::prepareMinikinPaint(&minikinPaint, paint,
typeface);
- return b->addStyleRun(&minikinPaint, resolvedTypeface->fFontCollection, style, start, end,
- isRtl);
-}
-// Accept width measurements for the run, passed in from Java
-static void nAddMeasuredRun(JNIEnv* env, jclass, jlong nativePtr,
- jint start, jint end, jfloatArray widths) {
- minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
- env->GetFloatArrayRegion(widths, start, end - start, b->charWidths() + start);
- b->addStyleRun(nullptr, nullptr, minikin::FontStyle{}, start, end, false);
+ ScopedNullableUtfString langTagsString(env, langTags);
+ float result = b->addStyleRun(&minikinPaint, resolvedTypeface->fFontCollection, style, start,
+ end, isRtl, langTagsString.get(), makeHyphenators(env, hyphenators));
+ return result;
}
static void nAddReplacementRun(JNIEnv* env, jclass, jlong nativePtr,
- jint start, jint end, jfloat width) {
+ jint start, jint end, jfloat width, jstring langTags, jlongArray hyphenators) {
minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
- b->addReplacement(start, end, width);
+ ScopedNullableUtfString langTagsString(env, langTags);
+ b->addReplacement(start, end, width, langTagsString.get(), makeHyphenators(env, hyphenators));
}
static void nGetWidths(JNIEnv* env, jclass, jlong nativePtr, jfloatArray widths) {
@@ -240,12 +267,9 @@
{"nNewBuilder", "()J", (void*) nNewBuilder},
{"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
{"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
- {"nLoadHyphenator", "(Ljava/nio/ByteBuffer;III)J", (void*) nLoadHyphenator},
- {"nSetLocales", "(JLjava/lang/String;[J)V", (void*) nSetLocales},
- {"nSetupParagraph", "(J[CIFIF[IIIIZ[II)V", (void*) nSetupParagraph},
- {"nAddStyleRun", "(JJIIZ)F", (void*) nAddStyleRun},
- {"nAddMeasuredRun", "(JII[F)V", (void*) nAddMeasuredRun},
- {"nAddReplacementRun", "(JIIF)V", (void*) nAddReplacementRun},
+ {"nSetupParagraph", "(J[CIFIF[IIIIZ[I[I[II)V", (void*) nSetupParagraph},
+ {"nAddStyleRun", "(JJIIZLjava/lang/String;[J)F", (void*) nAddStyleRun},
+ {"nAddReplacementRun", "(JIIFLjava/lang/String;[J)V", (void*) nAddReplacementRun},
{"nGetWidths", "(J[F)V", (void*) nGetWidths},
{"nComputeLineBreaks", "(JLandroid/text/StaticLayout$LineBreaks;[I[F[F[F[II)I",
(void*) nComputeLineBreaks}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index af5d12b..7908c9d 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -513,8 +513,8 @@
private:
JavaVM* const mVM;
- jobject mObject;
- jweak mObjectWeak; // will be a weak ref to the same VM-side DeathRecipient after binderDied()
+ jobject mObject; // Initial strong ref to Java-side DeathRecipient. Cleared on binderDied().
+ jweak mObjectWeak; // weak ref to the same Java-side DeathRecipient after binderDied().
wp<DeathRecipientList> mList;
};
@@ -586,7 +586,7 @@
env->DeleteGlobalRef((jobject)obj);
}
-static Mutex mProxyLock;
+static Mutex gProxyLock;
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
@@ -601,7 +601,7 @@
// For the rest of the function we will hold this lock, to serialize
// looking/creation/destruction of Java proxies for native Binder proxies.
- AutoMutex _l(mProxyLock);
+ AutoMutex _l(gProxyLock);
// Someone else's... do we know about it?
jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
@@ -1277,7 +1277,7 @@
static void android_os_BinderProxy_destroy(JNIEnv* env, jobject obj)
{
// Don't race with construction/initialization
- AutoMutex _l(mProxyLock);
+ AutoMutex _l(gProxyLock);
IBinder* b = (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
diff --git a/core/proto/android/app/notificationmanager.proto b/core/proto/android/app/notificationmanager.proto
new file mode 100644
index 0000000..4dfd0cf
--- /dev/null
+++ b/core/proto/android/app/notificationmanager.proto
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+option java_package = "android.app";
+option java_multiple_files = true;
+
+package android.app;
+
+/**
+ * An android.app.NotificationMananger.Policy object.
+ */
+message PolicyProto {
+ enum Category {
+ CATEGORY_UNKNOWN = 0;
+ // Reminder notifications are prioritized.
+ REMINDERS = 1;
+ // Event notifications are prioritized.
+ EVENTS = 2;
+ // Message notifications are prioritized.
+ MESSAGES = 3;
+ // Calls are prioritized.
+ CALLS = 4;
+ // Calls from repeat callers are prioritized.
+ REPEAT_CALLERS = 5;
+ }
+ repeated Category priority_categories = 1;
+
+ enum Sender {
+ // Any sender is prioritized.
+ ANY = 0;
+ // Saved contacts are prioritized.
+ CONTACTS = 1;
+ // Only starred contacts are prioritized.
+ STARRED = 2;
+ }
+ Sender priority_call_sender = 2;
+ Sender priority_message_sender = 3;
+
+ enum SuppressedVisualEffect {
+ SVE_UNKNOWN = 0;
+ // Whether notifications suppressed by DND should not interrupt visually
+ // (e.g. with notification lights or by turning the screen on) when the
+ // screen is off.
+ SCREEN_OFF = 1;
+ // Whether notifications suppressed by DND should not interrupt visually
+ // when the screen is on (e.g. by peeking onto the screen).
+ SCREEN_ON = 2;
+ }
+ repeated SuppressedVisualEffect suppressed_visual_effects = 4;
+}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index bce10dc..e823561 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -71,15 +71,28 @@
(section).args = "fingerprint --proto --incident"
];
- android.service.NetworkStatsServiceDumpProto netstats = 3001;
+ android.service.NetworkStatsServiceDumpProto netstats = 3001 [
+ (section).type = SECTION_DUMPSYS,
+ (section).args = "netstats --proto"
+ ];
+
android.providers.settings.SettingsServiceDumpProto settings = 3002;
android.service.appwidget.AppWidgetServiceDumpProto appwidget = 3003;
android.service.notification.NotificationServiceDumpProto notification = 3004 [
(section).type = SECTION_DUMPSYS,
(section).args = "notification --proto"
];
- android.service.battery.BatteryServiceDumpProto battery = 3006;
- android.service.diskstats.DiskStatsServiceDumpProto diskstats = 3007;
+
+ android.service.battery.BatteryServiceDumpProto battery = 3006 [
+ (section).type = SECTION_DUMPSYS,
+ (section).args = "battery --proto"
+ ];
+
+ android.service.diskstats.DiskStatsServiceDumpProto diskstats = 3007 [
+ (section).type = SECTION_DUMPSYS,
+ (section).args = "diskstats --proto"
+ ];
+
android.service.pm.PackageServiceDumpProto package = 3008;
android.service.power.PowerServiceDumpProto power = 3009;
android.service.print.PrintServiceDumpProto print = 3010;
diff --git a/core/proto/android/service/diskstats.proto b/core/proto/android/service/diskstats.proto
index 4d86526..4057e45 100644
--- a/core/proto/android/service/diskstats.proto
+++ b/core/proto/android/service/diskstats.proto
@@ -47,7 +47,7 @@
}
message DiskStatsCachedValuesProto {
- // Total app data size, in kilobytes
+ // Total app code size, in kilobytes
int64 agg_apps_size = 1;
// Total app cache size, in kilobytes
int64 agg_apps_cache_size = 2;
@@ -65,15 +65,19 @@
int64 other_size = 8;
// Sizes of individual packages
repeated DiskStatsAppSizesProto app_sizes = 9;
+ // Total app data size, in kilobytes
+ int64 agg_apps_data_size = 10;
}
message DiskStatsAppSizesProto {
// Name of the package
string package_name = 1;
- // App's data size in kilobytes
+ // App's code size in kilobytes
int64 app_size = 2;
// App's cache size in kilobytes
int64 cache_size = 3;
+ // App's data size in kilobytes
+ int64 app_data_size = 4;
}
message DiskStatsFreeSpaceProto {
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index a8482a1..05afe52 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -21,6 +21,7 @@
option java_multiple_files = true;
option java_outer_classname = "NotificationServiceProto";
+import "frameworks/base/core/proto/android/app/notificationmanager.proto";
import "frameworks/base/core/proto/android/content/component_name.proto";
message NotificationServiceDumpProto {
@@ -98,7 +99,7 @@
repeated string enabled_active_conditions = 2;
int32 suppressed_effects = 3;
repeated string suppressors = 4;
- string policy = 5;
+ android.app.PolicyProto policy = 5;
}
enum ZenMode {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 695fdac..4159c21 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1873,11 +1873,11 @@
<!-- @SystemApi @hide Allows an application to create/manage/remove stacks -->
<permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi @hide Allows an application to embed other activities -->
<permission android:name="android.permission.ACTIVITY_EMBEDDING"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged|development" />
<!-- Allows an application to start any activity, regardless of permission
protection or exported state.
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
index 76b3528..ee5c758 100644
--- a/core/res/res/layout/notification_template_material_ambient.xml
+++ b/core/res/res/layout/notification_template_material_ambient.xml
@@ -70,6 +70,8 @@
android:textSize="16sp"
android:textColor="#eeffffff"
android:layout_marginTop="4dp"
+ android:ellipsize="end"
+ android:maxLines="7"
/>
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index c734cfa..9e4184b 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Foon"</string>
<string name="map" msgid="6068210738233985748">"Kaarte"</string>
<string name="browse" msgid="6993590095938149861">"Blaaier"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Bergingspasie word min"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sommige stelselfunksies werk moontlik nie"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nie genoeg berging vir die stelsel nie. Maak seker jy het 250 MB spasie beskikbaar en herbegin."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Kanselleer"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Kanselleer"</string>
+ <string name="close" msgid="2318214661230355730">"MAAK TOE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Aandag"</string>
<string name="loading" msgid="7933681260296021180">"Laai tans..."</string>
<string name="capital_on" msgid="1544682755514494298">"AAN"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skaal"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Wys altyd"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Heraktiveer hierdie in Stelselinstellings > Programme > Afgelaai."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Program reageer nie"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> gebruik dalk te veel berging."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie die huidige skermgrootte-instelling nie en sal dalk onverwags reageer."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Wys altyd"</string>
<string name="smv_application" msgid="3307209192155442829">"Die program <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) het sy selfopgelegde StrictMode-beleid oortree."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Foon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dokluidsprekers"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Oorfone"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Stelsel"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-oudio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Draadlose skerm"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 43c1dc48..00257ee 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ስልክ"</string>
<string name="map" msgid="6068210738233985748">"ካርታዎች"</string>
<string name="browse" msgid="6993590095938149861">"አሳሽ"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"የማከማቻ ቦታ እያለቀ ነው"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"አንዳንድ የስርዓት ተግባራት ላይሰሩ ይችላሉ"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ለስርዓቱ የሚሆን በቂ ቦታ የለም። 250 ሜባ ነጻ ቦታ እንዳለዎት ያረጋግጡና ዳግም ያስጀምሩ።"</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"ይቅር"</string>
<string name="yes" msgid="5362982303337969312">"እሺ"</string>
<string name="no" msgid="5141531044935541497">"ይቅር"</string>
+ <string name="close" msgid="2318214661230355730">"ዝጋ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ትኩረት"</string>
<string name="loading" msgid="7933681260296021180">"በመጫን ላይ…"</string>
<string name="capital_on" msgid="1544682755514494298">"በ"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"የልኬት ለውጥ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ሁልጊዜ አሳይ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"በስርዓት ቅንብሮች ውስጥ ይሄንን ዳግም አንቃ> Apps &gt፤ወርዷል፡፡"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"መተግበሪያው ምላሽ እየሰጠ አይደለም"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> በጣም ብዙ ማህደረ ትውስታ እየተጠቀመ ሊሆን ይችላል።"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> አሁን ያለውን የማሳያ መጠን ቅንብር አይደግፍም እና ያልተጠብቀ ባሕሪ ሊያሳይ ይችላል።"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ሁልጊዜ አሳይ"</string>
<string name="smv_application" msgid="3307209192155442829">"መተግበሪያው <xliff:g id="APPLICATION">%1$s</xliff:g>( ሂደት<xliff:g id="PROCESS">%2$s</xliff:g>) በራስ ተነሳሺ StrictMode ደንብን ይተላለፋል።"</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ቴሌቪዥን"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ስልክ"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"የትከል ድምፅ ማጉያዎች"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"ኤችዲኤምአይ"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"የጆሮ ማዳመጫዎች"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"ዩ ኤስ ቢ"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"ስርዓት"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"የብሉቱዝ ድምጽ"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"ገመድ አልባ ማሳያ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index d248428..8f78cfa 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1060,6 +1060,10 @@
<string name="dial" msgid="4204975095406423102">"الهاتف"</string>
<string name="map" msgid="6068210738233985748">"الخرائط"</string>
<string name="browse" msgid="6993590095938149861">"المتصفح"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"مساحة التخزين منخفضة"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"قد لا تعمل بعض وظائف النظام"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ليست هناك سعة تخزينية كافية للنظام. تأكد من أنه لديك مساحة خالية تبلغ ٢٥٠ ميغابايت وأعد التشغيل."</string>
@@ -1069,6 +1073,7 @@
<string name="cancel" msgid="6442560571259935130">"إلغاء"</string>
<string name="yes" msgid="5362982303337969312">"حسنًا"</string>
<string name="no" msgid="5141531044935541497">"إلغاء"</string>
+ <string name="close" msgid="2318214661230355730">"إغلاق"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"تنبيه"</string>
<string name="loading" msgid="7933681260296021180">"جارٍ التحميل…"</string>
<string name="capital_on" msgid="1544682755514494298">"تشغيل"</string>
@@ -1125,6 +1130,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"تدرج"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"الإظهار دائمًا"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"يمكنك إعادة تمكين هذا في إعدادات النظام > التطبيقات > ما تم تنزيله."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"التطبيق لا يستجيب"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"ربما يشغل <xliff:g id="APP_NAME">%1$s</xliff:g> مساحة كبيرة جدًا من الذاكرة."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> غير متوافق مع الإعداد الحالي لحجم شاشة العرض وربما يعمل بطريقة غير متوقعة."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"العرض دائمًا"</string>
<string name="smv_application" msgid="3307209192155442829">"انتهك التطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> (العملية <xliff:g id="PROCESS">%2$s</xliff:g>) سياسة StrictMode المفروضة ذاتيًا."</string>
@@ -1513,11 +1520,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"التلفزيون"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"الهاتف"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"مكبرات صوت للإرساء"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"سماعات رأس"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"النظام"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"صوت بلوتوث"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"عرض شاشة لاسلكي"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index bd711bf..97a67e0 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Xəritə"</string>
<string name="browse" msgid="6993590095938149861">"Brauzer"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Yaddaş yeri bitir"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bəzi sistem funksiyaları işləməyə bilər"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistem üçün yetərincə yaddaş ehtiyatı yoxdur. 250 MB yaddaş ehtiyatının olmasına əmin olun və yenidən başladın."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Ləğv et"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Ləğv et"</string>
+ <string name="close" msgid="2318214661230355730">"BAĞLAYIN"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Diqqət"</string>
<string name="loading" msgid="7933681260296021180">"Yüklənir…"</string>
<string name="capital_on" msgid="1544682755514494298">"AÇIQ"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Miqyas"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Həmişə göstər"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bunları Sistem ayarlarında yenidən aktivləşdir Yüklənmiş > Tətbiqlər >."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Tətbiq cavab vermir"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> daha çox yaddaş istifadə edə bilər."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> cari Ekran ölçüsü ayarını dəstəkləmir və gözlənilməz şəkildə davrana bilər."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Həmişə göstərin"</string>
<string name="smv_application" msgid="3307209192155442829">"Tətbiq <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) StrictMode siyasətini pozdu."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dok spikerlər"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Qulaqlıq"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Simsiz ekran"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 621185c0..2daf942 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1000,6 +1000,10 @@
<string name="dial" msgid="4204975095406423102">"Pozovi"</string>
<string name="map" msgid="6068210738233985748">"Mape"</string>
<string name="browse" msgid="6993590095938149861">"Pregledač"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Memorijski prostor je na izmaku"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda ne funkcionišu"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno memorijskog prostora za sistem. Uverite se da imate 250 MB slobodnog prostora i ponovo pokrenite."</string>
@@ -1009,6 +1013,7 @@
<string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
<string name="yes" msgid="5362982303337969312">"Potvrdi"</string>
<string name="no" msgid="5141531044935541497">"Otkaži"</string>
+ <string name="close" msgid="2318214661230355730">"ZATVORI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Pažnja"</string>
<string name="loading" msgid="7933681260296021180">"Učitava se…"</string>
<string name="capital_on" msgid="1544682755514494298">"DA"</string>
@@ -1065,6 +1070,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Razmera"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Uvek prikazuj"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ponovo omogućite u meniju Sistemska podešavanja > Aplikacije > Preuzeto."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacija ne reaguje"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> možda koristi previše memorije."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava trenutno podešavanje veličine prikaza i može da se ponaša neočekivano."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Uvek prikazuj"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) je prekršila samonametnute StrictMode smernice."</string>
@@ -1444,11 +1451,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Zvučnici bazne stanice"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Slušalice"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Bežični ekran"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index d4808d0..c89987b 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Тэлефон"</string>
<string name="map" msgid="6068210738233985748">"Карты"</string>
<string name="browse" msgid="6993590095938149861">"Браўзер"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Месца для захавання на зыходзе"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некаторыя сістэмныя функцыі могуць не працаваць"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Не хапае сховішча для сістэмы. Пераканайцеся, што ў вас ёсць 250 МБ свабоднага месца, і перазапусціце."</string>
@@ -1029,6 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Скасаваць"</string>
<string name="yes" msgid="5362982303337969312">"ОК"</string>
<string name="no" msgid="5141531044935541497">"Скасаваць"</string>
+ <string name="close" msgid="2318214661230355730">"ЗАКРЫЦЬ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Увага"</string>
<string name="loading" msgid="7933681260296021180">"Загрузка..."</string>
<string name="capital_on" msgid="1544682755514494298">"Уключыць"</string>
@@ -1085,6 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Шкала"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Заўсёды паказваць"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Зноў уключыце гэта ў раздзеле \"Сістэмныя налады > Прыкладанні > Спампаваныя\"."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Праграма не адказвае"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> можа выкарыстоўваць занадта шмат памяці."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае бягучую наладу Памеру дысплэя і можа паводзіць сябе непрадказальным чынам."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Заўсёды паказваць"</string>
<string name="smv_application" msgid="3307209192155442829">"Прыкладанне <xliff:g id="APPLICATION">%1$s</xliff:g> (працэс <xliff:g id="PROCESS">%2$s</xliff:g>) парушыла ўласную палітыку StrictMode."</string>
@@ -1467,11 +1474,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ТБ"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Тэлефон"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Дынамікі станцыi"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Навушнікі"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Сістэма"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-аўдыё"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Бесправадны дысплей"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 70870ec..07bdc3d 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Телефон"</string>
<string name="map" msgid="6068210738233985748">"Карти"</string>
<string name="browse" msgid="6993590095938149861">"Браузър"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Мястото в хранилището е на изчерпване"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Възможно е някои функции на системата да не работят"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"За системата няма достатъчно място в хранилището. Уверете се, че имате свободни 250 МБ, и рестартирайте."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Отказ"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Отказ"</string>
+ <string name="close" msgid="2318214661230355730">"ЗАТВАРЯНЕ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Внимание"</string>
<string name="loading" msgid="7933681260296021180">"Зарежда се..."</string>
<string name="capital_on" msgid="1544682755514494298">"ВКЛ"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Мащаб"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Винаги да се показва"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Активирайте отново това в „Системни настройки“ > „Приложения“ > „Изтеглени“."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Приложението не реагира"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Възможно е <xliff:g id="APP_NAME">%1$s</xliff:g> да използва твърде много памет."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа текущата настройка за размер на дисплея и може да се държи по неочакван начин."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Винаги да се показва"</string>
<string name="smv_application" msgid="3307209192155442829">"Приложението „<xliff:g id="APPLICATION">%1$s</xliff:g>“ (процес „<xliff:g id="PROCESS">%2$s</xliff:g>“) наруши правилото за стриктен режим, наложено от самото него."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевизор"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Телефон"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Докинг станц.: Високогов."</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Слушалки"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Звук през Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Безжичен дисплей"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 49b2ccc..5d19486 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ফোন করুন"</string>
<string name="map" msgid="6068210738233985748">"মানচিত্র"</string>
<string name="browse" msgid="6993590095938149861">"ব্রাউজার"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"স্টোরেজ পূর্ণ হতে চলেছে"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"কিছু কিছু সিস্টেম ক্রিয়াকলাপ কাজ নাও করতে পারে"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"সিস্টেমের জন্য যথেষ্ট স্টোরেজ নেই৷ আপনার কাছে ২৫০এমবি ফাঁকা স্থান রয়েছে কিনা সে বিষয়ে নিশ্চিত হন এবং সিস্টেম চালু করুন৷"</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"বাতিল করুন"</string>
<string name="yes" msgid="5362982303337969312">"ঠিক আছে"</string>
<string name="no" msgid="5141531044935541497">"বাতিল করুন"</string>
+ <string name="close" msgid="2318214661230355730">"বন্ধ করুন"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"খেয়াল করুন"</string>
<string name="loading" msgid="7933681260296021180">"লোড হচ্ছে..."</string>
<string name="capital_on" msgid="1544682755514494298">"চালু করুন"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"স্কেল"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"সবসময় দেখান"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"সিস্টেম সেটিংস> অ্যাপ্স> ডাউনলোড করাগুলি এ এটি পুনঃসক্ষম করুন৷"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"অ্যাপটি সাড়া দিচ্ছে না"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"মনে হচ্ছে <xliff:g id="APP_NAME">%1$s</xliff:g> খুব বেশি মেমরি ব্যবহার করছে।"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>, বর্তমান প্রদর্শনের আকারের সেটিংস সমর্থন করে না এবং অপ্রত্যাশিত আচরণ করতে পারে৷"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"সর্বদা দেখান"</string>
<string name="smv_application" msgid="3307209192155442829">"অ্যাপ্লিকেশানটি <xliff:g id="APPLICATION">%1$s</xliff:g> (প্রক্রিয়া <xliff:g id="PROCESS">%2$s</xliff:g>) তার স্ব-প্রয়োগ করা কঠোর মোড নীতি লঙ্ঘন করেছে৷"</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"টিভি"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ফোন"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ডক স্পিকার"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"হেডফোন"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"সিস্টেম"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ব্লুটুথ অডিও"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"ওয়্যারলেস প্রদর্শন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 3860106..31ecfc5 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -980,7 +980,7 @@
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Odaberi sve"</string>
<string name="cut" msgid="3092569408438626261">"Izreži"</string>
- <string name="copy" msgid="2681946229533511987">"Kopirajte"</string>
+ <string name="copy" msgid="2681946229533511987">"Kopiraj"</string>
<string name="failed_to_copy_to_clipboard" msgid="1833662432489814471">"Kopiranje u spremnik nije uspjelo"</string>
<string name="paste" msgid="5629880836805036433">"Zalijepi"</string>
<string name="paste_as_plain_text" msgid="5427792741908010675">"Zalijepi kao neformatiran tekst"</string>
@@ -1000,6 +1000,10 @@
<string name="dial" msgid="4204975095406423102">"Pozovi"</string>
<string name="map" msgid="6068210738233985748">"Mape"</string>
<string name="browse" msgid="6993590095938149861">"Preglednik"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ponestaje prostora za pohranu"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke funkcije sistema možda neće raditi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno prostora za sistem. Obezbijedite 250MB slobodnog prostora i ponovo pokrenite uređaj."</string>
@@ -1009,6 +1013,7 @@
<string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
<string name="yes" msgid="5362982303337969312">"Uredu"</string>
<string name="no" msgid="5141531044935541497">"Otkaži"</string>
+ <string name="close" msgid="2318214661230355730">"ZATVORI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Pažnja"</string>
<string name="loading" msgid="7933681260296021180">"Učitavanje..."</string>
<string name="capital_on" msgid="1544682755514494298">"Uključeno"</string>
@@ -1067,6 +1072,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Razmjer"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Uvijek prikaži"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ponovo omogućite ovu opciju u meniju Postavke sistema > Aplikacije > Preuzete aplikacije."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacija ne reagira"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Moguće je da aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> koristi previše memorije."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava trenutnu postavku veličine ekrana i može se ponašati neočekivano."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Uvijek prikaži"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) prekršila je vlastita StrictMode pravila."</string>
@@ -1078,7 +1085,7 @@
<string name="android_upgrading_notification_body" msgid="5761201379457064286">"Neke aplikacije možda neće raditi ispravno dok traje nadogradnja"</string>
<string name="app_upgrading_toast" msgid="3008139776215597053">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> se nadograđuje…"</string>
<string name="android_upgrading_apk" msgid="7904042682111526169">"Optimiziranje aplikacije <xliff:g id="NUMBER_0">%1$d</xliff:g> od <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
- <string name="android_preparing_apk" msgid="8162599310274079154">"Priprema se <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
+ <string name="android_preparing_apk" msgid="8162599310274079154">"Pripremanje aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Pokretanje aplikacija."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Pokretanje pri kraju."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Pokrenuta je aplikacija <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1446,11 +1453,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Zvučnici priključne stanice"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Slušalice"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Bežični prikaz"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 3475891..082513d 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Truca"</string>
<string name="map" msgid="6068210738233985748">"Mapes"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"L\'espai d\'emmagatzematge s\'està esgotant"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"És possible que algunes funcions del sistema no funcionin"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"No hi ha prou espai d\'emmagatzematge per al sistema. Comprova que tinguis 250 MB d\'espai lliure i reinicia."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancel·la"</string>
<string name="yes" msgid="5362982303337969312">"D\'acord"</string>
<string name="no" msgid="5141531044935541497">"Cancel·la"</string>
+ <string name="close" msgid="2318214661230355730">"TANCA"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atenció"</string>
<string name="loading" msgid="7933681260296021180">"S\'està carregant…"</string>
<string name="capital_on" msgid="1544682755514494298">"SÍ"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostra sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Torna a activar-ho a Configuració del sistema > Aplicacions > Baixades."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"L\'aplicació no respon"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"És possible que <xliff:g id="APP_NAME">%1$s</xliff:g> faci servir massa memòria."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet la mida de pantalla actual i és possible que funcioni de manera inesperada."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostra sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g>(procés <xliff:g id="PROCESS">%2$s</xliff:g>) ha incomplert la seva política autoimposada de mode estricte."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televisor"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telèfon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altaveus de la base"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Auriculars"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Àudio per Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla sense fil"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 09e156d..23f3cb9 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Mapy"</string>
<string name="browse" msgid="6993590095938149861">"Prohlížeč"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"V úložišti je málo místa"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Některé systémové funkce nemusí fungovat"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Pro systém není dostatek místa v úložišti. Uvolněte alespoň 250 MB místa a restartujte zařízení."</string>
@@ -1029,6 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Zrušit"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Zrušit"</string>
+ <string name="close" msgid="2318214661230355730">"ZAVŘÍT"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Upozornění"</string>
<string name="loading" msgid="7933681260296021180">"Načítání..."</string>
<string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1085,6 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Měřítko"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vždy zobrazovat"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Tento režim znovu povolíte v sekci Nastavení systému > Aplikace > Stažené."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikace nereaguje"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> pravděpodobně využívá příliš mnoho paměti."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> aktuální nastavení velikosti zobrazení nepodporuje a může se chovat neočekávaně."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vždy zobrazovat"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila své vlastní vynucené zásady StrictMode."</string>
@@ -1467,11 +1474,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televize"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Reproduktory doku"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Sluchátka"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth Audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Bezdrátový displej"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 5ee109d..9360cbe 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Opkald"</string>
<string name="map" msgid="6068210738233985748">"Kort"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der er snart ikke mere lagerplads"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Nogle systemfunktioner virker måske ikke"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Der er ikke nok ledig lagerplads til systemet. Sørg for, at du har 250 MB ledig plads, og genstart."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Annuller"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Annuller"</string>
+ <string name="close" msgid="2318214661230355730">"LUK"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Bemærk"</string>
<string name="loading" msgid="7933681260296021180">"Indlæser…"</string>
<string name="capital_on" msgid="1544682755514494298">"TIL"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skaler"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vis altid"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivér dette igen i Systemindstillinger > Apps > Downloadet."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Appen svarer ikke"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruger muligvis for meget hukommelse."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke den aktuelle indstilling for visningsstørrelse og vil muligvis ikke fungere som forventet."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vis altid"</string>
<string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) har overtrådt sin egen StrictMode-politik."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tv"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dockstationens højttalere"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Hovedtelefoner"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Trådløs skærm"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 3585d4c..8b31d96 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Karten"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der Speicherplatz wird knapp"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Einige Systemfunktionen funktionieren möglicherweise nicht."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Der Speicherplatz reicht nicht für das System aus. Stelle sicher, dass 250 MB freier Speicherplatz vorhanden sind, und starte das Gerät dann neu."</string>
@@ -989,6 +993,8 @@
<string name="cancel" msgid="6442560571259935130">"Abbrechen"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Abbrechen"</string>
+ <!-- no translation found for close (2318214661230355730) -->
+ <skip />
<string name="dialog_alert_title" msgid="2049658708609043103">"Achtung"</string>
<string name="loading" msgid="7933681260296021180">"Wird geladen…"</string>
<string name="capital_on" msgid="1544682755514494298">"AN"</string>
@@ -1045,6 +1051,10 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skalieren"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Immer anzeigen"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Eine erneute Aktivierung ist in den Systemeinstellungen unter \"Apps > Heruntergeladen\" möglich."</string>
+ <!-- no translation found for top_app_killed_title (6814231368167994497) -->
+ <skip />
+ <!-- no translation found for top_app_killed_message (3487519022191609844) -->
+ <skip />
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt nicht die aktuelle Einstellung für die Anzeigegröße, sodass ein unerwartetes Verhalten auftreten kann."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Immer anzeigen"</string>
<string name="smv_application" msgid="3307209192155442829">"Die App <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) hat gegen deine selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
@@ -1421,11 +1431,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dock-Lautsprecher"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Kopfhörer"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-Audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Kabellose Übertragung (WiDi)"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index c20ba6e..19aafc8 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Τηλέφωνο"</string>
<string name="map" msgid="6068210738233985748">"Χάρτες"</string>
<string name="browse" msgid="6993590095938149861">"Πρόγραμμα περιήγησης"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ο αποθηκευτικός χώρος εξαντλείται"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Ορισμένες λειτουργίες συστήματος ενδέχεται να μην λειτουργούν"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Δεν υπάρχει αρκετός αποθηκευτικός χώρος για το σύστημα. Βεβαιωθείτε ότι διαθέτετε 250 MB ελεύθερου χώρου και κάντε επανεκκίνηση."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Ακύρωση"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Ακύρωση"</string>
+ <string name="close" msgid="2318214661230355730">"ΚΛΕΙΣΙΜΟ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Προσοχή"</string>
<string name="loading" msgid="7933681260296021180">"Φόρτωση…"</string>
<string name="capital_on" msgid="1544682755514494298">"Ενεργό"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Κλίμακα"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Να εμφανίζονται πάντα"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ενεργοποιήστε το ξανά στις Ρυθμίσεις συστημάτων > Εφαρμογές > Ληφθείσες."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Η εφαρμογή δεν αποκρίνεται"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> μπορεί να χρησιμοποιεί υπερβολική μνήμη."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει την τρέχουσα ρύθμιση Μεγέθους οθόνης και ενδέχεται να παρουσιάζει μη αναμενόμενη συμπεριφορά."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Να εμφανίζεται πάντα"</string>
<string name="smv_application" msgid="3307209192155442829">"Η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> (διεργασία <xliff:g id="PROCESS">%2$s</xliff:g>) παραβίασε την αυτοεπιβαλλόμενη πολιτική StrictMode."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Τηλεόραση"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Τηλέφωνο"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Ηχεία βάσης σύνδεσης"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Ακουστικά"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Σύστημα"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Ήχος Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Ασύρματη οθόνη"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index afddfc4..7fff878 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Phone"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancel"</string>
+ <string name="close" msgid="2318214661230355730">"CLOSE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"App isn\'t responding"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> may be using too much memory."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Phone"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dock speakers"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Headphones"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index afddfc4..7fff878 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Phone"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancel"</string>
+ <string name="close" msgid="2318214661230355730">"CLOSE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"App isn\'t responding"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> may be using too much memory."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Phone"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dock speakers"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Headphones"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index afddfc4..7fff878 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Phone"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancel"</string>
+ <string name="close" msgid="2318214661230355730">"CLOSE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"App isn\'t responding"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> may be using too much memory."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Phone"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dock speakers"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Headphones"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index afddfc4..7fff878 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Phone"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancel"</string>
+ <string name="close" msgid="2318214661230355730">"CLOSE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"App isn\'t responding"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> may be using too much memory."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced Strict Mode policy."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Phone"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dock speakers"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Headphones"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index e4a69ab..b93db1c 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Phone"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure you have 250MB of free space and restart."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancel"</string>
+ <string name="close" msgid="2318214661230355730">"CLOSE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings > Apps > Downloaded."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"App isn\'t responding"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> may be using too much memory."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Always show"</string>
<string name="smv_application" msgid="3307209192155442829">"The app <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced StrictMode policy."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Phone"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dock speakers"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Headphones"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 0261363..3946e7d 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Teléfono"</string>
<string name="map" msgid="6068210738233985748">"Mapas"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Queda poco espacio de almacenamiento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Es posible que algunas funciones del sistema no estén disponibles."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"No hay espacio suficiente para el sistema. Asegúrate de que haya 250 MB libres y reinicia el dispositivo."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="yes" msgid="5362982303337969312">"Aceptar"</string>
<string name="no" msgid="5141531044935541497">"Cancelar"</string>
+ <string name="close" msgid="2318214661230355730">"CERRAR"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
<string name="loading" msgid="7933681260296021180">"Cargando…"</string>
<string name="capital_on" msgid="1544682755514494298">"Sí"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar siempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Volver a activar Configuración del sistema > Aplicaciones > Descargas"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"La app no responde"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Es posible que <xliff:g id="APP_NAME">%1$s</xliff:g> esté consumiendo demasiada memoria."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no es compatible con la configuración del tamaño de pantalla actual. Es posible que no se comporte de manera correcta."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar siempre"</string>
<string name="smv_application" msgid="3307209192155442829">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode de aplicación automática."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Dispositivo"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altavoces del conector"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Auriculares"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla inalámbrica"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 6a5d3a9..7085fda 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -524,12 +524,12 @@
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string>
<string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y borre notificaciones, incluidas las que han publicado otras aplicaciones."</string>
- <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"enlazar con un servicio de detector de notificaciones"</string>
- <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite enlazar con la interfaz de nivel superior de un servicio de detector de notificaciones. No debe ser necesario para las aplicaciones normales."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"enlazar con un servicio de proveedor de condiciones"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite enlazar con la interfaz de nivel superior de un servicio de proveedor de condiciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <string name="permlab_bindDreamService" msgid="4153646965978563462">"enlazar con un servicio de salvapantallas"</string>
- <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permite enlazar con la interfaz de nivel superior de un servicio de salvapantallas. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincular con un servicio de detector de notificaciones"</string>
+ <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite vincular con la interfaz de nivel superior de un servicio de detector de notificaciones. No debe ser necesario para las aplicaciones normales."</string>
+ <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vincular con un servicio de proveedor de condiciones"</string>
+ <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite vincular con la interfaz de nivel superior de un servicio de proveedor de condiciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_bindDreamService" msgid="4153646965978563462">"vincular con un servicio de salvapantallas"</string>
+ <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permite vincular con la interfaz de nivel superior de un servicio de salvapantallas. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ejecutar la aplicación de configuración proporcionada por el operador"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite ejecutar la aplicación de configuración proporcionada por el operador. No debe ser necesario para aplicaciones normales."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"detectar cambios en el estado de la red"</string>
@@ -542,10 +542,10 @@
<string name="permdesc_handoverStatus" msgid="4788144087245714948">"Permite que esta aplicación reciba información sobre las transferencias actuales de Android Beam"</string>
<string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"quitar certificados DRM"</string>
<string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Permite a una aplicación eliminar los certificados DRM. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"enlazar con el servicio de mensajería de un operador"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite enlazar con la interfaz de nivel superior del servicio de mensajería de un operador. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"enlazar con servicios de operador"</string>
- <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Permite enlazar con servicios de operador. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"vincular con el servicio de mensajería de un operador"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite vincular con la interfaz de nivel superior del servicio de mensajería de un operador. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"vincular con servicios de operador"</string>
+ <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Permite vincular con servicios de operador. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_access_notification_policy" msgid="4247510821662059671">"acceso a No molestar"</string>
<string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Permite que la aplicación lea y modifique la configuración de No molestar."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string>
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Teléfono"</string>
<string name="map" msgid="6068210738233985748">"Mapas"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Queda poco espacio"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Es posible que algunas funciones del sistema no funcionen."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"No hay espacio suficiente para el sistema. Comprueba que haya 250 MB libres y reinicia el dispositivo."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="yes" msgid="5362982303337969312">"Aceptar"</string>
<string name="no" msgid="5141531044935541497">"Cancelar"</string>
+ <string name="close" msgid="2318214661230355730">"CERRAR"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
<string name="loading" msgid="7933681260296021180">"Cargando..."</string>
<string name="capital_on" msgid="1544682755514494298">"ACTIVADO"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar siempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Para volver a habilitar esta opción, accede a Ajustes > Aplicaciones > Descargadas."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"La aplicación no responde"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Es posible que <xliff:g id="APP_NAME">%1$s</xliff:g> esté usando demasiada memoria."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite el tamaño de pantalla actual y es posible que funcione de forma inesperada."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar siempre"</string>
<string name="smv_application" msgid="3307209192155442829">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode autoaplicable."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Teléfono"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altavoces de la base"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Auriculares"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla inalámbrica"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 267cd9d..2565e62 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"Brauser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Talletusruum saab täis"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Mõned süsteemifunktsioonid ei pruugi töötada"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Süsteemis pole piisavalt talletusruumi. Veenduge, et seadmes oleks 250 MB vaba ruumi, ja käivitage seade uuesti."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Tühista"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Tühista"</string>
+ <string name="close" msgid="2318214661230355730">"SULGE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Tähelepanu"</string>
<string name="loading" msgid="7933681260296021180">"Laadimine ..."</string>
<string name="capital_on" msgid="1544682755514494298">"SEES"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mõõtkava"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Kuva alati"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Lubage see uuesti valikutes Süsteemiseaded > Rakendused > Allalaaditud."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Rakendus ei reageeri"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Võimalik, et rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> kasutab liiga palju mälu."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta praegust ekraani suuruse seadet ja võib ootamatult käituda."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Kuva alati"</string>
<string name="smv_application" msgid="3307209192155442829">"Rakendus <xliff:g id="APPLICATION">%1$s</xliff:g> (protsess <xliff:g id="PROCESS">%2$s</xliff:g>) on rikkunud isekehtestatud StrictMode\'i eeskirju."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Teler"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Doki kõlarid"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Kõrvaklapid"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Süsteem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-heli"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Juhtmeta ekraan"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 20cefa8..f88d4c4 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefonoa"</string>
<string name="map" msgid="6068210738233985748">"Mapak"</string>
<string name="browse" msgid="6993590095938149861">"Arakatzailea"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Memoria betetzen ari da"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sistemaren funtzio batzuek ez dute agian funtzionatuko"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sisteman ez dago behar adina memoria. Ziurtatu gutxienez 250 MB erabilgarri dituzula eta, ondoren, berrabiarazi gailua."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Utzi"</string>
<string name="yes" msgid="5362982303337969312">"Ados"</string>
<string name="no" msgid="5141531044935541497">"Utzi"</string>
+ <string name="close" msgid="2318214661230355730">"ITXI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Abisua"</string>
<string name="loading" msgid="7933681260296021180">"Kargatzen…"</string>
<string name="capital_on" msgid="1544682755514494298">"AKTIBATUTA"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Eskala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Erakutsi beti"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Gaitu hori berriro Sistemaren ezarpenak > Aplikazioak > Deskargatutakoak."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikazioak ez du erantzuten"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> memoria gehiegi erabiltzen ari liteke."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez du onartzen uneko pantailaren tamaina eta espero ez bezala joka lezake."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Erakutsi beti"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioak (<xliff:g id="PROCESS">%2$s</xliff:g> prozesua) berak aplikatutako StrictMode gidalerroa urratu du."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Telebista"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefonoa"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Konektatu bozgorailuak oinarrira"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Aurikularrak"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetootharen audioa"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Hari gabeko pantaila"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 320ab80..2bd7696 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"تلفن"</string>
<string name="map" msgid="6068210738233985748">"نقشهها"</string>
<string name="browse" msgid="6993590095938149861">"مرورگر"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"حافظه درحال پر شدن است"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"برخی از عملکردهای سیستم ممکن است کار نکنند"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"فضای ذخیرهسازی سیستم کافی نیست. اطمینان حاصل کنید که دارای ۲۵۰ مگابایت فضای خالی هستید و سیستم را راهاندازی مجدد کنید."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"لغو"</string>
<string name="yes" msgid="5362982303337969312">"تأیید"</string>
<string name="no" msgid="5141531044935541497">"لغو"</string>
+ <string name="close" msgid="2318214661230355730">"بستن"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"توجه"</string>
<string name="loading" msgid="7933681260296021180">"در حال بارکردن…"</string>
<string name="capital_on" msgid="1544682755514494298">"روشن"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"مقیاس"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"همیشه نشان داده شود"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"در تنظیمات سیستم >برنامهها > مورد بارگیری شده آن را دوباره فعال کنید."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"برنامه پاسخ نمیدهد"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ممکن است حافظه خیلی زیادی مصرف کند."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> از تنظیم فعلی اندازه نمایشگر پشتیبانی نمیکند و ممکن است رفتار غیرمنتظرهای داشته باشد."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"همیشه نشان داده شود"</string>
<string name="smv_application" msgid="3307209192155442829">"برنامه <xliff:g id="APPLICATION">%1$s</xliff:g> (پردازش <xliff:g id="PROCESS">%2$s</xliff:g>) خطمشی StrictMode اجرایی خود را نقض کرده است."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"تلویزیون"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"تلفن"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"بلندگوهای جایگاه"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"هدفونها"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"سیستم"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوتوثهای صوتی"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"صفحه نمایش بیسیم"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 62b0486..c2a2ccb 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Puhelin"</string>
<string name="map" msgid="6068210738233985748">"Kartat"</string>
<string name="browse" msgid="6993590095938149861">"Selain"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Tallennustila loppumassa"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Kaikki järjestelmätoiminnot eivät välttämättä toimi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Tallennustila ei riitä. Varmista, että vapaata tilaa on 250 Mt, ja käynnistä uudelleen."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Peruuta"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Peruuta"</string>
+ <string name="close" msgid="2318214661230355730">"SULJE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Huomio"</string>
<string name="loading" msgid="7933681260296021180">"Ladataan…"</string>
<string name="capital_on" msgid="1544682755514494298">"PÄÄLLÄ"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Asteikko"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Näytä aina"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ota tämä uudelleen käyttöön kohdassa Järjestelmäasetukset > Sovellukset > Ladattu."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Sovellus ei vastaa"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> saattaa käyttää liikaa muistia."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue nykyistä näytön kokoasetusta ja saattaa toimia odottamattomalla tavalla."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Näytä aina"</string>
<string name="smv_application" msgid="3307209192155442829">"Sovellus <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessi <xliff:g id="PROCESS">%2$s</xliff:g>) on rikkonut itse käyttöön ottamaansa StrictMode-käytäntöä."</string>
@@ -1130,7 +1137,7 @@
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Sallitaanko yhteys?"</string>
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Sovellus %1$s yrittää yhdistää Wi-Fi-verkkoon %2$s."</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Sovellus"</string>
- <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Suora Wi-Fi-yhteys"</string>
+ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käynnistä suora Wi-Fi-yhteys. Wi-Fi-asiakas/-hotspot poistetaan käytöstä."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Suoran Wi-Fi-yhteyden käynnistäminen epäonnistui."</string>
<string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct on käytössä"</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televisio"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Puhelin"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Telineen kaiuttimet"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Kuulokkeet"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Järjestelmä"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ääni"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Langaton näyttö"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 90b31c8..fbed666 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -253,7 +253,7 @@
<string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> applications sollicitent la pile"</string>
<string name="foreground_service_tap_for_details" msgid="372046743534354644">"Touchez pour afficher des détails sur l\'utilisation de la pile et des données"</string>
<string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
- <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
+ <string name="safeMode" msgid="2788228061547930246">"Mode sans échec"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
<string name="user_owner_label" msgid="1119010402169916617">"Passer au profil personnel"</string>
<string name="managed_profile_label" msgid="5289992269827577857">"Passer au profil professionnel"</string>
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Téléphone"</string>
<string name="map" msgid="6068210738233985748">"Cartes"</string>
<string name="browse" msgid="6993590095938149861">"Navigateur"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Espace de stockage bientôt saturé"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Il est possible que certaines fonctionnalités du système ne soient pas opérationnelles."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Espace de stockage insuffisant pour le système. Assurez-vous de disposer de 250 Mo d\'espace libre, puis redémarrez."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Annuler"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Annuler"</string>
+ <string name="close" msgid="2318214661230355730">"FERMER"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Chargement en cours..."</string>
<string name="capital_on" msgid="1544682755514494298">"OUI"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Redimensionner"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Toujours afficher"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Réactivez ce mode en accédant à Paramètres système > Applications > Téléchargements"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"L\'application ne répond pas"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> utilise peut-être trop de mémoire."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec le paramètre de taille d\'affichage actuel et peut se comporter de manière inattendue."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Toujours afficher"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) a enfreint ses propres règles du mode strict."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Télévision"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Téléphone"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Haut-parleurs de la station d\'accueil"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Oreillettes"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Système"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Affichage sans fil"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index e361500..fcdccad 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Téléphone"</string>
<string name="map" msgid="6068210738233985748">"Cartes"</string>
<string name="browse" msgid="6993590095938149861">"Navigateur"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Espace de stockage bientôt saturé"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Il est possible que certaines fonctionnalités du système ne soient pas opérationnelles."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Espace de stockage insuffisant pour le système. Assurez-vous de disposer de 250 Mo d\'espace libre, puis redémarrez."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Annuler"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Annuler"</string>
+ <string name="close" msgid="2318214661230355730">"FERMER"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Chargement…"</string>
<string name="capital_on" msgid="1544682755514494298">"OUI"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mise à l\'échelle"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Toujours afficher"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Réactivez ce mode en accédant à Paramètres système > Applications > Téléchargements"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"L\'application ne répond pas"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> utilise peut-être trop de mémoire."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec le paramètre de taille d\'affichage actuel et peut présenter un comportement inattendu."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Toujours afficher"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) a enfreint ses propres règles du mode strict."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Téléviseur"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Téléphone"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Haut-parleurs de la station d\'accueil"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Écouteurs"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Système"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Affichage sans fil"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index a24252c..0c0e12a 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Teléfono"</string>
<string name="map" msgid="6068210738233985748">"Mapas"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Estase esgotando o espazo de almacenamento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"É posible que algunhas funcións do sistema non funcionen"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Non hai almacenamento suficiente para o sistema. Asegúrate de ter un espazo libre de 250 MB e reinicia o dispositivo."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="yes" msgid="5362982303337969312">"Aceptar"</string>
<string name="no" msgid="5141531044935541497">"Cancelar"</string>
+ <string name="close" msgid="2318214661230355730">"PECHAR"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
<string name="loading" msgid="7933681260296021180">"Cargando..."</string>
<string name="capital_on" msgid="1544682755514494298">"SI"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Volve activar esta función en Configuración do sistema > Aplicacións > Descargadas."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"A aplicación non responde"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"É posible que <xliff:g id="APP_NAME">%1$s</xliff:g> estea utilizando demasiada memoria."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite a configuración do tamaño de pantalla actual e quizais presente un comportamento inesperado."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"A aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) infrinxiu a súa política StrictMode autoaplicada."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televisión"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Teléfono"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Conectar altofalantes á base"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Auriculares"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio por Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Visualización sen fíos"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 3249e14..d985e28 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -270,8 +270,8 @@
<string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS સંદેશા મોકલવાની અને જોવાની"</string>
<string name="permgrouprequest_sms" msgid="605618939583628306">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ને SMS સંદેશા મોકલવા અને જોવાની મંજૂરી આપો"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"સ્ટોરેજ"</string>
- <string name="permgroupdesc_storage" msgid="637758554581589203">"તમારા ઉપકરણ પર ફોટા, મીડિયા અને ફાઇલો ઍક્સેસ કરવાની"</string>
- <string name="permgrouprequest_storage" msgid="7429669910547860218">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ને તમારા ઉપકરણ પર ફોટા, મીડિયા, અને ફાઇલોને ઍક્સેસ કરવાની મંજૂરી આપો"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"તમારા ઉપકરણ પર ફોટો, મીડિયા અને ફાઇલો ઍક્સેસ કરવાની"</string>
+ <string name="permgrouprequest_storage" msgid="7429669910547860218">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ને તમારા ઉપકરણ પર ફોટો, મીડિયા, અને ફાઇલોને ઍક્સેસ કરવાની મંજૂરી આપો"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"માઇક્રોફોન"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"ઑડિઓ રેકોર્ડ કરવાની"</string>
<string name="permgrouprequest_microphone" msgid="8065941268709600606">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ને ઑડિઓ રોકૉર્ડ કરવાની મંજૂરી આપો"</string>
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ફોન"</string>
<string name="map" msgid="6068210738233985748">"નકશા"</string>
<string name="browse" msgid="6993590095938149861">"બ્રાઉઝર"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"સ્ટોરેજ સ્થાન સમાપ્ત થયું"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"કેટલાક સિસ્ટમ કાર્યો કામ કરી શકશે નહીં"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"સિસ્ટમ માટે પર્યાપ્ત સ્ટોરેજ નથી. ખાતરી કરો કે તમારી પાસે 250MB ખાલી સ્થાન છે અને ફરીથી પ્રારંભ કરો."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"રદ કરો"</string>
<string name="yes" msgid="5362982303337969312">"ઓકે"</string>
<string name="no" msgid="5141531044935541497">"રદ કરો"</string>
+ <string name="close" msgid="2318214661230355730">"બંધ કરો"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ધ્યાન આપો"</string>
<string name="loading" msgid="7933681260296021180">"લોડ કરી રહ્યું છે…"</string>
<string name="capital_on" msgid="1544682755514494298">"ચાલુ"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"સ્કેલ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"હંમેશા બતાવો"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"આને સિસ્ટમ સેટિંગ્સ > ઍપ્લિકેશનો > ડાઉનલોડ કરેલમાં ફરીથી સક્ષમ કરો."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"ઍપ પ્રતિસાદ આપી રહી નથી"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ખૂબ વધારે મેમરીનો ઉપયોગ કરતી હોઈ શકે."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> વર્તમાન પ્રદર્શન કદની સેટિંગનું સમર્થન કરતું નથી અને અનપેક્ષિત રીતે વર્તી શકે છે."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"હંમેશાં બતાવો"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> ઍપ્લિકેશન (<xliff:g id="PROCESS">%2$s</xliff:g> પ્રક્રિયા)એ તેની સ્વ-લાગુ કરેલ StrictMode નીતિનું ઉલ્લંઘન કર્યું છે."</string>
@@ -1183,7 +1190,7 @@
<string name="usb_charging_notification_title" msgid="6895185153353640787">"આ ઉપકરણને USB થી ચાર્જ કરે છે"</string>
<string name="usb_supplying_notification_title" msgid="5310642257296510271">"જોડાયેલ ઉપકરણ માટે USB પાવર પૂરો પાડે છે"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"ફાઇલ ટ્રાન્સફર માટે USB"</string>
- <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ફોટા ટ્રાન્સફર માટે USB"</string>
+ <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ફોટો ટ્રાન્સફર માટે USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI માટે USB"</string>
<string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB ઍક્સેસરીથી કનેક્ટ થયાં"</string>
<string name="usb_notification_message" msgid="3370903770828407960">"વધુ વિકલ્પો માટે ટૅપ કરો."</string>
@@ -1213,7 +1220,7 @@
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ને તૈયાર કરી રહ્યું છે"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ભૂલો માટે તપાસી રહ્યું છે"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"નવું <xliff:g id="NAME">%s</xliff:g> મળ્યું"</string>
- <string name="ext_media_ready_notification_message" msgid="4083398150380114462">"ફોટા અને મીડિયા ટ્રાન્સફર કરવા માટે"</string>
+ <string name="ext_media_ready_notification_message" msgid="4083398150380114462">"ફોટો અને મીડિયા ટ્રાન્સફર કરવા માટે"</string>
<string name="ext_media_unmountable_notification_title" msgid="8295123366236989588">"દૂષિત <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_unmountable_notification_message" msgid="2343202057122495773">"<xliff:g id="NAME">%s</xliff:g> દૂષિત છે. ઠીક કરવા માટે ટૅપ કરો."</string>
<string name="ext_media_unmountable_notification_message" product="tv" msgid="3941179940297874950">"<xliff:g id="NAME">%s</xliff:g> દૂષિત છે. સુધારવા માટે પસંદ કરો."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ફોન"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"સ્પીકર્સ ડૉક કરો"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"હેડફોન"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"સિસ્ટમ"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"બ્લૂટૂથ ઑડિઓ"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"વાયરલેસ ડિસ્પ્લે"</string>
@@ -1741,7 +1746,7 @@
<string name="app_category_game" msgid="5431836943981492993">"રમતો"</string>
<string name="app_category_audio" msgid="1659853108734301647">"સંગીત અને ઑડિઓ"</string>
<string name="app_category_video" msgid="2728726078629384196">"મૂવી અને વીડિઓ"</string>
- <string name="app_category_image" msgid="4867854544519846048">"ફોટા અને છબીઓ"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"ફોટો અને છબીઓ"</string>
<string name="app_category_social" msgid="5842783057834965912">"સામાજિક અને સંચાર"</string>
<string name="app_category_news" msgid="7496506240743986873">"સમાચાર અને સામાયિકો"</string>
<string name="app_category_maps" msgid="5878491404538024367">"નકશા અને નેવિગેશન"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 7c2c35c..e29deab 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"फ़ोन"</string>
<string name="map" msgid="6068210738233985748">"मानचित्र"</string>
<string name="browse" msgid="6993590095938149861">"ब्राउज़र"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"मेमोरी में जगह नहीं बची है"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"हो सकता है कुछ सिस्टम फ़ंक्शन कार्य न करें"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"सिस्टम के लिए ज़रूरी मेमोरी नहीं है. पक्का करें कि आपके पास 250एमबी की खाली जगह है और फिर से शुरू करें."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"रद्द करें"</string>
<string name="yes" msgid="5362982303337969312">"ठीक है"</string>
<string name="no" msgid="5141531044935541497">"रद्द करें"</string>
+ <string name="close" msgid="2318214661230355730">"बंद करें"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ध्यान दें"</string>
<string name="loading" msgid="7933681260296021180">"लोड हो रहे हैं..."</string>
<string name="capital_on" msgid="1544682755514494298">"ऑन"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"स्केल"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"हमेशा दिखाएं"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"इसे सिस्टम सेटिंग > ऐप > डाउनलोड किए गए में फिर से चालू करें."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"ऐप काम नहीं कर रहा है"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> शायद बहुत ज़्यादा मेमोरी इस्तेमाल कर रहा है."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> वर्तमान स्क्रीन के आकार की सेटिंग का समर्थन नहीं करता है और अनपेक्षित रूप से व्यवहार कर सकता है."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"हमेशा दिखाएं"</string>
<string name="smv_application" msgid="3307209192155442829">"ऐप्स <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने उसकी स्वयं लागू होने वाली StrictMode नीति का उल्लंघन किया है."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"टीवी"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"फ़ोन"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"डॉक स्पीकर"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"हेडफ़ोन"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"सिस्टम"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ब्लूटूथ ऑडियो"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"वायरलेस डिसप्ले"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 8f74abc..bcf789b 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1000,6 +1000,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Karte"</string>
<string name="browse" msgid="6993590095938149861">"Preglednik"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ponestaje prostora za pohranu"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda neće raditi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno pohrane za sustav. Oslobodite 250 MB prostora i pokrenite uređaj ponovo."</string>
@@ -1009,6 +1013,7 @@
<string name="cancel" msgid="6442560571259935130">"Odustani"</string>
<string name="yes" msgid="5362982303337969312">"U redu"</string>
<string name="no" msgid="5141531044935541497">"Odustani"</string>
+ <string name="close" msgid="2318214661230355730">"ZATVORI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Pažnja"</string>
<string name="loading" msgid="7933681260296021180">"Učitavanje…"</string>
<string name="capital_on" msgid="1544682755514494298">"Uklj."</string>
@@ -1065,6 +1070,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mjerilo"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Uvijek prikaži"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Omogućiti to ponovo u Postavkama sustava > Aplikacije > Preuzimanja."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacija ne reagira"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> možda upotrebljava previše memorije."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava trenutačnu postavku veličine zaslona i može se ponašati neočekivano."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Uvijek prikaži"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) prekršila je vlastito pravilo StrictMode."</string>
@@ -1444,11 +1451,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televizor"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Zvučnici postolja"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Slušalice"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sustav"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth zvuk"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Bežični prikaz"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 96d878c..93eb9ac 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Térkép"</string>
<string name="browse" msgid="6993590095938149861">"Böngésző"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Kevés a szabad terület"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Előfordulhat, hogy néhány rendszerfunkció nem működik."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nincs elegendő tárhely a rendszerhez. Győződjön meg arról, hogy rendelkezik 250 MB szabad területtel, majd kezdje elölről."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Mégse"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Mégse"</string>
+ <string name="close" msgid="2318214661230355730">"BEZÁRÁS"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Figyelem"</string>
<string name="loading" msgid="7933681260296021180">"Betöltés..."</string>
<string name="capital_on" msgid="1544682755514494298">"Be"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skála"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mindig megjelenik"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Újbóli engedélyezés itt: Rendszerbeállítások > Alkalmazások > Letöltve."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Az alkalmazás nem válaszol"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Lehetséges, hogy a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> túl sok memóriát használ."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás nem támogatja a képernyőméret jelenlegi beállításait, ezért nem várt módon viselkedhet."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mindig megjelenik"</string>
<string name="smv_application" msgid="3307209192155442829">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás (<xliff:g id="PROCESS">%2$s</xliff:g> folyamat) megsértette az általa kényszerített Szigorú üzemmód irányelvet."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dokkolóegység hangszórója"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Fejhallgató"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Rendszer"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth hang"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Vezeték nélküli kijelző"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index b664997..e5d92c6 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Հեռախոս"</string>
<string name="map" msgid="6068210738233985748">"Քարտեզներ"</string>
<string name="browse" msgid="6993590095938149861">"Դիտարկիչ"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Հիշողությունը սպառվում է"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Որոշ գործառույթներ կարող են չաշխատել"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Համակարգի համար բավարար հիշողություն չկա: Համոզվեք, որ ունեք 250ՄԲ ազատ տարածություն և վերագործարկեք:"</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Չեղարկել"</string>
<string name="yes" msgid="5362982303337969312">"Լավ"</string>
<string name="no" msgid="5141531044935541497">"Չեղարկել"</string>
+ <string name="close" msgid="2318214661230355730">"ՓԱԿԵԼ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Ուշադրություն"</string>
<string name="loading" msgid="7933681260296021180">"Բեռնում..."</string>
<string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Աստիճանակարգել"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Միշտ ցույց տալ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Կրկին ակտիվացնել սա Համակարգի կարգավորումներում &gt Ծրագրեր > Ներբեռնումներ:"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Հավելվածը չի արձագանքում"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Հնարավոր է, որ <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը չափազանց շատ հիշողություն է օգտագործում:"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը չի աջակցում Էկրանի չափի ընթացիկ կարգավորումները, ինչի պատճառով կարող են խնդիրներ առաջանալ:"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Միշտ ցուցադրել"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> ծրագիրը (գործընթաց <xliff:g id="PROCESS">%2$s</xliff:g>) խախտել է իր ինքնահարկադրված Խիստ ռեժիմ քաղաքականությունը:"</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Հեռուստացույց"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Հեռախոս"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Համակցված բարձրախոսներ"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Ականջակալներ"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Համակարգ"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ի աուդիո ֆայլ"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Անլար էկրան"</string>
@@ -1763,10 +1768,10 @@
<item quantity="one"><xliff:g id="COUNT">%1$s</xliff:g> ինքնալցման առաջարկ</item>
<item quantity="other"><xliff:g id="COUNT">%1$s</xliff:g> ինքնալցման առաջարկ</item>
</plurals>
- <string name="autofill_save_title" msgid="3345527308992082601">"Պահե՞լ <b><xliff:g id="LABEL">%1$s</xliff:g></b>-ում:"</string>
- <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Պահե՞լ <xliff:g id="TYPE">%1$s</xliff:g>-ը <b><xliff:g id="LABEL">%2$s</xliff:g></b>-ում:"</string>
- <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Պահե՞լ <xliff:g id="TYPE_0">%1$s</xliff:g>-ը և <xliff:g id="TYPE_1">%2$s</xliff:g>-ը <b><xliff:g id="LABEL">%3$s</xliff:g></b>-ում:"</string>
- <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Պահե՞լ <xliff:g id="TYPE_0">%1$s</xliff:g>-ը, <xliff:g id="TYPE_1">%2$s</xliff:g>-ը և <xliff:g id="TYPE_2">%3$s</xliff:g>-ը <b><xliff:g id="LABEL">%4$s</xliff:g></b>-ում:"</string>
+ <string name="autofill_save_title" msgid="3345527308992082601">"Պահե՞լ <b><xliff:g id="LABEL">%1$s</xliff:g></b> ծառայությունում"</string>
+ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Պահե՞լ <xliff:g id="TYPE">%1$s</xliff:g>ը <b><xliff:g id="LABEL">%2$s</xliff:g></b> ծառայությունում"</string>
+ <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Պահե՞լ <xliff:g id="TYPE_0">%1$s</xliff:g>ն ու <xliff:g id="TYPE_1">%2$s</xliff:g>ը <b><xliff:g id="LABEL">%3$s</xliff:g></b> ծառայությունում"</string>
+ <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Պահե՞լ <xliff:g id="TYPE_0">%1$s</xliff:g>ը, <xliff:g id="TYPE_1">%2$s</xliff:g>ն ու <xliff:g id="TYPE_2">%3$s</xliff:g>ը <b><xliff:g id="LABEL">%4$s</xliff:g></b> ծառայությունում"</string>
<string name="autofill_save_yes" msgid="6398026094049005921">"Պահել"</string>
<string name="autofill_save_no" msgid="2625132258725581787">"Ոչ"</string>
<string name="autofill_save_type_password" msgid="5288448918465971568">"գաղտնաբառ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 0f210e9..89e96f9 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telepon"</string>
<string name="map" msgid="6068210738233985748">"Peta"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ruang penyimpanan hampir habis"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Beberapa fungsi sistem mungkin tidak dapat bekerja"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Penyimpanan tidak cukup untuk sistem. Pastikan Anda memiliki 250 MB ruang kosong, lalu mulai ulang."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Batal"</string>
<string name="yes" msgid="5362982303337969312">"Oke"</string>
<string name="no" msgid="5141531044935541497">"Batal"</string>
+ <string name="close" msgid="2318214661230355730">"TUTUP"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Perhatian"</string>
<string name="loading" msgid="7933681260296021180">"Memuat..."</string>
<string name="capital_on" msgid="1544682755514494298">"AKTIF"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Selalu tampilkan"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktifkan kembali dialog ini di Setelan sistem > Apl > Terdownload."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikasi tidak merespons"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> mungkin menggunakan terlalu banyak memori."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung setelan Ukuran layar saat ini dan dapat menunjukkan perilaku yang tak diharapkan."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Selalu tampilkan"</string>
<string name="smv_application" msgid="3307209192155442829">"Apl <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) telah melanggar kebijakan StrictMode yang diberlakukannya sendiri."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Ponsel"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Pengeras suara dok"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Headphone"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Layar nirkabel"</string>
@@ -1440,7 +1445,7 @@
<string name="media_route_status_available" msgid="6983258067194649391">"Tersedia"</string>
<string name="media_route_status_not_available" msgid="6739899962681886401">"Tidak tersedia"</string>
<string name="media_route_status_in_use" msgid="4533786031090198063">"Sedang digunakan"</string>
- <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Layar Bawaan"</string>
+ <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Layar Built-In"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"Layar HDMI"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Hamparan #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
@@ -1610,7 +1615,7 @@
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Coba lagi nanti"</string>
<string name="immersive_cling_title" msgid="8394201622932303336">"Melihat layar penuh"</string>
- <string name="immersive_cling_description" msgid="3482371193207536040">"Untuk keluar, gesek ke bawah dari atas."</string>
+ <string name="immersive_cling_description" msgid="3482371193207536040">"Untuk keluar, geser layar ke bawah dari atas."</string>
<string name="immersive_cling_positive" msgid="5016839404568297683">"Mengerti"</string>
<string name="done_label" msgid="2093726099505892398">"Selesai"</string>
<string name="hour_picker_description" msgid="6698199186859736512">"Penggeser putar jam"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 3c256a9..2850fec 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Sími"</string>
<string name="map" msgid="6068210738233985748">"Kort"</string>
<string name="browse" msgid="6993590095938149861">"Vafri"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Geymslurýmið er senn á þrotum"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sumir kerfiseiginleikar kunna að vera óvirkir"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Ekki nægt geymslurými fyrir kerfið. Gakktu úr skugga um að 250 MB séu laus og endurræstu."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Hætta við"</string>
<string name="yes" msgid="5362982303337969312">"Í lagi"</string>
<string name="no" msgid="5141531044935541497">"Hætta við"</string>
+ <string name="close" msgid="2318214661230355730">"LOKA"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Athugaðu"</string>
<string name="loading" msgid="7933681260296021180">"Hleður…"</string>
<string name="capital_on" msgid="1544682755514494298">"KVEIKT"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Breyta stærð"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Sýna alltaf"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Þú getur kveikt aftur á þessu undir Kerfisstillingar > Forrit > Sótt."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Forritið svarar ekki"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> notar hugsanlega of mikið minni."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki núverandi skjástærðarstillingu og gæti því ekki virkað sem skyldi."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Sýna alltaf"</string>
<string name="smv_application" msgid="3307209192155442829">"Forritið <xliff:g id="APPLICATION">%1$s</xliff:g> (ferli <xliff:g id="PROCESS">%2$s</xliff:g>) hefur brotið gegn eigin StrictMode-stefnu."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Sjónvarp"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Sími"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dokkuhátalarar"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Heyrnartól"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Kerfi"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-hljóð"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Þráðlaus skjábirting"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 147c103..0274602 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefono"</string>
<string name="map" msgid="6068210738233985748">"Mappe"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spazio di archiviazione in esaurimento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Alcune funzioni di sistema potrebbero non funzionare"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Memoria insufficiente per il sistema. Assicurati di avere 250 MB di spazio libero e riavvia."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Annulla"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Annulla"</string>
+ <string name="close" msgid="2318214661230355730">"CHIUDI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attenzione"</string>
<string name="loading" msgid="7933681260296021180">"Caricamento..."</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostra sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Riattivala in Impostazioni di sistema > Applicazioni > Scaricate."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"L\'app non risponde"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Probabilmente <xliff:g id="APP_NAME">%1$s</xliff:g> utilizza troppa memoria."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le dimensioni di visualizzazione attualmente impostate e potrebbe comportarsi in modo imprevisto."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostra sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"L\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) ha violato la norma StrictMode autoimposta."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefono"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altoparlanti dock"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Cuffie audio"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Visualizzazione wireless"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 67acb4f..5fa6c52 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"טלפון"</string>
<string name="map" msgid="6068210738233985748">"מפות"</string>
<string name="browse" msgid="6993590095938149861">"דפדפן"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"שטח האחסון אוזל"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ייתכן שפונקציות מערכת מסוימות לא יפעלו"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"אין מספיק שטח אחסון עבור המערכת. ודא שיש לך שטח פנוי בגודל 250MB התחל שוב."</string>
@@ -1029,6 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"ביטול"</string>
<string name="yes" msgid="5362982303337969312">"אישור"</string>
<string name="no" msgid="5141531044935541497">"ביטול"</string>
+ <string name="close" msgid="2318214661230355730">"סגירה"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"זהירות"</string>
<string name="loading" msgid="7933681260296021180">"טוען..."</string>
<string name="capital_on" msgid="1544682755514494298">"מופעל"</string>
@@ -1085,6 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"שינוי קנה-מידה"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"הצג תמיד"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"אפשר תכונה זו מחדש ב\'הגדרות מערכת\' < Google Apps < \'הורדות\'."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"האפליקציה לא מגיבה"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"ייתכן שהאפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> משתמשת ביותר מדי שטח זיכרון."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> אינו תומך בהגדרת הגודל הנוכחית של התצוגה, והתנהגותו עשויה להיות בלתי צפויה."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"הצג תמיד"</string>
<string name="smv_application" msgid="3307209192155442829">"האפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> (תהליך <xliff:g id="PROCESS">%2$s</xliff:g>) הפר את מדיניות StrictMode באכיפה עצמית שלו."</string>
@@ -1467,11 +1474,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"טלוויזיה"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"טלפון"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"רמקולים של מעגן"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"אוזניות"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"מערכת"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"אודיו Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"צג אלחוטי"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index de8c758..78e59a3 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"電話"</string>
<string name="map" msgid="6068210738233985748">"マップ"</string>
<string name="browse" msgid="6993590095938149861">"ブラウザ"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"空き容量わずか"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"一部のシステム機能が動作しない可能性があります"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"システムに十分な容量がありません。250MBの空き容量を確保して再起動してください。"</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"キャンセル"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"キャンセル"</string>
+ <string name="close" msgid="2318214661230355730">"閉じる"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"注意"</string>
<string name="loading" msgid="7933681260296021180">"読み込んでいます..."</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"スケール"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"常に表示"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"[システム設定]>[アプリ]>[ダウンロード済み]で再度有効にします。"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"このアプリは応答していません"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」のメモリの使用量は多すぎる可能性があります。"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」は現在の [表示サイズ] 設定に対応していないため、予期しない動作が発生するおそれがあります。"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"常に表示"</string>
<string name="smv_application" msgid="3307209192155442829">"アプリ「<xliff:g id="APPLICATION">%1$s</xliff:g>」(プロセス「<xliff:g id="PROCESS">%2$s</xliff:g>」)でStrictModeポリシー違反がありました。"</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"テレビ"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"モバイル端末"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ホルダーのスピーカー"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"ヘッドホン"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"システム"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth音声"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"ワイヤレスディスプレイ"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 08bd6a4..d9947b0 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ტელეფონი"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"ბრაუზერი"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"თავისუფალი ადგილი იწურება"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"სისტემის ზოგიერთმა ფუნქციამ შესაძლოა არ იმუშავოს"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"სისტემისათვის საკმარისი საცავი არ არის. დარწმუნდით, რომ იქონიოთ სულ მცირე 250 მბაიტი თავისუფალი სივრცე და დაიწყეთ ხელახლა."</string>
@@ -989,6 +993,8 @@
<string name="cancel" msgid="6442560571259935130">"გაუქმება"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"გაუქმება"</string>
+ <!-- no translation found for close (2318214661230355730) -->
+ <skip />
<string name="dialog_alert_title" msgid="2049658708609043103">"ყურადღება"</string>
<string name="loading" msgid="7933681260296021180">"ჩატვირთვა…"</string>
<string name="capital_on" msgid="1544682755514494298">"ჩართ."</string>
@@ -1045,6 +1051,10 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"მასშტაბი"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ყოველთვის ჩვენება"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ხელახალი გააქტიურება განყოფილებაში: სისტემის პარამეტრები > აპები > ჩამოტვირთულები."</string>
+ <!-- no translation found for top_app_killed_title (6814231368167994497) -->
+ <skip />
+ <!-- no translation found for top_app_killed_message (3487519022191609844) -->
+ <skip />
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის მიერ ეკრანის ამჟამინდელი პარამეტრები მხარდაუჭერელია და შეიძლება არასათანადოდ იმუშაოს."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ყოველთვის ჩვენება"</string>
<string name="smv_application" msgid="3307209192155442829">"აპმა <xliff:g id="APPLICATION">%1$s</xliff:g> (პროცესი <xliff:g id="PROCESS">%2$s</xliff:g>) დაარღვია საკუთარი StrictMode დებულება."</string>
@@ -1421,11 +1431,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ტელევიზია"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ტელეფონი"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"სპიკერების მიმაგრება"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"ყურსასმენები"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"სისტემა"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth აუდიო"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"უსადენო ეკრანი"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index cd08c7a..95e1459 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Телефон"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"Браузер"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Жадта орын азайып барады"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Жүйенің кейбір функциялары жұмыс істемеуі мүмкін"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Жүйе үшін жад жеткіліксіз. 250 МБ бос орын бар екенін тексеріп, қайта іске қосыңыз."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Бас тарту"</string>
<string name="yes" msgid="5362982303337969312">"Жарайды"</string>
<string name="no" msgid="5141531044935541497">"Бас тарту"</string>
+ <string name="close" msgid="2318214661230355730">"ЖАБУ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Назар аударыңыз"</string>
<string name="loading" msgid="7933681260296021180">"Жүктелуде…"</string>
<string name="capital_on" msgid="1544682755514494298">"Қосулы"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Меже"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Үнемі көрсету"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Мұны «Жүйелік параметрлер» > «Қолданбалар» > «Жүктелгендер» тармағында қосыңыз."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Қолданба жауап бермеуде"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> жадтан тым көп орын пайдалануда."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасында \"Дисплей өлшемі\" параметрінің таңдалған мәніне қолдау көрсетілмейді, сондықтан дұрыс жұмыс істемеуі мүмкін."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Үнемі көрсету"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасы (<xliff:g id="PROCESS">%2$s</xliff:g> процесі) өзі қолданған StrictMode саясатын бұзды."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ТД"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Телефон"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Үндеткіштерді қондыру"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Құлақаспаптар"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Жүйе"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth aудио"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Сымсыз дисплей"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index b8f9820..ae11db4 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ទូរសព្ទ"</string>
<string name="map" msgid="6068210738233985748">"ផែនទី"</string>
<string name="browse" msgid="6993590095938149861">"កម្មវិធីរុករកតាមអ៊ីនធឺណិត"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"អស់ទំហំផ្ទុក"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"មុខងារប្រព័ន្ធមួយចំនួនអាចមិនដំណើរការ"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"មិនមានទំហំផ្ទុកគ្រប់គ្រាន់សម្រាប់ប្រព័ន្ធ។ សូមប្រាកដថាអ្នកមានទំហំទំនេរ 250MB ហើយចាប់ផ្ដើមឡើងវិញ។"</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"បោះបង់"</string>
<string name="yes" msgid="5362982303337969312">"យល់ព្រម"</string>
<string name="no" msgid="5141531044935541497">"បោះបង់"</string>
+ <string name="close" msgid="2318214661230355730">"បិទ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ប្រយ័ត្ន"</string>
<string name="loading" msgid="7933681260296021180">"កំពុងផ្ទុក..."</string>
<string name="capital_on" msgid="1544682755514494298">"បើក"</string>
@@ -1047,6 +1052,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"មាត្រដ្ឋាន"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"បង្ហាញជានិច្ច"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"បើកវាឡើងវិញក្នុងការកំណត់ប្រព័ន្ធ > កម្មវិធី > ទាញយក។"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"កម្មវិធីមិនមានការឆ្លើយតបទេ"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> អាចកំពុងប្រើអង្គចងចាំច្រើនពេក។"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនគាំទ្រការកំណត់ទំហំនៃការបង្ហាញបច្ចុប្បន្ន និងអាចមានសកម្មភាពខុសពីការរំពឹងទុក។"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"បង្ហាញជានិច្ច"</string>
<string name="smv_application" msgid="3307209192155442829">"កម្មវិធី <xliff:g id="APPLICATION">%1$s</xliff:g> (ដំណើរការ <xliff:g id="PROCESS">%2$s</xliff:g>) បានបំពានគោលនយោបាយរបៀបតឹងរ៉ឹងអនុវត្តដោយខ្លួនឯង។"</string>
@@ -1423,11 +1430,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ទូរទស្សន៍"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ទូរសព្ទ"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ភ្ជាប់អូប៉ាល័រ"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"កាស"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"ប្រព័ន្ធ"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"សំឡេងប៊្លូធូស"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"បង្ហាញបណ្ដាញឥតខ្សែ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index ea233f6..125ccbb 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ಫೋನ್"</string>
<string name="map" msgid="6068210738233985748">"ನಕ್ಷೆಗಳು"</string>
<string name="browse" msgid="6993590095938149861">"ಬ್ರೌಸರ್"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"ಸಂಗ್ರಹಣೆ ಸ್ಥಳವು ತುಂಬಿದೆ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ಕೆಲವು ಸಿಸ್ಟಂ ಕಾರ್ಯವಿಧಾನಗಳು ಕಾರ್ಯನಿರ್ವಹಿಸದೇ ಇರಬಹುದು"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ಸಿಸ್ಟಂನಲ್ಲಿ ಸಾಕಷ್ಟು ಸಂಗ್ರಹಣೆಯಿಲ್ಲ. ನೀವು 250MB ನಷ್ಟು ಖಾಲಿ ಸ್ಥಳವನ್ನು ಹೊಂದಿರುವಿರಾ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ ಹಾಗೂ ಮರುಪ್ರಾರಂಭಿಸಿ."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"ರದ್ದುಮಾಡಿ"</string>
<string name="yes" msgid="5362982303337969312">"ಸರಿ"</string>
<string name="no" msgid="5141531044935541497">"ರದ್ದುಮಾಡಿ"</string>
+ <string name="close" msgid="2318214661230355730">"ಮುಚ್ಚಿ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ಗಮನಿಸಿ"</string>
<string name="loading" msgid="7933681260296021180">"ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
<string name="capital_on" msgid="1544682755514494298">"ಆನ್ ಮಾಡಿ"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"ಮಾಪಕ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ಯಾವಾಗಲೂ ತೋರಿಸಿ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ಸಿಸ್ಟಂ ಸೆಟ್ಟಿಂಗ್ಗಳು > ಅಪ್ಲಿಕೇಶನ್ಗಳು > ಡೌನ್ಲೋಡ್ ಆಗಿರುವುದರಲ್ಲಿ ಇದನ್ನು ಮರು ಸಕ್ರಿಯಗೊಳಿಸಿ."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"ಅಪ್ಲಿಕೇಶನ್ ಪ್ರತಿಕ್ರಿಯಿಸುತ್ತಿಲ್ಲ"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಹೆಚ್ಚು ಮೆಮೊರಿಯನ್ನು ಬಳಸಿಕೊಳ್ಳುತ್ತಿರಬಹುದು."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಪ್ರಸ್ತುತ ಪ್ರದರ್ಶನ ಗಾತ್ರದ ಸೆಟ್ಟಿಂಗ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ ಮತ್ತು ಅನಿರೀಕ್ಷಿತವಾಗಿ ವರ್ತಿಸಬಹುದು."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ಯಾವಾಗಲೂ ತೋರಿಸು"</string>
<string name="smv_application" msgid="3307209192155442829">"ಅಪ್ಲಿಕೇಶನ್ <xliff:g id="APPLICATION">%1$s</xliff:g> (ಪ್ರಕ್ರಿಯೆಯು <xliff:g id="PROCESS">%2$s</xliff:g>) ತನ್ನ ಸ್ವಯಂ-ಜಾರಿ ಕಠಿಣ ಮೋಡ್ ನೀತಿಯನ್ನು ಉಲ್ಲಂಘನೆ ಮಾಡಿದೆ."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ಟಿವಿ"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ಫೋನ್"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ಡಾಕ್ ಸ್ಪೀಕರ್ಗಳು"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"ಹೆಡ್ಫೋನ್ಗಳು"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"ಸಿಸ್ಟಂ"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೊ"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"ವಯರ್ಲೆಸ್ ಪ್ರದರ್ಶನ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 411f127..c253742 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -192,7 +192,7 @@
<string name="reboot_to_update_prepare" msgid="6305853831955310890">"업데이트 준비 중…"</string>
<string name="reboot_to_update_package" msgid="3871302324500927291">"업데이트 패키지 처리 중…"</string>
<string name="reboot_to_update_reboot" msgid="6428441000951565185">"다시 시작하는 중..."</string>
- <string name="reboot_to_reset_title" msgid="4142355915340627490">"공장 초기화"</string>
+ <string name="reboot_to_reset_title" msgid="4142355915340627490">"초기화"</string>
<string name="reboot_to_reset_message" msgid="2432077491101416345">"다시 시작하는 중..."</string>
<string name="shutdown_progress" msgid="2281079257329981203">"종료 중..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"태블릿이 종료됩니다."</string>
@@ -358,11 +358,11 @@
<string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"앱이 브로드캐스트가 끝난 후에 남은 브로드캐스트를 보낼 수 있도록 허용합니다. 앱을 지나치게 사용하면 태블릿에서 메모리를 너무 많이 사용하도록 하여 속도를 저하시키거나 불안정하게 만들 수 있습니다."</string>
<string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"앱이 브로드캐스트가 끝난 후에도 흥미로운 브로드캐스트를 보낼 수 있도록 허용합니다. 이 기능을 과도하게 사용하면 메모리 사용량이 많아져 TV 속도가 저하되거나 성능이 불안정해질 수 있습니다."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"앱이 브로드캐스트가 끝난 후에 남은 브로드캐스트를 보낼 수 있도록 허용합니다. 앱을 지나치게 사용하면 휴대전화에서 메모리를 너무 많이 사용하도록 하여 속도를 저하시키거나 불안정하게 만들 수 있습니다."</string>
- <string name="permlab_readContacts" msgid="8348481131899886131">"주소록 읽기"</string>
+ <string name="permlab_readContacts" msgid="8348481131899886131">"연락처 읽기"</string>
<string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"특정인과 전화, 이메일 또는 기타 수단으로 연락한 빈도를 포함하여 사용자 태블릿에 저장된 연락처에 대한 데이터를 앱이 읽도록 허용합니다. 이 권한을 사용하면 앱이 연락처 데이터를 저장할 수 있으며, 악성 앱이 사용자 모르게 연락처 데이터를 공유할 수도 있습니다."</string>
<string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"앱이 특정 연락처와 통화를 하거나 이메일을 주고받거나 다른 방법으로 연락한 횟수를 포함하여 TV에 저장된 연락처 관련 데이터를 읽을 수 있도록 허용합니다. 이 경우 앱이 연락처 데이터를 저장할 수 있으며 악성 앱이 사용자 몰래 연락처 데이터에 공유할 수도 있습니다."</string>
<string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"특정인과 전화, 이메일 또는 기타 수단으로 연락한 빈도를 포함하여 사용자 휴대전화에 저장된 연락처에 대한 데이터를 앱이 읽도록 허용합니다. 이 권한을 사용하면 앱이 연락처 데이터를 저장할 수 있으며, 악성 앱이 사용자 모르게 연락처 데이터를 공유할 수도 있습니다."</string>
- <string name="permlab_writeContacts" msgid="5107492086416793544">"주소록 수정"</string>
+ <string name="permlab_writeContacts" msgid="5107492086416793544">"연락처 수정"</string>
<string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"특정인과 전화, 이메일 또는 기타 수단으로 연락한 빈도를 포함하여 사용자 태블릿에 저장된 연락처에 대한 데이터를 앱이 수정할 수 있도록 허용합니다. 이 권한을 사용하면 앱이 연락처 데이터를 삭제할 수 있습니다."</string>
<string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"앱이 특정 연락처와 통화를 하거나 이메일을 주고받거나 다른 수단으로 연락한 횟수를 포함하여 TV에 저장된 연락처 관련 데이터를 수정할 수 있도록 허용합니다. 이 경우 앱이 연락처 데이터를 삭제할 수 있습니다."</string>
<string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"특정인과 전화, 이메일 또는 기타 수단으로 연락한 빈도를 포함하여 사용자 휴대전화에 저장된 연락처에 대한 데이터를 앱이 수정할 수 있도록 허용합니다. 이 권한을 사용하면 앱이 연락처 데이터를 삭제할 수 있습니다."</string>
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"전화"</string>
<string name="map" msgid="6068210738233985748">"지도"</string>
<string name="browse" msgid="6993590095938149861">"브라우저"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"저장 공간이 부족함"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"일부 시스템 기능이 작동하지 않을 수 있습니다."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"시스템의 저장 공간이 부족합니다. 250MB의 여유 공간이 확보한 후 다시 시작하세요."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"취소"</string>
<string name="yes" msgid="5362982303337969312">"확인"</string>
<string name="no" msgid="5141531044935541497">"취소"</string>
+ <string name="close" msgid="2318214661230355730">"닫기"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"주의"</string>
<string name="loading" msgid="7933681260296021180">"로드 중.."</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"배율"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"항상 표시"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"시스템 설정 > 앱 > 다운로드로 이동하여 이 모드를 다시 사용하도록 설정합니다."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"앱이 응답하지 않음"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 메모리를 과도하게 사용하는 것으로 보입니다."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 현재 디스플레이 크기 설정을 지원하지 않으며 예기치 않게 동작할 수 있습니다."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"항상 표시"</string>
<string name="smv_application" msgid="3307209192155442829">"앱 <xliff:g id="APPLICATION">%1$s</xliff:g>(프로세스 <xliff:g id="PROCESS">%2$s</xliff:g>)이(가) 자체 시행 StrictMode 정책을 위반했습니다."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"휴대전화"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"도크 스피커"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"헤드폰"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"시스템"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"블루투스 오디오"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"무선 디스플레이"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index ce9bab3..77f3b0c 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Телефон"</string>
<string name="map" msgid="6068210738233985748">"Карталар"</string>
<string name="browse" msgid="6993590095938149861">"Серепчи"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Сактагычта орун калбай баратат"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Системанын кээ бир функциялары иштебеши мүмкүн"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Тутумда сактагыч жетишсиз. 250МБ бош орун бар экенин текшерип туруп, өчүрүп күйгүзүңүз."</string>
@@ -989,6 +993,8 @@
<string name="cancel" msgid="6442560571259935130">"Жокко чыгаруу"</string>
<string name="yes" msgid="5362982303337969312">"Жарайт"</string>
<string name="no" msgid="5141531044935541497">"Жокко чыгаруу"</string>
+ <!-- no translation found for close (2318214661230355730) -->
+ <skip />
<string name="dialog_alert_title" msgid="2049658708609043103">"Көңүл буруңуз"</string>
<string name="loading" msgid="7933681260296021180">"Жүктөлүүдө…"</string>
<string name="capital_on" msgid="1544682755514494298">"ЖАНДЫРЫЛГАН"</string>
@@ -1045,6 +1051,10 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Шкала"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Ар дайым көрсөтүлсүн"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Муну тутум жөндөөлөрүнөн кайра иштетүү > Колдонмолор > Жүктөлүп алынган."</string>
+ <!-- no translation found for top_app_killed_title (6814231368167994497) -->
+ <skip />
+ <!-- no translation found for top_app_killed_message (3487519022191609844) -->
+ <skip />
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу көрүнүштүн тандалган өлчөмүн экранда көрсөтө албайт жана туура эмес иштеши мүмкүн."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Ар дайым көрсөтүлсүн"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосу (<xliff:g id="PROCESS">%2$s</xliff:g> процесси) өз алдынча иштеткен StrictMode саясатын бузду."</string>
@@ -1422,11 +1432,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Сыналгы"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Телефон"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Аудио док бекет"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Кулакчын"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Тутум"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Зымсыз дисплей"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 2ebf450..d53c702 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ໂທລະສັບ"</string>
<string name="map" msgid="6068210738233985748">"ແຜນທີ່"</string>
<string name="browse" msgid="6993590095938149861">"ໂປຣແກຣມທ່ອງເວັບ"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"ພື້ນທີ່ຈັດເກັບຂໍ້ມູນກຳລັງຈະເຕັມ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ການເຮັດວຽກບາງຢ່າງຂອງລະບົບບາງອາດຈະໃຊ້ບໍ່ໄດ້"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ບໍ່ມີບ່ອນເກັບຂໍ້ມູນພຽງພໍສຳລັບລະບົບ. ກວດສອບໃຫ້ແນ່ໃຈວ່າທ່ານມີພື້ນທີ່ຫວ່າງຢ່າງໜ້ອຍ 250MB ແລ້ວລອງໃໝ່."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"ຍົກເລີກ"</string>
<string name="yes" msgid="5362982303337969312">"ຕົກລົງ"</string>
<string name="no" msgid="5141531044935541497">"ຍົກເລີກ"</string>
+ <string name="close" msgid="2318214661230355730">"ປິດ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ກະລຸນາຮັບຊາບ"</string>
<string name="loading" msgid="7933681260296021180">"ກຳລັງໂຫລດ..."</string>
<string name="capital_on" msgid="1544682755514494298">"ເປີດ"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"ຂະໜາດ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ສະແດງຕະຫຼອດເວລາ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ເປີດການເຮັດວຽກນີ້ຄືນໄດ້ໃນ ການຕັ້ງຄ່າລະບົບ > ແອັບຯ > ດາວໂຫລດແລ້ວ"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"ແອັບບໍ່ຕອບສະໜອງ"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ອາດກຳລັງໃຊ້ໜ່ວຍຄວາມຈຳຫຼາຍເກີນໄປ"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ຮອງຮັບການຕັ້ງຄ່າຂະໜາດສະແດງຜົນປັດຈຸບັນ ແລະ ອາດມີຄວາມຜິດພາດໄດ້."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ສະແດງທຸກເທື່ອ"</string>
<string name="smv_application" msgid="3307209192155442829">"ແອັບຯ <xliff:g id="APPLICATION">%1$s</xliff:g> (ໂປຣເຊສ <xliff:g id="PROCESS">%2$s</xliff:g>) ໄດ້ລະເມີດນະໂຍບາຍ StrictMode ທີ່ບັງຄັບໃຊ້ດ້ວຍໂຕເອງ."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ໂທລະພາບ"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ໂທລະສັບ"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ບ່ອນຕັ້ງລຳໂພງ"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"ຫູຟັງ"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"ລະບົບ"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ສຽງ Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"ການສະແດງຜົນໄຮ້ສາຍ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index e5a7209..a3deaa7 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Telefonas"</string>
<string name="map" msgid="6068210738233985748">"Žemėlapiai"</string>
<string name="browse" msgid="6993590095938149861">"Naršyklė"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Mažėja laisvos saugyklos vietos"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Kai kurios sistemos funkcijos gali neveikti"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistemos saugykloje nepakanka vietos. Įsitikinkite, kad yra 250 MB laisvos vietos, ir paleiskite iš naujo."</string>
@@ -1029,6 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Atšaukti"</string>
<string name="yes" msgid="5362982303337969312">"Gerai"</string>
<string name="no" msgid="5141531044935541497">"Atšaukti"</string>
+ <string name="close" msgid="2318214661230355730">"UŽDARYTI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Dėmesio"</string>
<string name="loading" msgid="7933681260296021180">"Įkeliama..."</string>
<string name="capital_on" msgid="1544682755514494298">"ĮJ."</string>
@@ -1085,6 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mastelis"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Visada rodyti"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Įgalinkite jį iš naujo nuėję į „Sistemos nustatymai“ > „Programos“ > „Atsisiųsta“."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Programa nereaguoja"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ gali naudoti per daug atminties."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Programoje „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaikomas dabartinis ekrano dydžio nustatymas ir ji gali netinkamai veikti."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Visada rodyti"</string>
<string name="smv_application" msgid="3307209192155442829">"Programa „<xliff:g id="APPLICATION">%1$s</xliff:g>“ (procesas „<xliff:g id="PROCESS">%2$s</xliff:g>“) pažeidė savo vykdomą „StrictMode“ politiką."</string>
@@ -1467,11 +1474,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefonas"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Doko garsiakalbiai"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Ausinės"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"„Bluetooth“ garsas"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Belaidis rodymas"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 61c0756..c323fcc 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1000,6 +1000,10 @@
<string name="dial" msgid="4204975095406423102">"Tālrunis"</string>
<string name="map" msgid="6068210738233985748">"Kartes"</string>
<string name="browse" msgid="6993590095938149861">"Pārlūkprogramma"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Paliek maz brīvas vietas"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Dažas sistēmas funkcijas var nedarboties."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistēmai pietrūkst vietas. Atbrīvojiet vismaz 250 MB vietas un restartējiet ierīci."</string>
@@ -1009,6 +1013,7 @@
<string name="cancel" msgid="6442560571259935130">"Atcelt"</string>
<string name="yes" msgid="5362982303337969312">"Labi"</string>
<string name="no" msgid="5141531044935541497">"Atcelt"</string>
+ <string name="close" msgid="2318214661230355730">"AIZVĒRT"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Uzmanību!"</string>
<string name="loading" msgid="7933681260296021180">"Notiek ielāde..."</string>
<string name="capital_on" msgid="1544682755514494298">"IESLĒGT"</string>
@@ -1065,6 +1070,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mērogs"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Rādīt vienmēr"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Atkārtoti iespējojiet šeit: Sistēmas iestatījumi > Lietotnes > Lejupielādētās."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Lietotne nereaģē"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Iespējams, lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> aizņem pārāk daudz vietas atmiņā."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstīts pašreizējais displeja lieluma iestatījums, tādēļ tā var tikt attēlota neparedzētā veidā."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Rādīt vienmēr"</string>
<string name="smv_application" msgid="3307209192155442829">"Lietotne <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) ir pārkāpusi savu pašieviesto StrictMode politiku."</string>
@@ -1444,11 +1451,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Tālrunis"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Doka skaļruņi"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Austiņas"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistēma"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Bezvadu attēlošana"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 6406ed1..c3de4a9 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Телефон"</string>
<string name="map" msgid="6068210738233985748">"„Карти“"</string>
<string name="browse" msgid="6993590095938149861">"Прелистувач"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Меморијата е речиси полна"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некои системски функции може да не работат"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема доволно меморија во системот. Проверете дали има слободен простор од 250 МБ и рестартирајте."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Откажи"</string>
<string name="yes" msgid="5362982303337969312">"Во ред"</string>
<string name="no" msgid="5141531044935541497">"Откажи"</string>
+ <string name="close" msgid="2318214661230355730">"ЗАТВОРИ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Внимание"</string>
<string name="loading" msgid="7933681260296021180">"Се вчитува..."</string>
<string name="capital_on" msgid="1544682755514494298">"ВКЛУЧЕНО"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Размер"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Покажи секогаш"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Повторно овозможете го ова во Системски поставки > Апликации > Преземено."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Апликацијата не реагира"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> може да користи премногу меморија."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не ја поддржува тековната поставка за големина на екранот и може да се однесува непредвидено."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Секогаш прикажувај"</string>
<string name="smv_application" msgid="3307209192155442829">"Апликацијата <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) ја прекрши политиката StrictMode што си ја наметна врз себеси."</string>
@@ -1423,11 +1430,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевизор"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Телефон"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Приклучи звучници"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Слушалки"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Аудио на Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Безжичен приказ"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 2f9583e..2623167 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ഫോണ്"</string>
<string name="map" msgid="6068210738233985748">"മാപ്സ്"</string>
<string name="browse" msgid="6993590095938149861">"ബ്രൗസർ"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"സംഭരണയിടം കഴിഞ്ഞു"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ചില സിസ്റ്റം പ്രവർത്തനങ്ങൾ പ്രവർത്തിക്കണമെന്നില്ല."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"സിസ്റ്റത്തിനായി മതിയായ സംഭരണമില്ല. 250MB സൗജന്യ സംഭരണമുണ്ടെന്ന് ഉറപ്പുവരുത്തി പുനരാരംഭിക്കുക."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"റദ്ദാക്കുക"</string>
<string name="yes" msgid="5362982303337969312">"ശരി"</string>
<string name="no" msgid="5141531044935541497">"റദ്ദാക്കുക"</string>
+ <string name="close" msgid="2318214661230355730">"അടയ്ക്കുക"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ശ്രദ്ധിക്കുക"</string>
<string name="loading" msgid="7933681260296021180">"ലോഡുചെയ്യുന്നു..."</string>
<string name="capital_on" msgid="1544682755514494298">"ഓൺ"</string>
@@ -1026,7 +1031,7 @@
<string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> നിലയ്ക്കുന്നത് തുടരുന്നു"</string>
<string name="aerr_restart" msgid="7581308074153624475">"ആപ്പ് വീണ്ടും തുറക്കുക"</string>
<string name="aerr_report" msgid="5371800241488400617">"ഫീഡ്ബാക്ക് അയയ്ക്കുക"</string>
- <string name="aerr_close" msgid="2991640326563991340">"അടയ്ക്കുക"</string>
+ <string name="aerr_close" msgid="2991640326563991340">"അവസാനിപ്പിക്കുക"</string>
<string name="aerr_mute" msgid="1974781923723235953">"ഉപകരണം പുനഃരാരംഭിക്കുന്നത് വരെ മ്യൂട്ടുചെയ്യുക"</string>
<string name="aerr_wait" msgid="3199956902437040261">"കാത്തിരിക്കുക"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"ആപ്പ് അടയ്ക്കുക"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"സ്കെയിൽ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"എപ്പോഴും പ്രദര്ശിപ്പിക്കുക"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"സിസ്റ്റം ക്രമീകരണങ്ങൾ > അപ്ലിക്കേഷനുകൾ > ഡൗൺലോഡുചെയ്തവ എന്നതിൽ ഇത് വീണ്ടും പ്രവർത്തനക്ഷമമാക്കുക."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"ആപ്പ് പ്രതികരിക്കുന്നില്ല"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> വളരെയധികം മെമ്മറി ഉപയോഗിക്കുന്നുണ്ടാകാം."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"നിലവിലെ ഡിസ്പ്ലേ വലുപ്പ ക്രമീകരണത്തെ <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്ക്കുന്നില്ല, അതിനാൽ പ്രതീക്ഷിക്കാത്ത തരത്തിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കാം."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"എല്ലായ്പ്പോഴും ദൃശ്യമാക്കുക"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> എന്ന അപ്ലിക്കേഷൻ (<xliff:g id="PROCESS">%2$s</xliff:g> പ്രോസസ്സ്) അതിന്റെ സ്വയം നിർബന്ധിത StrictMode നയം ലംഘിച്ചു."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ടിവി"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ഫോണ്"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ഡോക്ക് സ്പീക്കറുകൾ"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"ഹെഡ്ഫോണുകൾ"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"സിസ്റ്റം"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ബ്ലൂടൂത്ത് ഓഡിയോ"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"വയർലെസ് ഡിസ്പ്ലേ"</string>
@@ -1699,7 +1704,7 @@
<string name="floating_toolbar_open_overflow_description" msgid="4797287862999444631">"കൂടുതൽ ഓപ്ഷനുകള്"</string>
<string name="floating_toolbar_close_overflow_description" msgid="559796923090723804">"ഓവർഫ്ലോ അടയ്ക്കുക"</string>
<string name="maximize_button_text" msgid="7543285286182446254">"വലുതാക്കുക"</string>
- <string name="close_button_text" msgid="3937902162644062866">"അടയ്ക്കുക"</string>
+ <string name="close_button_text" msgid="3937902162644062866">"അവസാനിപ്പിക്കുക"</string>
<string name="notification_messaging_title_template" msgid="3452480118762691020">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
<plurals name="selected_count" formatted="false" msgid="7187339492915744615">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> തിരഞ്ഞെടുത്തു</item>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index eab1e7e..ce09140 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Утас"</string>
<string name="map" msgid="6068210738233985748">"Газрын зураг"</string>
<string name="browse" msgid="6993590095938149861">"Хөтөч"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Сангийн хэмжээ дутагдаж байна"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Зарим систем функц ажиллахгүй байна"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Системд хангалттай сан байхгүй байна. 250MБ чөлөөтэй зай байгаа эсэхийг шалгаад дахин эхлүүлнэ үү."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Цуцлах"</string>
<string name="yes" msgid="5362982303337969312">"ОК"</string>
<string name="no" msgid="5141531044935541497">"Цуцлах"</string>
+ <string name="close" msgid="2318214661230355730">"ХААХ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Анхаар"</string>
<string name="loading" msgid="7933681260296021180">"Ачааллаж байна..."</string>
<string name="capital_on" msgid="1544682755514494298">"Идэвхтэй"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Цар хэмжээ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Байнга харуулах"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Энийг Системийн тохиргоо > Апп > Татаж авсан дотроос дахин идэвхтэй болгох боломжтой."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Апп хариу өгөхгүй байна"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> хэт их санах ой ашиглаж байж болзошгүй."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь Дэлгэцийн хэмжээний одоогийн тохиргоог дэмждэггүй учир буруу ажиллаж болзошгүй."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Байнга харуулах"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> апп (<xliff:g id="PROCESS">%2$s</xliff:g> процесс) өөрийнхөө StrictMode бодлогыг зөрчив."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tелевиз"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Утас"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Чанга яригчийг суулгах"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Чихэвч"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Утасгүй дэлгэц"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index f95df78..2d0cad7 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -641,7 +641,7 @@
<string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
<string name="phoneTypeWorkMobile" msgid="1311426989184065709">"कार्य मोबाईल"</string>
<string name="phoneTypeWorkPager" msgid="649938731231157056">"कार्य पेजर"</string>
- <string name="phoneTypeAssistant" msgid="5596772636128562884">"सहाय्यक"</string>
+ <string name="phoneTypeAssistant" msgid="5596772636128562884">"साहाय्यक"</string>
<string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
<string name="eventTypeCustom" msgid="7837586198458073404">"सानुकूल"</string>
<string name="eventTypeBirthday" msgid="2813379844211390740">"वाढदिवस"</string>
@@ -674,7 +674,7 @@
<string name="orgTypeOther" msgid="3951781131570124082">"अन्य"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"सानुकूल"</string>
<string name="relationTypeCustom" msgid="3542403679827297300">"सानुकूल"</string>
- <string name="relationTypeAssistant" msgid="6274334825195379076">"सहाय्यक"</string>
+ <string name="relationTypeAssistant" msgid="6274334825195379076">"साहाय्यक"</string>
<string name="relationTypeBrother" msgid="8757913506784067713">"भाऊ"</string>
<string name="relationTypeChild" msgid="1890746277276881626">"मूल"</string>
<string name="relationTypeDomesticPartner" msgid="6904807112121122133">"घरातील जोडीदार"</string>
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"फोन"</string>
<string name="map" msgid="6068210738233985748">"नकाशे"</string>
<string name="browse" msgid="6993590095938149861">"ब्राउझर"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"संचयन स्थान संपत आहे"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"काही सिस्टम कार्ये कार्य करू शकत नाहीत"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"सिस्टीमसाठी पुरेसे संचयन नाही. आपल्याकडे 250MB मोकळे स्थान असल्याचे सुनिश्चित करा आणि रीस्टार्ट करा."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"रद्द करा"</string>
<string name="yes" msgid="5362982303337969312">"ठीक"</string>
<string name="no" msgid="5141531044935541497">"रद्द करा"</string>
+ <string name="close" msgid="2318214661230355730">"बंद करा"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"लक्ष द्या"</string>
<string name="loading" msgid="7933681260296021180">"लोड करीत आहे..."</string>
<string name="capital_on" msgid="1544682755514494298">"चालू"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"स्केल"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"नेहमी दर्शवा"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"सिस्टम सेटिंग्ज > Apps > डाउनलोड केलेले मध्ये हे पुन्हा-सक्षम करा."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"अॅप प्रतिसाद देत नाही"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> कदाचित बरीच मेमरी वापरत आहे."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> वर्तमान डिस्प्ले आकार सेटिंगला समर्थन देत नाही आणि अनपेक्षित वर्तन करू शकते."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"नेहमी दर्शवा"</string>
<string name="smv_application" msgid="3307209192155442829">"अॅप <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने तिच्या स्वयं-लागू केलेल्या StrictMode धोरणाचे उल्लंघन केले आहे."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"टीव्ही"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"फोन"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"स्पीकर डॉक करा"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"हेडफोन"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"सिस्टम"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ब्लूटूथ ऑडिओ"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"वायरलेस डिस्प्ले"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index e526246..536f2c2 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Peta"</string>
<string name="browse" msgid="6993590095938149861">"Penyemak imbas"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ruang storan semakin berkurangan"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Beberapa fungsi sistem mungkin tidak berfungsi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Tidak cukup storan untuk sistem. Pastikan anda mempunyai 250MB ruang kosong dan mulakan semula."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Batal"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Batal"</string>
+ <string name="close" msgid="2318214661230355730">"TUTUP"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Perhatian"</string>
<string name="loading" msgid="7933681260296021180">"Memuatkan…"</string>
<string name="capital_on" msgid="1544682755514494298">"HIDUP"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Sentiasa tunjukkan"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Dayakan semula kod kompak ini tetapan Sistem > Apl > Dimuat turun."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Apl tidak bertindak balas"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> mungkin menggunakan terlalu banyak memori."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong tetapan saiz Paparan semasa dan mungkin menunjukkan gelagat yang tidak dijangka."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Sentiasa tunjukkan"</string>
<string name="smv_application" msgid="3307209192155442829">"Apl <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) telah melanggar dasar Mod Tegasnya sendiri."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Pembesar suara dok"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Fon kepala"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Paparan wayarles"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index c8c95f0..c0539a5 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ဖုန်း"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"ဘရောင်ဇာ"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"သိမ်းဆည်သော နေရာ နည်းနေပါသည်"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"တချို့ စနစ်လုပ်ငန်းများ အလုပ် မလုပ်ခြင်း ဖြစ်နိုင်ပါသည်"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"စနစ်အတွက် သိုလှောင်ခန်း မလုံလောက်ပါ။ သင့်ဆီမှာ နေရာလွတ် ၂၅၀ MB ရှိတာ စစ်ကြည့်ပြီး စတင်ပါ။"</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"မလုပ်တော့"</string>
<string name="yes" msgid="5362982303337969312">"အိုကေ"</string>
<string name="no" msgid="5141531044935541497">"မလုပ်တော့"</string>
+ <string name="close" msgid="2318214661230355730">"ပိတ်ရန်"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"သတိပြုရန်"</string>
<string name="loading" msgid="7933681260296021180">"တင်နေ…"</string>
<string name="capital_on" msgid="1544682755514494298">"ဖွင့်ရန်"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"စကေး"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"အမြဲပြသရန်"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ဒါကို စနစ် ဆက်တင်များထဲ ပြန်ဖွင့်ပေးရန် > Apps > ဒေါင်းလုဒ် လုပ်ပြီး။"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"အက်ပ်က တုံ့ပြန်မှုမရှိပါ"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> က နေရာအလွန်အကျွံ ယူထားပုံရပါသည်။"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် လက်ရှိ မျက်နှာပြင်အရွယ်အစားကို ပံ့ပိုးထားခြင်း မရှိပါ။ မမျှော်လင့်နိုင်သည့် ချွတ်ယွင်းချက်များ ဖြစ်ပေါ်နိုင်ပါသည်။"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"အမြဲပြပါ"</string>
<string name="smv_application" msgid="3307209192155442829">"app <xliff:g id="APPLICATION">%1$s</xliff:g> (လုပ်ငန်းစဉ် <xliff:g id="PROCESS">%2$s</xliff:g>) က ကိုယ်တိုင် ပြဌာန်းခဲ့သည့် StrictMode မူဝါဒကို ချိုးဖောက်ခဲ့သည်။"</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"တီဗွီ"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ဖုန်း"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"အထိုင်ရှိသော စပီကာများ"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"နားကြပ်"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"စနစ်"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ဘလူးတုသ် အသံ"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"ကြိုးမဲ့ပြသခြင်း"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index b853894..4eb0f1d 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Kart"</string>
<string name="browse" msgid="6993590095938149861">"Nettleser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Lite ledig lagringsplass"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Enkelte systemfunksjoner fungerer muligens ikke slik de skal"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Det er ikke nok lagringsplass for systemet. Kontrollér at du har 250 MB ledig plass, og start på nytt."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Avbryt"</string>
+ <string name="close" msgid="2318214661230355730">"LUKK"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Merk"</string>
<string name="loading" msgid="7933681260296021180">"Laster inn …"</string>
<string name="capital_on" msgid="1544682755514494298">"På"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vis alltid"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reaktiver dette i systeminnstillingene > Apper > Nedlastet."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Appen svarer ikke"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruker muligens for mye minne."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke den nåværende innstillingen for skjermstørrelse og fungerer kanskje ikke som den skal."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vis alltid"</string>
<string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessen <xliff:g id="PROCESS">%2$s</xliff:g>) har brutt de selvpålagte StrictMode-retningslinjene."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Google TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dokkhøyttalere"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Hodetelefoner"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Trådløs skjerm"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 69eab15..16743d5 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"फोन गर्नुहोस्"</string>
<string name="map" msgid="6068210738233985748">"नक्सा"</string>
<string name="browse" msgid="6993590095938149861">"ब्राउजर"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"भण्डारण ठाउँ सकिँदै छ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"सायद केही प्रणाली कार्यक्रमहरूले काम गर्दैनन्"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"प्रणालीको लागि पर्याप्त भण्डारण छैन। तपाईँसँग २५० मेगा बाइट ठाउँ खाली भएको निश्चित गर्नुहोस् र फेरि सुरु गर्नुहोस्।"</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"रद्द गर्नुहोस्"</string>
<string name="yes" msgid="5362982303337969312">"ठीक छ"</string>
<string name="no" msgid="5141531044935541497">"रद्द गर्नुहोस्"</string>
+ <string name="close" msgid="2318214661230355730">"बन्द गर्नुहोस्"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"सावधानी"</string>
<string name="loading" msgid="7933681260296021180">"लोड हुँदै..."</string>
<string name="capital_on" msgid="1544682755514494298">"चालु"</string>
@@ -1051,6 +1056,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"स्केल"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"सधैँ देखाउनुहोस्"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"प्रणाली सेटिङहरूमा यसलाई पुनःसक्षम गराउनुहोस् > अनुप्रयोगहरू > डाउनलोड गरेको।"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"अनुप्रयोग चलिरहेको छैन"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले अत्यधिक मेमोरी प्रयोग गरिरहेको हुनसक्छ।"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले हालको प्रदर्शनको आकार सम्बन्धी सेटिङलाई समर्थन गर्दैन र अप्रत्याशित तरिकाले व्यवहार गर्न सक्छ।"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"सधैँ देखाउनुहोस्"</string>
<string name="smv_application" msgid="3307209192155442829">"अनुप्रयोग <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ले यसको स्वयं-लागु गरिएको स्ट्रिटमोड नीति उलङ्घन गरेको छ।"</string>
@@ -1427,11 +1434,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"फोन"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"डक स्पिकरहरू"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"हेडफोनहरू"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"प्रणाली"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ब्लुटुथ अडियो"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"ताररहित प्रदर्शन"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index ed7a1dd..e914caf 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefoon"</string>
<string name="map" msgid="6068210738233985748">"Kaarten"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Opslagruimte is bijna vol"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bepaalde systeemfuncties werken mogelijk niet"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Onvoldoende opslagruimte voor het systeem. Zorg ervoor dat je 250 MB vrije ruimte hebt en start opnieuw."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Annuleren"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Annuleren"</string>
+ <string name="close" msgid="2318214661230355730">"SLUITEN"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Let op"</string>
<string name="loading" msgid="7933681260296021180">"Laden..."</string>
<string name="capital_on" msgid="1544682755514494298">"AAN"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Schaal"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Altijd weergeven"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"U kunt dit opnieuw inschakelen via Systeeminstellingen > Apps > Gedownload."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"App reageert niet"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> gebruikt mogelijk te veel geheugen"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> biedt geen ondersteuning voor de huidige instelling voor weergavegrootte en kan onverwacht gedrag vertonen."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Altijd weergeven"</string>
<string name="smv_application" msgid="3307209192155442829">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tv"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefoon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dockluidsprekers"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Hoofdtelefoon"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Systeem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Draadloze weergave"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 11957f1..7917b23 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -45,10 +45,10 @@
<string name="invalidPuk" msgid="8761456210898036513">"ਇੱਕ PUK ਕੋਡ ਟਾਈਪ ਕਰੋ ਜੋ 8 ਜਾਂ ਵੱਧ ਸੰਖਿਆਵਾਂ ਦਾ ਹੋਵੇ।"</string>
<string name="needPuk" msgid="919668385956251611">"ਤੁਹਾਡਾ ਸਿਮ ਕਾਰਡ PUK-ਲੌਕਡ ਹੈ। ਇਸਨੂੰ ਅਣਲਾਕ ਕਰਨ ਲਈ PUK ਕੋਡ ਟਾਈਪ ਕਰੋ।"</string>
<string name="needPuk2" msgid="4526033371987193070">"SIM ਕਾਰਡ ਅਨਬਲੌਕ ਕਰਨ ਲਈ PUK2 ਟਾਈਪ ਕਰੋ।"</string>
- <string name="enablePin" msgid="209412020907207950">"ਅਸਫਲ, SIM/RUIM ਲੌਕ ਨੂੰ ਚਾਲੂ ਕਰੋ।"</string>
+ <string name="enablePin" msgid="209412020907207950">"ਅਸਫਲ, SIM/RUIM ਲਾਕ ਨੂੰ ਚਾਲੂ ਕਰੋ।"</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
- <item quantity="one">ਇਸਤੋਂ ਪਹਿਲਾਂ ਕਿ SIM ਲੌਕ ਹੋਵੇ, ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਕੀ ਹਨ।</item>
- <item quantity="other">ਇਸਤੋਂ ਪਹਿਲਾਂ ਕਿ SIM ਲੌਕ ਹੋਵੇ, ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਕੀ ਹਨ।</item>
+ <item quantity="one">ਇਸਤੋਂ ਪਹਿਲਾਂ ਕਿ SIM ਲਾਕ ਹੋਵੇ, ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਕੀ ਹਨ।</item>
+ <item quantity="other">ਇਸਤੋਂ ਪਹਿਲਾਂ ਕਿ SIM ਲਾਕ ਹੋਵੇ, ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਕੀ ਹਨ।</item>
</plurals>
<string name="imei" msgid="2625429890869005782">"IMEI"</string>
<string name="meid" msgid="4841221237681254195">"MEID"</string>
@@ -183,7 +183,7 @@
<string name="silent_mode" msgid="7167703389802618663">"ਸਾਈਲੈਂਟ ਮੋਡ"</string>
<string name="turn_on_radio" msgid="3912793092339962371">"ਵਾਇਰਲੈਸ ਚਾਲੂ ਕਰੋ"</string>
<string name="turn_off_radio" msgid="8198784949987062346">"ਵਾਇਰਲੈਸ ਬੰਦ ਕਰੋ"</string>
- <string name="screen_lock" msgid="799094655496098153">"ਸਕ੍ਰੀਨ ਲੌਕ"</string>
+ <string name="screen_lock" msgid="799094655496098153">"ਸਕ੍ਰੀਨ ਲਾਕ"</string>
<string name="power_off" msgid="4266614107412865048">"ਪਾਵਰ ਬੰਦ"</string>
<string name="silent_mode_silent" msgid="319298163018473078">"ਰਿੰਗਰ ਬੰਦ"</string>
<string name="silent_mode_vibrate" msgid="7072043388581551395">"ਰਿੰਗਰ ਥਰਥਰਾਹਟ"</string>
@@ -207,7 +207,7 @@
<string name="global_actions" product="tablet" msgid="408477140088053665">"ਟੈਬਲੈੱਟ ਵਿਕਲਪ"</string>
<string name="global_actions" product="tv" msgid="7240386462508182976">"TV ਚੋਣਾਂ"</string>
<string name="global_actions" product="default" msgid="2406416831541615258">"ਫ਼ੋਨ ਚੋਣਾਂ"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"ਸਕ੍ਰੀਨ ਲੌਕ"</string>
+ <string name="global_action_lock" msgid="2844945191792119712">"ਸਕ੍ਰੀਨ ਲਾਕ"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"ਪਾਵਰ ਬੰਦ"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"ਸੰਕਟਕਾਲ"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"ਬਗ ਰਿਪੋਰਟ"</string>
@@ -464,7 +464,7 @@
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"ਐਪ ਨੂੰ ਬਲੂਟੁੱਥ ਤੇ ਬਲੂਟੁੱਥ ਦਾ ਸੰਰੂਪਣ ਦੇਖਣ, ਜੋੜਾਬੱਧ ਕੀਤੇ ਡੀਵਾਈਸਾਂ ਨਾਲ ਕਨੈਕਸ਼ਨ ਬਣਾਉਣ ਅਤੇ ਸਵੀਕਾਰ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permlab_nfc" msgid="4423351274757876953">"ਨਜ਼ਦੀਕੀ ਖੇਤਰ ਸੰਚਾਰ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string>
<string name="permdesc_nfc" msgid="7120611819401789907">"ਐਪ ਨੂੰ ਨਜ਼ਦੀਕੀ ਖੇਤਰ ਸੰਚਾਰ (NFC) ਟੈਗਾਂ, ਕਾਰਡਾਂ ਅਤੇ ਰੀਡਰਾਂ ਨਾਲ ਸੰਚਾਰ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
- <string name="permlab_disableKeyguard" msgid="3598496301486439258">"ਆਪਣਾ ਸਕ੍ਰੀਨ ਲੌਕ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
+ <string name="permlab_disableKeyguard" msgid="3598496301486439258">"ਆਪਣਾ ਸਕ੍ਰੀਨ ਲਾਕ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
<string name="permdesc_disableKeyguard" msgid="6034203065077122992">"ਐਪ ਨੂੰ ਕੀਲਾਕ ਅਤੇ ਕਿਸੇ ਵੀ ਸੰਬੰਧਿਤ ਪਾਸਵਰਡ ਸੁਰੱਖਿਆ ਨੂੰ ਬੰਦ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਫ਼ੋਨ ਇੱਕ ਇਨਕਮਿੰਗ ਫ਼ੋਨ ਕਾਲ ਪ੍ਰਾਪਤ ਕਰਨ ਵੇਲੇ ਬੰਦ ਕਰਦਾ ਹੈ, ਫਿਰ ਜਦੋਂ ਕਾਲ ਖਤਮ ਹੁੰਦੀ ਹੈ ਤਾਂ ਕੀਲਾਕ ਨੂੰ ਮੁੜ-ਚਾਲੂ ਕਰਦਾ ਹੈ।"</string>
<string name="permlab_manageFingerprint" msgid="5640858826254575638">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਹਾਰਡਵੇਅਰ ਵਿਵਸਥਿਤ ਕਰੋ"</string>
<string name="permdesc_manageFingerprint" msgid="178208705828055464">"ਐਪ ਨੂੰ ਵਰਤੋਂ ਲਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸ਼ਾਮਲ ਕਰਨ ਅਤੇ ਮਿਟਾਉਣ ਦੀਆਂ ਵਿਧੀਆਂ ਦੀ ਬੇਨਤੀ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
@@ -552,15 +552,15 @@
<string name="policydesc_limitPassword" msgid="2502021457917874968">"ਸਕ੍ਰੀਨ ਲਾਕ ਪਾਸਵਰਡਾਂ ਅਤੇ ਪਿੰਨ ਵਿੱਚ ਆਗਿਆ ਦਿੱਤੀ ਲੰਮਾਈ ਅਤੇ ਅੱਖਰਾਂ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ।"</string>
<string name="policylab_watchLogin" msgid="5091404125971980158">"ਸਕ੍ਰੀਨ ਅਣਲਾਕ ਕਰਨ ਦੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ \'ਤੇ ਨਿਗਰਾਨੀ ਰੱਖੋ"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਹੋਏ ਟਾਈਪ ਕੀਤੇ ਗਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦਾ ਨਿਰੀਖਣ ਕਰੋ ਅਤੇ ਟੈਬਲੈੱਟ ਨੂੰ ਲਾਕ ਕਰੋ ਜਾਂ ਟੈਬਲੈੱਟ ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ, ਜੇਕਰ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ।"</string>
- <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਸਮੇਂ ਟਾਈਪ ਕੀਤੇ ਗ਼ਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦਾ ਨਿਰੀਖਣ ਕਰੋ ਅਤੇ TV ਨੂੰ ਲੌਕ ਕਰੋ ਜਾਂ TV ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ ਜੇਕਰ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗ਼ਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ।"</string>
+ <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਸਮੇਂ ਟਾਈਪ ਕੀਤੇ ਗ਼ਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦਾ ਨਿਰੀਖਣ ਕਰੋ ਅਤੇ TV ਨੂੰ ਲਾਕ ਕਰੋ ਜਾਂ TV ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ ਜੇਕਰ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗ਼ਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ।"</string>
<string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਸਮੇਂ ਟਾਈਪ ਕੀਤੇ ਗਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦਾ ਨਿਰੀਖਣ ਕਰੋ ਅਤੇ ਫ਼ੋਨ ਨੂੰ ਲਾਕ ਕਰੋ ਜਾਂ ਫ਼ੋਨ ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ ਜੇਕਰ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ।"</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਹੋਏ ਟਾਈਪ ਕੀਤੇ ਗਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦਾ ਨਿਰੀਖਣ ਕਰੋ ਅਤੇ ਟੈਬਲੈੱਟ ਨੂੰ ਲਾਕ ਕਰੋ ਜਾਂ ਟੈਬਲੈੱਟ ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ, ਜੇਕਰ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ।"</string>
- <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਸਮੇਂ ਟਾਈਪ ਕੀਤੇ ਗ਼ਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦਾ ਨਿਰੀਖਣ ਕਰੋ ਅਤੇ TV ਨੂੰ ਲੌਕ ਕਰੋ ਜਾਂ TV ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ ਜੇਕਰ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗ਼ਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ।"</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਸਮੇਂ ਟਾਈਪ ਕੀਤੇ ਗ਼ਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦਾ ਨਿਰੀਖਣ ਕਰੋ ਅਤੇ TV ਨੂੰ ਲਾਕ ਕਰੋ ਜਾਂ TV ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ ਜੇਕਰ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗ਼ਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ।"</string>
<string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਸਮੇਂ ਟਾਈਪ ਕੀਤੇ ਗਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦਾ ਨਿਰੀਖਣ ਕਰੋ ਅਤੇ ਫ਼ੋਨ ਨੂੰ ਲਾਕ ਕਰੋ ਜਾਂ ਫ਼ੋਨ ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ ਜੇਕਰ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ।"</string>
- <string name="policylab_resetPassword" msgid="4934707632423915395">"ਸਕ੍ਰੀਨ ਲੌਕ ਬਦਲੋ"</string>
- <string name="policydesc_resetPassword" msgid="1278323891710619128">"ਸਕ੍ਰੀਨ ਲੌਕ ਬਦਲੋ।"</string>
- <string name="policylab_forceLock" msgid="2274085384704248431">"ਸਕ੍ਰੀਨ ਲੌਕ ਕਰੋ"</string>
- <string name="policydesc_forceLock" msgid="1141797588403827138">"ਇਸਤੇ ਨਿਯੰਤਰਣ ਪਾਓ ਕਿ ਸਕ੍ਰਿਨ ਕਿਵੇਂ ਅਤੇ ਕਦੋਂ ਲੌਕ ਹੁੰਦੀ ਹੈ।"</string>
+ <string name="policylab_resetPassword" msgid="4934707632423915395">"ਸਕ੍ਰੀਨ ਲਾਕ ਬਦਲੋ"</string>
+ <string name="policydesc_resetPassword" msgid="1278323891710619128">"ਸਕ੍ਰੀਨ ਲਾਕ ਬਦਲੋ।"</string>
+ <string name="policylab_forceLock" msgid="2274085384704248431">"ਸਕ੍ਰੀਨ ਲਾਕ ਕਰੋ"</string>
+ <string name="policydesc_forceLock" msgid="1141797588403827138">"ਇਸਤੇ ਨਿਯੰਤਰਣ ਪਾਓ ਕਿ ਸਕ੍ਰਿਨ ਕਿਵੇਂ ਅਤੇ ਕਦੋਂ ਲਾਕ ਹੁੰਦੀ ਹੈ।"</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ"</string>
<string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"ਇੱਕ ਫੈਕਟਰੀ ਡਾਟਾ ਰੀਸੈੱਟ ਕਰਕੇ ਚਿਤਾਵਨੀ ਤੋਂ ਬਿਨਾਂ ਟੈਬਲੈੱਟ ਦਾ ਡਾਟਾ ਮਿਟਾਓ।"</string>
<string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"ਇੱਕ ਫੈਕਟਰੀ ਡਾਟਾ ਰੀਸੈੱਟ ਕਰਕੇ ਚਿਤਾਵਨੀ ਤੋਂ ਬਿਨਾਂ ਟੀਵੀ ਦਾ ਡਾਟਾ ਮਿਟਾਓ।"</string>
@@ -577,8 +577,8 @@
<string name="policydesc_encryptedStorage" msgid="2637732115325316992">"ਲੋੜ ਹੈ ਕਿ ਸਟੋਰ ਕੀਤਾ ਐਪ ਡਾਟਾ ਇਨਕ੍ਰਿਪਟ ਕੀਤਾ ਜਾਏ।"</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"ਕੈਮਰੇ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
<string name="policydesc_disableCamera" msgid="2306349042834754597">"ਸਾਰੇ ਡੀਵਾਈਸ ਕੈਮਰਿਆਂ ਦੀ ਵਰਤੋਂ ਰੋਕੋ।"</string>
- <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"ਸਕ੍ਰੀਨ ਲੌਕ ਦੀਆਂ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
- <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"ਸਕ੍ਰੀਨ ਲੌਕ ਦੀਆਂ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦੀ ਵਰਤੋਂ ਰੋਕੋ।"</string>
+ <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"ਸਕ੍ਰੀਨ ਲਾਕ ਦੀਆਂ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
+ <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"ਸਕ੍ਰੀਨ ਲਾਕ ਦੀਆਂ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦੀ ਵਰਤੋਂ ਰੋਕੋ।"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"ਘਰ"</item>
<item msgid="869923650527136615">"ਮੋਬਾਈਲ"</item>
@@ -704,7 +704,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"ਅਣਲਾਕ ਕਰਨ ਲਈ, ਪਹਿਲਾਂ ਮੀਨੂ ਫਿਰ 0 ਦਬਾਓ।"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"ਐਮਰਜੈਂਸੀ ਨੰਬਰ"</string>
<string name="lockscreen_carrier_default" msgid="6169005837238288522">"ਕੋਈ ਸੇਵਾ ਨਹੀਂ"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"ਸਕ੍ਰੀਨ ਲੌਕ ਕੀਤੀ।"</string>
+ <string name="lockscreen_screen_locked" msgid="7288443074806832904">"ਸਕ੍ਰੀਨ ਲਾਕ ਕੀਤੀ।"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ ਜਾਂ ਸੰਕਟਕਾਲੀਨ ਕਾਲ ਕਰੋ।"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ।"</string>
<string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਪੈਟਰਨ ਡ੍ਰਾ ਕਰੋ"</string>
@@ -731,10 +731,10 @@
<string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"ਰੀਵਾਈਂਡ ਕਰੋ"</string>
<string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"ਤੇਜ਼ੀ ਨਾਲ ਅੱਗੇ ਭੇਜੋ"</string>
<string name="emergency_calls_only" msgid="6733978304386365407">"ਕੇਵਲ ਐਮਰਜੈਂਸੀ ਕਾਲਾਂ"</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"ਨੈੱਟਵਰਕ ਲੌਕ ਕੀਤਾ"</string>
+ <string name="lockscreen_network_locked_message" msgid="143389224986028501">"ਨੈੱਟਵਰਕ ਲਾਕ ਕੀਤਾ"</string>
<string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM ਕਾਰਡ PUK-ਲੌਕਡ ਹੈ।"</string>
<string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"ਵਰਤੋਂਕਾਰ ਗਾਈਡ ਦੇਖੋ ਜਾਂ ਗਾਹਕ ਸੇਵਾ ਨੂੰ ਫ਼ੋਨ ਕਰੋ।"</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM ਕਾਰਡ ਲੌਕ ਕੀਤਾ ਹੋਇਆ ਹੈ।"</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>
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ਫ਼ੋਨ ਕਰੋ"</string>
<string name="map" msgid="6068210738233985748">"ਨਕਸ਼ੇ"</string>
<string name="browse" msgid="6993590095938149861">"ਬ੍ਰਾਊਜ਼ਰ"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"ਸਟੋਰੇਜ ਦੀ ਜਗ੍ਹਾ ਖਤਮ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ਕੁਝ ਸਿਸਟਮ ਫੰਕਸ਼ਨ ਕੰਮ ਨਹੀਂ ਵੀ ਕਰ ਸਕਦੇ"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ਸਿਸਟਮ ਲਈ ਲੋੜੀਂਦੀ ਸਟੋਰੇਜ ਨਹੀਂ ਹੈ। ਯਕੀਨੀ ਬਣਾਓ ਕਿ ਤੁਹਾਡੇ ਕੋਲ 250MB ਖਾਲੀ ਜਗ੍ਹਾ ਹੈ ਅਤੇ ਮੁੜ-ਚਾਲੂ ਕਰੋ।"</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"ਰੱਦ ਕਰੋ"</string>
<string name="yes" msgid="5362982303337969312">"ਠੀਕ"</string>
<string name="no" msgid="5141531044935541497">"ਰੱਦ ਕਰੋ"</string>
+ <string name="close" msgid="2318214661230355730">"ਬੰਦ ਕਰੋ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ਧਿਆਨ ਦਿਓ"</string>
<string name="loading" msgid="7933681260296021180">"ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ..."</string>
<string name="capital_on" msgid="1544682755514494298">"ਚਾਲੂ"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"ਸਕੇਲ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ਹਮੇਸ਼ਾਂ ਦਿਖਾਓ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"ਸਿਸਟਮ ਸੈਟਿੰਗਾਂ > ਐਪਾਂ > ਡਾਊਨਲੋਡ ਕੀਤਿਆਂ ਵਿੱਚ ਇਸਨੂੰ ਮੁੜ-ਸਮਰੱਥ ਬਣਾਓ।"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"ਐਪ ਪ੍ਰਤਿਕਿਰਿਆ ਨਹੀਂ ਦੇ ਰਹੀ ਹੈ"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"ਸ਼ਾਇਦ <xliff:g id="APP_NAME">%1$s</xliff:g> ਵੱਲੋਂ ਬਹੁਤ ਜ਼ਿਆਦਾ ਮੈਮੋਰੀ ਦੀ ਵਰਤੋਂ ਕੀਤੀ ਜਾ ਰਹੀ ਹੋਵੇ।"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਵਰਤਮਾਨ ਡਿਸਪਲੇ ਆਕਾਰ ਸੈਟਿੰਗ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ ਹੈ ਅਤੇ ਅਣਕਿਆਸੇ ਤੌਰ \'ਤੇ ਵਿਹਾਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ਹਮੇਸ਼ਾ ਦਿਖਾਓ"</string>
<string name="smv_application" msgid="3307209192155442829">"ਐਪ <xliff:g id="APPLICATION">%1$s</xliff:g> (ਪ੍ਰਕਿਰਿਆ <xliff:g id="PROCESS">%2$s</xliff:g>) ਨੇ ਆਪਣੀ ਖੁਦ-ਲਾਗੂ ਕੀਤੀ ਸਟ੍ਰਿਕਟਮੋਡ ਨੀਤੀ ਦੀ ਉਲੰਘਣਾ ਕੀਤੀ ਹੈ।"</string>
@@ -1221,7 +1228,7 @@
<string name="ext_media_unsupported_notification_message" msgid="6121601473787888589">"ਇਹ ਡੀਵਾਈਸ ਇਸ <xliff:g id="NAME">%s</xliff:g> ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦਾ ਹੈ। ਕਿਸੇ ਸਮਰਥਿਤ ਫਾਰਮੈਟ ਵਿੱਚ ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="ext_media_unsupported_notification_message" product="tv" msgid="3725436899820390906">"ਇਹ ਡੀਵਾਈਸ ਇਸ <xliff:g id="NAME">%s</xliff:g> ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦਾ ਹੈ। ਕਿਸੇ ਸਮਰਥਿਤ ਫਾਰਮੈਟ ਵਿੱਚ ਸਥਾਪਤ ਕਰਨ ਲਈ ਚੁਣੋ।"</string>
<string name="ext_media_badremoval_notification_title" msgid="3206248947375505416">"<xliff:g id="NAME">%s</xliff:g> ਨੂੰ ਅਚਨਚੇਤ ਹਟਾਇਆ ਗਿਆ"</string>
- <string name="ext_media_badremoval_notification_message" msgid="380176703346946313">"ਡੇਟਾ ਦੇ ਨੁਕਸਾਨ ਤੋਂ ਬੱਚਣ ਲਈ ਹਟਾਉਣ ਤੋਂ ਪਹਿਲਾਂ <xliff:g id="NAME">%s</xliff:g> ਅਨਮਾਊਂਟ ਕਰੋ"</string>
+ <string name="ext_media_badremoval_notification_message" msgid="380176703346946313">" ਡਾਟਾ ਦੇ ਨੁਕਸਾਨ ਤੋਂ ਬੱਚਣ ਲਈ ਹਟਾਉਣ ਤੋਂ ਪਹਿਲਾਂ <xliff:g id="NAME">%s</xliff:g> ਅਨਮਾਊਂਟ ਕਰੋ"</string>
<string name="ext_media_nomedia_notification_title" msgid="1704840188641749091">"ਹਟਾਇਆ <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_nomedia_notification_message" msgid="6471542972147056586">"<xliff:g id="NAME">%s</xliff:g> ਨੂੰ ਹਟਾਇਆ ਗਿਆ, ਕੋਈ ਨਵਾਂ ਸੰਮਿਲਿਤ ਕਰੋ"</string>
<string name="ext_media_unmounting_notification_title" msgid="640674168454809372">"ਅਜੇ ਵੀ <xliff:g id="NAME">%s</xliff:g> ਨੂੰ ਕੱਢ ਰਿਹਾ ਹੈ..."</string>
@@ -1232,11 +1239,11 @@
<string name="ext_media_missing_title" msgid="620980315821543904">"<xliff:g id="NAME">%s</xliff:g> ਲਾਪਤਾ"</string>
<string name="ext_media_missing_message" msgid="5761133583368750174">"ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਮੁੜ ਸੰਮਿਲਿਤ ਕਰੋ"</string>
<string name="ext_media_move_specific_title" msgid="1471100343872375842">"<xliff:g id="NAME">%s</xliff:g> ਮੂਵ ਕਰ ਰਿਹਾ ਹੈ"</string>
- <string name="ext_media_move_title" msgid="1022809140035962662">"ਡੇਟਾ ਮੂਵ ਕਰ ਰਿਹਾ ਹੈ"</string>
+ <string name="ext_media_move_title" msgid="1022809140035962662">" ਡਾਟਾ ਮੂਵ ਕਰ ਰਿਹਾ ਹੈ"</string>
<string name="ext_media_move_success_title" msgid="8575300932957954671">"ਮੂਵ ਸੰਪੂਰਣ"</string>
- <string name="ext_media_move_success_message" msgid="4199002148206265426">"ਡੇਟਾ ਨੂੰ <xliff:g id="NAME">%s</xliff:g> ਵਿੱਚ ਮੂਵ ਕੀਤਾ ਗਿਆ"</string>
- <string name="ext_media_move_failure_title" msgid="7613189040358789908">"ਡੇਟਾ ਨੂੰ ਮੂਵ ਨਹੀਂ ਕਰ ਸਕਿਆ"</string>
- <string name="ext_media_move_failure_message" msgid="1978096440816403360">"ਡੇਟਾ ਮੂਲ ਸਥਾਨ \'ਤੇ ਛੱਡਿਆ ਗਿਆ"</string>
+ <string name="ext_media_move_success_message" msgid="4199002148206265426">" ਡਾਟਾ ਨੂੰ <xliff:g id="NAME">%s</xliff:g> ਵਿੱਚ ਮੂਵ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="ext_media_move_failure_title" msgid="7613189040358789908">" ਡਾਟਾ ਨੂੰ ਮੂਵ ਨਹੀਂ ਕਰ ਸਕਿਆ"</string>
+ <string name="ext_media_move_failure_message" msgid="1978096440816403360">" ਡਾਟਾ ਮੂਲ ਸਥਾਨ \'ਤੇ ਛੱਡਿਆ ਗਿਆ"</string>
<string name="ext_media_status_removed" msgid="6576172423185918739">"ਹਟਾਏ ਗਏ"</string>
<string name="ext_media_status_unmounted" msgid="2551560878416417752">"ਹਟਾਇਆ ਗਿਆ"</string>
<string name="ext_media_status_checking" msgid="6193921557423194949">"ਜਾਂਚ ਕਰ ਰਿਹਾ ਹੈ..."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ਫ਼ੋਨ ਕਰੋ"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ਡੌਕ ਸਪੀਕਰਸ"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"ਹੈੱਡਫ਼ੋਨ"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"ਸਿਸਟਮ"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ਆਡੀਓ"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"ਵਾਇਰਲੈੱਸ ਡਿਸਪਲੇ"</string>
@@ -1724,7 +1729,7 @@
<string name="new_sms_notification_content" msgid="7002938807812083463">"ਦੇਖਣ ਲਈ SMS ਐਪ ਖੋਲ੍ਹੋ"</string>
<string name="user_encrypted_title" msgid="9054897468831672082">"ਕੁਝ ਪ੍ਰਕਾਰਜਾਤਮਕਤਾ ਸੀਮਿਤ ਹੋ ਸਕਦੀ ਹੈ"</string>
<string name="user_encrypted_message" msgid="4923292604515744267">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <string name="user_encrypted_detail" msgid="5708447464349420392">"ਵਰਤੋਂਕਾਰ ਡਾਟਾ ਲੌਕ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"ਵਰਤੋਂਕਾਰ ਡਾਟਾ ਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
<string name="profile_encrypted_detail" msgid="3700965619978314974">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਲਾਕ ਕੀਤੀ ਗਈ"</string>
<string name="profile_encrypted_message" msgid="6964994232310195874">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋਈ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 071b570..0989576 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -257,7 +257,7 @@
<string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplikacje zużywające baterię"</string>
<string name="foreground_service_app_in_background" msgid="1060198778219731292">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> zużywa baterię"</string>
<string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Liczba aplikacji zużywających baterię: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Kliknij, by wyświetlić szczegóły wykorzystania baterii i transmisji danych"</string>
+ <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Kliknij, by wyświetlić szczegóły wykorzystania baterii i użycia danych"</string>
<string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
<string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
<string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
@@ -347,7 +347,7 @@
<string name="permlab_runInBackground" msgid="7365290743781858803">"działanie w tle"</string>
<string name="permdesc_runInBackground" msgid="7370142232209999824">"Ta aplikacja może działać w tle. Bateria może się szybciej rozładowywać."</string>
<string name="permlab_useDataInBackground" msgid="8694951340794341809">"transmisja danych w tle"</string>
- <string name="permdesc_useDataInBackground" msgid="6049514223791806027">"Ta aplikacja może przesyłać i odbierać dane w tle. Transmisja danych może się zwiększyć."</string>
+ <string name="permdesc_useDataInBackground" msgid="6049514223791806027">"Ta aplikacja może przesyłać i odbierać dane w tle. Użycie danych może się zwiększyć."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"sprawianie, że aplikacja jest cały czas uruchomiona"</string>
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Pozwala aplikacji na trwałe zapisywanie swoich fragmentów w pamięci. Może to zmniejszyć ilość pamięci dostępnej dla innych aplikacji i spowolnić działanie tabletu."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Pozwala aplikacji zapewnić nieusuwalność swoich fragmentów z pamięci. Może to ograniczyć ilość pamięci dostępną dla innych aplikacji i spowalniać działanie telewizora."</string>
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Mapy"</string>
<string name="browse" msgid="6993590095938149861">"Internet"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Kończy się miejsce"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Niektóre funkcje systemu mogą nie działać"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Za mało pamięci w systemie. Upewnij się, że masz 250 MB wolnego miejsca i uruchom urządzenie ponownie."</string>
@@ -1029,6 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Anuluj"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Anuluj"</string>
+ <string name="close" msgid="2318214661230355730">"ZAMKNIJ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Uwaga"</string>
<string name="loading" msgid="7933681260296021180">"Wczytuję…"</string>
<string name="capital_on" msgid="1544682755514494298">"Wł."</string>
@@ -1085,6 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Zawsze pokazuj"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Włącz ponownie, wybierając Ustawienia systemowe > Aplikacje > Pobrane."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacja nie reaguje"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> może wykorzystywać za dużo pamięci"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje obecnie ustawionego rozmiaru wyświetlacza i może działać niestabilnie."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Zawsze pokazuj"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) naruszyła wymuszone przez siebie zasady StrictMode."</string>
@@ -1426,7 +1433,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>
- <string name="data_usage_warning_title" msgid="3620440638180218181">"Alert transmisji danych"</string>
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Alert użycia 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>
@@ -1467,11 +1474,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Telewizor"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Głośniki stacji dokującej"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Słuchawki"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Dźwięk Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Wyświetlacz bezprzewodowy"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 8e3c991..a9e0ac9 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefone"</string>
<string name="map" msgid="6068210738233985748">"Mapas"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Pouco espaço de armazenamento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema podem não funcionar"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Não há armazenamento suficiente para o sistema. Certifique-se de ter 250 MB de espaço livre e reinicie."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancelar"</string>
+ <string name="close" msgid="2318214661230355730">"FECHAR"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
<string name="loading" msgid="7933681260296021180">"Carregando…"</string>
<string name="capital_on" msgid="1544682755514494298">"LIG"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reativar isso em Configurações do sistema > Apps > Transferidos."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"O app não está respondendo"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> pode estar usando muita memória."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com a configuração atual de tamanho de exibição e pode se comportar de forma inesperada."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"O app <xliff:g id="APPLICATION">%1$s</xliff:g>, processo <xliff:g id="PROCESS">%2$s</xliff:g>, violou a política StrictMode imposta automaticamente."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefone"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Alto-falantes da dock"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Fones de ouvido"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Display sem fio"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 1042165..cd26bd5 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telemóvel"</string>
<string name="map" msgid="6068210738233985748">"Mapas"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Está quase sem espaço de armazenamento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema poderão não funcionar"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Não existe armazenamento suficiente para o sistema. Certifique-se de que tem 250 MB de espaço livre e reinicie."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancelar"</string>
+ <string name="close" msgid="2318214661230355730">"FECHAR"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
<string name="loading" msgid="7933681260296021180">"A carregar…"</string>
<string name="capital_on" msgid="1544682755514494298">"Ativado"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reative este modo nas Definições do Sistema > Aplicações > Transferidas."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"A aplicação não está a responder"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"A aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> pode estar a utilizar demasiada memória."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> não suporta a definição de Tamanho do ecrã atual e pode ter um comportamento inesperado."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) violou a política StrictMode auto-imposta."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telemóvel"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altif. estação ancoragem"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Auscultadores"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Visualização sem fios"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 8e3c991..a9e0ac9 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefone"</string>
<string name="map" msgid="6068210738233985748">"Mapas"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Pouco espaço de armazenamento"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema podem não funcionar"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Não há armazenamento suficiente para o sistema. Certifique-se de ter 250 MB de espaço livre e reinicie."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancelar"</string>
+ <string name="close" msgid="2318214661230355730">"FECHAR"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
<string name="loading" msgid="7933681260296021180">"Carregando…"</string>
<string name="capital_on" msgid="1544682755514494298">"LIG"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reativar isso em Configurações do sistema > Apps > Transferidos."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"O app não está respondendo"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> pode estar usando muita memória."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com a configuração atual de tamanho de exibição e pode se comportar de forma inesperada."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
<string name="smv_application" msgid="3307209192155442829">"O app <xliff:g id="APPLICATION">%1$s</xliff:g>, processo <xliff:g id="PROCESS">%2$s</xliff:g>, violou a política StrictMode imposta automaticamente."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefone"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Alto-falantes da dock"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Fones de ouvido"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Display sem fio"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 1750066..67f17b25 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1000,6 +1000,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Hărți"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spațiul de stocare aproape ocupat"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Este posibil ca unele funcții de sistem să nu funcționeze"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Spațiu de stocare insuficient pentru sistem. Asigurați-vă că aveți 250 MB de spațiu liber și reporniți."</string>
@@ -1009,6 +1013,7 @@
<string name="cancel" msgid="6442560571259935130">"Anulați"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Anulați"</string>
+ <string name="close" msgid="2318214661230355730">"ÎNCHIDEȚI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Atenție"</string>
<string name="loading" msgid="7933681260296021180">"Se încarcă…"</string>
<string name="capital_on" msgid="1544682755514494298">"DA"</string>
@@ -1065,6 +1070,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scară"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Afișați întotdeauna"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivați acest mod din Setări de sistem > Aplicații > Descărcate."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplicația nu răspunde"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Este posibil ca <xliff:g id="APP_NAME">%1$s</xliff:g> să utilizeze prea multă memorie."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă setarea actuală pentru Dimensiunea afișării și este posibil să aibă un comportament neașteptat."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Afișează întotdeauna"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplicația <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) a încălcat propria politică StrictMode."</string>
@@ -1444,11 +1451,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Difuz. dispozit. andocare"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Căști"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Ecran wireless"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index b5cf233..70631d0 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Телефон"</string>
<string name="map" msgid="6068210738233985748">"Карты"</string>
<string name="browse" msgid="6993590095938149861">"Браузер"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Недостаточно памяти"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некоторые функции могут не работать"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Недостаточно свободного места для системы. Освободите не менее 250 МБ дискового пространства и перезапустите устройство."</string>
@@ -1029,6 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Отмена"</string>
<string name="yes" msgid="5362982303337969312">"ОК"</string>
<string name="no" msgid="5141531044935541497">"Отмена"</string>
+ <string name="close" msgid="2318214661230355730">"ЗАКРЫТЬ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Внимание"</string>
<string name="loading" msgid="7933681260296021180">"Загрузка…"</string>
<string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1085,6 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Масштаб"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Всегда показывать"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Включить эту функцию можно в меню \"Настройки > Приложения > Загруженные\"."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Приложение не отвечает"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Возможно, приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" использует слишком много памяти."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает выбранный масштаб изображения на экране и может работать некорректно."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Всегда показывать"</string>
<string name="smv_application" msgid="3307209192155442829">"Приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" (процесс: <xliff:g id="PROCESS">%2$s</xliff:g>) нарушило собственную политику StrictMode."</string>
@@ -1467,11 +1474,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевизор"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Телефон"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Динамики док-станции"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Наушники"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Воспроизведение звука через Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Беспроводной монитор"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 539064c..11c42dc 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -982,6 +982,10 @@
<string name="dial" msgid="4204975095406423102">"දුරකථනය"</string>
<string name="map" msgid="6068210738233985748">"සිතියම්"</string>
<string name="browse" msgid="6993590095938149861">"බ්රවුසරය"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"ආචයනය ඉඩ ප්රමාණය අඩු වී ඇත"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"සමහර පද්ධති කාර්යයන් ක්රියා නොකරනු ඇත"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"පද්ධතිය සඳහා ප්රමාණවත් ඉඩ නොමැත. ඔබට 250MB නිදහස් ඉඩක් තිබෙන ඔබට තිබෙන බව සහතික කරගෙන නැවත උත්සාහ කරන්න."</string>
@@ -991,6 +995,7 @@
<string name="cancel" msgid="6442560571259935130">"අවලංගු කරන්න"</string>
<string name="yes" msgid="5362982303337969312">"හරි"</string>
<string name="no" msgid="5141531044935541497">"අවලංගු කරන්න"</string>
+ <string name="close" msgid="2318214661230355730">"වසන්න"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"අවධානය"</string>
<string name="loading" msgid="7933681260296021180">"පූරණය වෙමින්..."</string>
<string name="capital_on" msgid="1544682755514494298">"සක්රීයයි"</string>
@@ -1047,6 +1052,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"පරිමාණය"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"සැමවිටම පෙන්වන්න"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"පද්ධති සැකසීම් තුළ මෙය නැවත ක්රියාත්මක කරන්න > යෙදුම් > බාගන්නා ලදි."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"යෙදුම ප්රතිචාර නොදක්වයි"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> මතකය ඉතා වැඩියෙන් භාවිත කරනවා විය හැකිය."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> වත්මන් සංදර්ශක තරම සඳහා සහාය නොදක්වන අතර අනපේක්ෂිත ලෙස හැසිරීමට හැකිය."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"සැම විටම පෙන්වන්න"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> යෙදුම (<xliff:g id="PROCESS">%2$s</xliff:g> ක්රියාවලිය) එහි StrictMode කොන්දේසිය උල්ලංඝනය කර ඇත."</string>
@@ -1423,11 +1430,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"රූපවාහිනී"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"දුරකථනය"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"නාදක ඩොක් කරන්න"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"ඉස් බණු"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"පද්ධතිය"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"බ්ලූටූත් ශ්රව්ය"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"නොරැහැන් සංදර්ශකය"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index be7664c..1eb24ac 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Telefón"</string>
<string name="map" msgid="6068210738233985748">"Mapy"</string>
<string name="browse" msgid="6993590095938149861">"Prehliadač"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nedostatok ukladacieho priestoru"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Niektoré systémové funkcie nemusia fungovať"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"V úložisku nie je dostatok voľného miesta pre systém. Zaistite, aby ste mali 250 MB voľného miesta a zariadenie reštartujte."</string>
@@ -1029,6 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Zrušiť"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Zrušiť"</string>
+ <string name="close" msgid="2318214661230355730">"ZAVRIEŤ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Upozornenie"</string>
<string name="loading" msgid="7933681260296021180">"Načítava sa…"</string>
<string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1085,6 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Prispôsobiť veľkosť"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vždy zobraziť"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Povoľte to znova v sekcii Nastavenia systému > Aplikácie > Stiahnuté súbory."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikácia nereaguje"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> pravdepodobne používa príliš veľa pamäte."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> aktuálne nastavenie veľkosti zobrazenia nepodporuje a môže sa správať neočakávane."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vždy zobrazovať"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikácia <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila svoje vlastné vynútené pravidlá StrictMode."</string>
@@ -1467,11 +1474,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televízor"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefón"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Reproduktory doku"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Slúchadlá"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Bezdrôtové zobrazenie"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index aaa2432..4396cd3 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Zemljevidi"</string>
<string name="browse" msgid="6993590095938149861">"Brskalnik"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Prostor za shranjevanje bo pošel"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Nekatere sistemske funkcije morda ne delujejo"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"V shrambi ni dovolj prostora za sistem. Sprostite 250 MB prostora in znova zaženite napravo."</string>
@@ -1029,6 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Prekliči"</string>
<string name="yes" msgid="5362982303337969312">"V redu"</string>
<string name="no" msgid="5141531044935541497">"Prekliči"</string>
+ <string name="close" msgid="2318214661230355730">"ZAPRI"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Pozor"</string>
<string name="loading" msgid="7933681260296021180">"Nalaganje …"</string>
<string name="capital_on" msgid="1544682755514494298">"VKLOPLJENO"</string>
@@ -1085,6 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Lestvica"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vedno pokaži"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Znova omogočite to v sistemskih nastavitvah > Aplikacije > Preneseno."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacija se ne odziva"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> morda uporablja preveč pomnilnika."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira trenutne nastavitve velikosti zaslona, kar lahko vodi v nepričakovano delovanje."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Vedno pokaži"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) krši svoj samouveljavljiv pravilnik o strogem načinu."</string>
@@ -1467,11 +1474,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televizor"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Zvočniki stojala"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Slušalke"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Zvok prek Bluetootha"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Brezžični prikaz"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 31c7c31..d62f95f 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefoni"</string>
<string name="map" msgid="6068210738233985748">"Hartat"</string>
<string name="browse" msgid="6993590095938149861">"Shfletuesi"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Hapësira ruajtëse po mbaron"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Disa funksione të sistemit mund të mos punojnë"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nuk ka hapësirë të mjaftueshme ruajtjeje për sistemin. Sigurohu që të kesh 250 MB hapësirë të lirë dhe pastaj të rifillosh."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Anulo"</string>
<string name="yes" msgid="5362982303337969312">"Në rregull"</string>
<string name="no" msgid="5141531044935541497">"Anulo"</string>
+ <string name="close" msgid="2318214661230355730">"MBYLL"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Kujdes!"</string>
<string name="loading" msgid="7933681260296021180">"Po ngarkohet..."</string>
<string name="capital_on" msgid="1544682755514494298">"Aktivizuar"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Shkalla"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Shfaq gjithnjë"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivizoje sërish këtë te \"Cilësimet e sistemit\" > \"Aplikacionet\" > \"Të shkarkuara\"."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacioni nuk po përgjigjet"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> mund të jetë duke përdorur shumë memorie."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk mbështet cilësimin aktual të madhësisë së ekranit dhe mund të shfaqë sjellje të papritura."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Shfaq gjithmonë"</string>
<string name="smv_application" msgid="3307209192155442829">"Aplikacioni <xliff:g id="APPLICATION">%1$s</xliff:g> (procesi <xliff:g id="PROCESS">%2$s</xliff:g>) ka shkelur politikën e tij të vetë-imponuar \"Modaliteti i ashpër\" (StrictMode)."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televizori"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altoparlantët e stacionit"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Kufjet"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistemi"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audioja e \"bluetooth-it\""</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Ekran pa tel"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 5d25cf1..37552af 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1000,6 +1000,10 @@
<string name="dial" msgid="4204975095406423102">"Позови"</string>
<string name="map" msgid="6068210738233985748">"Мапе"</string>
<string name="browse" msgid="6993590095938149861">"Прегледач"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Меморијски простор је на измаку"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Неке системске функције можда не функционишу"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема довољно меморијског простора за систем. Уверите се да имате 250 MB слободног простора и поново покрените."</string>
@@ -1009,6 +1013,7 @@
<string name="cancel" msgid="6442560571259935130">"Откажи"</string>
<string name="yes" msgid="5362982303337969312">"Потврди"</string>
<string name="no" msgid="5141531044935541497">"Откажи"</string>
+ <string name="close" msgid="2318214661230355730">"ЗАТВОРИ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Пажња"</string>
<string name="loading" msgid="7933681260296021180">"Учитава се…"</string>
<string name="capital_on" msgid="1544682755514494298">"ДА"</string>
@@ -1065,6 +1070,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Размера"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Увек приказуј"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Поново омогућите у менију Системска подешавања > Апликације > Преузето."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Апликација не реагује"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> можда користи превише меморије."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава тренутно подешавање величине приказа и може да се понаша неочекивано."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Увек приказуј"</string>
<string name="smv_application" msgid="3307209192155442829">"Апликација <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) је прекршила самонаметнуте StrictMode смернице."</string>
@@ -1444,11 +1451,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ТВ"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Телефон"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Звучници базне станице"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Слушалице"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Бежични екран"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index d0c8572..64d8cba 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Kartor"</string>
<string name="browse" msgid="6993590095938149861">"Webbläsare"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Lagringsutrymmet börjar ta slut"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Det kan hända att vissa systemfunktioner inte fungerar"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Det finns inte tillräckligt med utrymme för systemet. Kontrollera att du har ett lagringsutrymme på minst 250 MB och starta om."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Avbryt"</string>
+ <string name="close" msgid="2318214661230355730">"STÄNG"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Obs!"</string>
<string name="loading" msgid="7933681260296021180">"Läser in …"</string>
<string name="capital_on" msgid="1544682755514494298">"PÅ"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Anpassning"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Visa alltid"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivera detta igen i Systeminställningar > Appar > Hämtat."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Appen svarar inte"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> kanske använder för mycket minne."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för den nuvarande inställningen för skärmstorlek och kanske inte fungerar som förväntat."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Visa alltid"</string>
<string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (processen <xliff:g id="PROCESS">%2$s</xliff:g>) har brutit mot sin egen StrictMode-policy."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Mobil"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dockningsstationens högtalare"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Hörlurar"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ljud"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Trådlös skärm"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index a28e14a..c3ee444 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -978,6 +978,10 @@
<string name="dial" msgid="4204975095406423102">"Simu"</string>
<string name="map" msgid="6068210738233985748">"Ramani"</string>
<string name="browse" msgid="6993590095938149861">"Kivinjari"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nafasi ya kuhifadhi inakaribia kujaa"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Baadhi ya vipengee vya mfumo huenda visifanye kazi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Hifadhi haitoshi kwa ajili ya mfumo. Hakikisha una MB 250 za nafasi ya hifadhi isiyotumika na uanzishe upya."</string>
@@ -987,6 +991,7 @@
<string name="cancel" msgid="6442560571259935130">"Ghairi"</string>
<string name="yes" msgid="5362982303337969312">"Sawa"</string>
<string name="no" msgid="5141531044935541497">"Ghairi"</string>
+ <string name="close" msgid="2318214661230355730">"FUNGA"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Zingatia"</string>
<string name="loading" msgid="7933681260296021180">"Inapakia…"</string>
<string name="capital_on" msgid="1544682755514494298">"Washa"</string>
@@ -1043,6 +1048,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Kipimo"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Onyesha kila wakati"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Wezesha tena hii katika mipangilio ya Mfumo > Programu > iliyopakuliwa."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Programu haifanyi kazi"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Huenda <xliff:g id="APP_NAME">%1$s</xliff:g> inatumia hifadhi nyingi mno."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> haiwezi kutumia mipangilio ya sasa ya ukubwa wa Skrini na huenda isifanye kazi vizuri."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Onyesha kila wakati"</string>
<string name="smv_application" msgid="3307209192155442829">"Programu <xliff:g id="APPLICATION">%1$s</xliff:g> (utaratibu <xliff:g id="PROCESS">%2$s</xliff:g>) imeenda kinyume na sera yake ya StrictMode."</string>
@@ -1419,11 +1426,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Runinga"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Simu"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Vipasa sauti vya kituo"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Vipokeasauti"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Mfumo"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Sauti ya Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Uonyeshaji usiotumia waya"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 62f9053..cd2a566 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ஃபோன்"</string>
<string name="map" msgid="6068210738233985748">"வரைபடம்"</string>
<string name="browse" msgid="6993590095938149861">"உலாவி"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"சேமிப்பிடம் குறைகிறது"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"சில அமைப்பு செயல்பாடுகள் வேலை செய்யாமல் போகலாம்"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"முறைமையில் போதுமான சேமிப்பகம் இல்லை. 250மெ.பை. அளவு காலி இடவசதி இருப்பதை உறுதிசெய்து மீண்டும் தொடங்கவும்."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"ரத்துசெய்"</string>
<string name="yes" msgid="5362982303337969312">"சரி"</string>
<string name="no" msgid="5141531044935541497">"ரத்துசெய்"</string>
+ <string name="close" msgid="2318214661230355730">"மூடு"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"கவனத்திற்கு"</string>
<string name="loading" msgid="7933681260296021180">"ஏற்றுகிறது..."</string>
<string name="capital_on" msgid="1544682755514494298">"ஆன்"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"அளவு"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"எப்போதும் காட்டு"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"சிஸ்டம் அமைப்பு > பயன்பாடுகள் > பதிவிறக்கம் என்பதில் இதை மீண்டும் இயக்கவும்."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"பயன்பாடு செயல்படவில்லை"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> பயன்பாடு, அதிகளவு நினைவகத்தைப் பயன்படுத்தக்கூடும்."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"தற்போதைய திரை அளவு அமைப்பை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காததால், அது வழக்கத்திற்கு மாறாகச் செயல்படக்கூடும்."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"எப்போதும் காட்டு"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> பயன்பாடு (செயல்முறை <xliff:g id="PROCESS">%2$s</xliff:g>), தனது சுய-செயலாக்க StrictMode கொள்கையை மீறியது."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"டிவி"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ஃபோன்"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"மொபைல் வைக்கும் கருவியின் ஸ்பீக்கர்கள்"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"ஹெட்ஃபோன்கள்"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"சிஸ்டம்"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"புளூடூத் ஆடியோ"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"வயர்லெஸ் காட்சி"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 95c0556..90981e7 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"ఫోన్"</string>
<string name="map" msgid="6068210738233985748">"మ్యాప్స్"</string>
<string name="browse" msgid="6993590095938149861">"బ్రౌజర్"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"నిల్వ ఖాళీ అయిపోతోంది"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"కొన్ని సిస్టమ్ కార్యాచరణలు పని చేయకపోవచ్చు"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"సిస్టమ్ కోసం తగినంత నిల్వ లేదు. మీకు 250MB ఖాళీ స్థలం ఉందని నిర్ధారించుకుని, పునఃప్రారంభించండి."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"రద్దు చేయి"</string>
<string name="yes" msgid="5362982303337969312">"సరే"</string>
<string name="no" msgid="5141531044935541497">"రద్దు చేయి"</string>
+ <string name="close" msgid="2318214661230355730">"మూసివేయండి"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"గమనిక"</string>
<string name="loading" msgid="7933681260296021180">"లోడ్ చేస్తోంది…"</string>
<string name="capital_on" msgid="1544682755514494298">"ఆన్లో ఉంది"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"ప్రమాణం"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ఎల్లప్పుడూ చూపు"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"సిస్టమ్ సెట్టింగ్లు > అనువర్తనాలు > డౌన్లోడ్ చేసినవిలో దీన్ని పునఃప్రారంభించండి."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"యాప్ ప్రతిస్పందించలేదు"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> చాలా ఎక్కువ మెమరీని ఉపయోగించుకోవచ్చు."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రస్తుత ప్రదర్శన పరిమాణ సెట్టింగ్కు మద్దతు ఇవ్వదు, దీని వలన ఊహించని సమస్యలు తలెత్తవచ్చు."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ఎల్లప్పుడూ చూపు"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> యాప్ (<xliff:g id="PROCESS">%2$s</xliff:g> ప్రాసెస్) అది స్వయంగా అమలు చేసే ఖచ్చితమైన మోడ్ విధానాన్ని ఉల్లంఘించింది."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"టీవీ"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ఫోన్"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"డాక్ స్పీకర్లు"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"హెడ్ఫోన్లు"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"సిస్టమ్"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"బ్లూటూత్ ఆడియో"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"వైర్లెస్ డిస్ప్లే"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 8b2db46..310bd95 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"โทรศัพท์"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"เบราว์เซอร์"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"พื้นที่จัดเก็บเหลือน้อย"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"บางฟังก์ชันระบบอาจไม่ทำงาน"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"พื้นที่เก็บข้อมูลไม่เพียงพอสำหรับระบบ โปรดตรวจสอบว่าคุณมีพื้นที่ว่าง 250 MB แล้วรีสตาร์ท"</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"ยกเลิก"</string>
<string name="yes" msgid="5362982303337969312">"ตกลง"</string>
<string name="no" msgid="5141531044935541497">"ยกเลิก"</string>
+ <string name="close" msgid="2318214661230355730">"ปิด"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"โปรดทราบ"</string>
<string name="loading" msgid="7933681260296021180">"กำลังโหลด..."</string>
<string name="capital_on" msgid="1544682755514494298">"เปิด"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"สเกล"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"แสดงเสมอ"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"เปิดใช้งานอีกครั้งในการตั้งค่าระบบ > แอปพลิเคชัน > ดาวน์โหลด"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"แอปไม่ตอบสนอง"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> อาจใช้หน่วยความจำมากเกินไป"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่สนับสนุนการตั้งค่าขนาดการแสดงผลปัจจุบันและอาจแสดงผลผิดปกติ"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"แสดงเสมอ"</string>
<string name="smv_application" msgid="3307209192155442829">"แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> (กระบวนการ <xliff:g id="PROCESS">%2$s</xliff:g>) ละเมิดนโยบาย StrictMode ที่บังคับใช้ด้วยตัวเอง"</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ทีวี"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"โทรศัพท์"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ลำโพงแท่นชาร์จ"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"หูฟัง"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"ระบบ"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"เสียงบลูทูธ"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"การแสดงผลแบบไร้สาย"</string>
@@ -1634,7 +1639,7 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"อัปเดตโดยผู้ดูแลระบบ"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"ลบโดยผู้ดูแลระบบ"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"เพื่อช่วยยืดอายุการใช้งานแบตเตอรี่ โหมดประหยัดแบตเตอรี่จะลดการทำงานของอุปกรณ์และจำกัดการสั่น บริการตำแหน่ง และข้อมูลแบ็กกราวด์ส่วนใหญ่ สำหรับอีเมล การรับส่งข้อความ และแอปอื่นๆ ที่ใช้การซิงค์จะไม่อัปเดตหากคุณไม่เปิดขึ้นมา\n\nโหมดประหยัดแบตเตอรี่จะปิดโดยอัตโนมัติขณะชาร์จอุปกรณ์"</string>
- <string name="data_saver_description" msgid="6015391409098303235">"เพื่อช่วยลดปริมาณการใช้อินเทอร์เน็ต โปรแกรมประหยัดอินเทอร์เน็ตจะช่วยป้องกันไม่ให้แอปบางส่วนส่งหรือรับข้อมูลเครือข่ายมือถือในพื้นหลัง แอปที่คุณกำลังใช้งานสามารถเข้าถึงข้อมูลเครือข่ายมือถือได้ แต่อาจไม่บ่อยเท่าเดิม ตัวอย่างเช่น ภาพต่างๆ จะไม่แสดงจนกว่าคุณจะแตะที่ภาพเหล่านั้น"</string>
+ <string name="data_saver_description" msgid="6015391409098303235">"เพื่อช่วยลดปริมาณการใช้อินเทอร์เน็ต โปรแกรมประหยัดอินเทอร์เน็ตจะช่วยป้องกันไม่ให้บางแอปส่งหรือรับข้อมูลเครือข่ายมือถือในการทำงานเบื้องหลัง แอปที่คุณกำลังใช้งานสามารถเข้าถึงข้อมูลเครือข่ายมือถือได้ แต่อาจไม่บ่อยเท่าเดิม ตัวอย่างเช่น ภาพต่างๆ จะไม่แสดงจนกว่าคุณจะแตะที่ภาพเหล่านั้น"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"เปิดการประหยัดอินเทอร์เน็ตไหม"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"เปิด"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 2e047c2..50d09a0 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telepono"</string>
<string name="map" msgid="6068210738233985748">"Mga Mapa"</string>
<string name="browse" msgid="6993590095938149861">"Browser"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nauubusan na ang puwang ng storage"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Maaaring hindi gumana nang tama ang ilang paggana ng system"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Walang sapat na storage para sa system. Tiyaking mayroon kang 250MB na libreng espasyo at i-restart."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Kanselahin"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Kanselahin"</string>
+ <string name="close" msgid="2318214661230355730">"ISARA"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Bigyang pansin"</string>
<string name="loading" msgid="7933681260296021180">"Naglo-load…"</string>
<string name="capital_on" msgid="1544682755514494298">"I-ON"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Sukat"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Palaging ipakita"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Muling paganahin ito sa mga setting ng System > Apps > Na-download."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Hindi tumutugon ang app"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Maaaring gumagamit ang <xliff:g id="APP_NAME">%1$s</xliff:g> ng masyadong maraming memory."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Hindi sinusuportahan ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang kasalukuyang setting ng laki ng Display at maaaring may mangyaring hindi inaasahan."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Palaging ipakita"</string>
<string name="smv_application" msgid="3307209192155442829">"Ang app na <xliff:g id="APPLICATION">%1$s</xliff:g> (prosesong <xliff:g id="PROCESS">%2$s</xliff:g>) ay lumabag sa sarili nitong ipinapatupad na patakarang StrictMode."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telepono"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Mga speaker ng dock"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Mga Headphone"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio sa Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 852471c..9bead0c 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Haritalar"</string>
<string name="browse" msgid="6993590095938149861">"Tarayıcı"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Depolama alanı bitiyor"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bazı sistem işlevleri çalışmayabilir"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistem için yeterli depolama alanı yok. 250 MB boş alanınızın bulunduğundan emin olun ve yeniden başlatın."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"İptal"</string>
<string name="yes" msgid="5362982303337969312">"Tamam"</string>
<string name="no" msgid="5141531044935541497">"İptal"</string>
+ <string name="close" msgid="2318214661230355730">"KAPAT"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Dikkat"</string>
<string name="loading" msgid="7933681260296021180">"Yükleniyor..."</string>
<string name="capital_on" msgid="1544682755514494298">"AÇIK"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Ölçek"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Her zaman göster"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bunu Sistem ayarları > Uygulamalar > İndirilenler bölümünden yeniden etkinleştirin."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Uygulama yanıt vermiyor"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> çok fazla bellek kullanıyor olabilir."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> geçerli Ekran boyutu ayarını desteklemiyor ve beklenmedik bir şekilde davranabilir."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Her zaman göster"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işlemi) kendiliğinden uyguladığı StrictMode politikasını ihlal etti."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Yuva hoparlörleri"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Kulaklıklar"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ses"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Kablosuz ekran"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 7d98b78..cb2f5b4 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1020,6 +1020,10 @@
<string name="dial" msgid="4204975095406423102">"Телефонувати"</string>
<string name="map" msgid="6068210738233985748">"Карти"</string>
<string name="browse" msgid="6993590095938149861">"Веб-переглядач"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Закінчується пам’ять"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Деякі системні функції можуть не працювати"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Недостатньо місця для системи. Переконайтесь, що на пристрої є 250 МБ вільного місця, і повторіть спробу."</string>
@@ -1029,6 +1033,7 @@
<string name="cancel" msgid="6442560571259935130">"Скасувати"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Скасувати"</string>
+ <string name="close" msgid="2318214661230355730">"ЗАКРИТИ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Увага"</string>
<string name="loading" msgid="7933681260296021180">"Завантаження..."</string>
<string name="capital_on" msgid="1544682755514494298">"УВІМК"</string>
@@ -1085,6 +1090,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Масштаб"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Завжди показувати"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Знову ввімкнути це в меню Налаштування системи > Програми > Завантажені."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Додаток не відповідає"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"Можливо, додаток <xliff:g id="APP_NAME">%1$s</xliff:g> використовує забагато пам’яті."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує поточне налаштування розміру екрана та може працювати неналежним чином."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Завжди показувати"</string>
<string name="smv_application" msgid="3307209192155442829">"Програма <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) порушила свою самозастосовну політику StrictMode."</string>
@@ -1467,11 +1474,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевізор"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Телефон"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Динаміки док-станції"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Навушники"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Аудіо Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Бездротовий екран"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 5198bb2..ab69fc3 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"فون کریں"</string>
<string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"براؤزر"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"اسٹوریج کی جگہ ختم ہو رہی ہے"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"ممکن ہے سسٹم کے کچھ فنکشنز کام نہ کریں"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"سسٹم کیلئے کافی اسٹوریج نہیں ہے۔ اس بات کو یقینی بنائیں کہ آپ کے پاس 250MB خالی جگہ ہے اور دوبارہ شروع کریں۔"</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"منسوخ کریں"</string>
<string name="yes" msgid="5362982303337969312">"ٹھیک ہے"</string>
<string name="no" msgid="5141531044935541497">"منسوخ کریں"</string>
+ <string name="close" msgid="2318214661230355730">"بند کریں"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"توجہ دیں"</string>
<string name="loading" msgid="7933681260296021180">"لوڈ ہو رہا ہے…"</string>
<string name="capital_on" msgid="1544682755514494298">"آن"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"پیمانہ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"ہمیشہ دکھائیں"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"سسٹم ترتیبات > ایپس > ڈاؤن لوڈ کردہ میں اسے دوبارہ فعال کریں۔"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"ایپ جواب نہیں دے رہی ہے"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> کافی زیادہ میموری استعمال کر سکتی ہے۔"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> میں موجودہ ڈسپلے سائز ترتیبات کی معاونت نہیں ہے اور ہو سکتا ہے غیر متوقع طریقے سے کام کرے۔"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"ہمیشہ دکھائیں"</string>
<string name="smv_application" msgid="3307209192155442829">"ایپ <xliff:g id="APPLICATION">%1$s</xliff:g> (کارروائی <xliff:g id="PROCESS">%2$s</xliff:g>) نے خود نافذ کی گئی StrictMode پالیسی کی خلاف ورزی کی ہے۔"</string>
@@ -1303,9 +1310,9 @@
<string name="submit" msgid="1602335572089911941">"جمع کرائیں"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"کار وضع فعال ہے"</string>
<string name="car_mode_disable_notification_message" msgid="6301524980144350051">"کار موڈ سے خارج ہونے کیلئے تھپتھپائیں۔"</string>
- <string name="tethered_notification_title" msgid="3146694234398202601">"ٹیتھرنگ یا ہاٹ اسپاٹ فعال"</string>
+ <string name="tethered_notification_title" msgid="3146694234398202601">"ٹیدرنگ یا ہاٹ اسپاٹ فعال"</string>
<string name="tethered_notification_message" msgid="2113628520792055377">"سیٹ اپ کرنے کیلئے تھپتھپائیں۔"</string>
- <string name="disable_tether_notification_title" msgid="7526977944111313195">"ربط بنانا غیر فعال ہے"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"ٹیدرنگ غیر فعال ہے"</string>
<string name="disable_tether_notification_message" msgid="2913366428516852495">"تفصیلات کے لئے اپنے منتظم سے رابطہ کریں"</string>
<string name="back_button_label" msgid="2300470004503343439">"واپس جائیں"</string>
<string name="next_button_label" msgid="1080555104677992408">"اگلا"</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"فون"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ڈاک اسپیکرز"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"ہیڈ فونز"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"سسٹم"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوٹوتھ آڈیو"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"وائرلیس ڈسپلے"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index bc30741..f402e26 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Telefon"</string>
<string name="map" msgid="6068210738233985748">"Xaritalar"</string>
<string name="browse" msgid="6993590095938149861">"Brauzer"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Xotirada bo‘sh joy tugamoqda"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Ba‘zi tizim funksiyalari ishlamasligi mumkin"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Tizim uchun xotirada joy yetarli emas. Avval 250 megabayt joy bo‘shatib, keyin qurilmani o‘chirib yoqing."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Bekor qilish"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Bekor qilish"</string>
+ <string name="close" msgid="2318214661230355730">"YOPISH"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Diqqat"</string>
<string name="loading" msgid="7933681260296021180">"Yuklanmoqda…"</string>
<string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Masshtab"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Doimo ko‘rsatish"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Uni Tizim sozlamalari > Ilovalar > Yuklab olingan menyusidan qayta yoqing."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Ilova javob bermayapti"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ortiqcha xotira ishlatmoqda."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” ilovasi joriy ekran o‘lchami sozlamalariga mos kelmasligi va noto‘g‘ri ishlashi mumkin."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Har doim ko‘rsatilsin"</string>
<string name="smv_application" msgid="3307209192155442829">"“<xliff:g id="APPLICATION">%1$s</xliff:g>” ilovasi (jarayaon: <xliff:g id="PROCESS">%2$s</xliff:g>) o‘zining StrictMode qoidasini buzdi."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Taglik karnaylar"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Quloq karnaychalari"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Tizim"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Ovozni Bluetooth orqali chiqarish"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Simsiz monitor"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ea2c3af..9a057cf 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Điện thoại"</string>
<string name="map" msgid="6068210738233985748">"Bản đồ"</string>
<string name="browse" msgid="6993590095938149861">"Trình duyệt"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Sắp hết dung lượng lưu trữ"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Một số chức năng hệ thống có thể không hoạt động"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Không đủ bộ nhớ cho hệ thống. Đảm bảo bạn có 250 MB dung lượng trống và khởi động lại."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Hủy"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Hủy"</string>
+ <string name="close" msgid="2318214661230355730">"ĐÓNG"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Chú ý"</string>
<string name="loading" msgid="7933681260296021180">"Đang tải…"</string>
<string name="capital_on" msgid="1544682755514494298">"BẬT"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Tỷ lệ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Luôn hiển thị"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bật lại chế độ này trong cài đặt Hệ thống > Ứng dụng > Đã tải xuống."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"Ứng dụng không phản hồi"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> có thể đang sử dụng quá nhiều bộ nhớ."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ cài đặt kích thước Màn hình hiện tại và có thể hoạt động không như mong đợi."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Luôn hiển thị"</string>
<string name="smv_application" msgid="3307209192155442829">"Ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> (quá trình <xliff:g id="PROCESS">%2$s</xliff:g>) đã vi phạm chính sách StrictMode tự thi hành của mình."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Điện thoại"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Loa đế"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Tai nghe"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Hệ thống"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Âm thanh Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Hiển thị không dây"</string>
@@ -1633,7 +1638,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Do quản trị viên của bạn cài đặt"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Do quản trị viên của bạn cập nhật"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Do quản trị viên của bạn xóa"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Để giúp tăng tuổi thọ pin, trình tiết kiệm pin sẽ giảm hiệu suất thiết bị của bạn và hạn chế rung, dịch vụ vị trí và hầu hết dữ liệu nền. Email, nhắn tin và các ứng dụng khác dựa trên đồng bộ hóa có thể không cập nhật nếu bạn không mở chúng.\n\nTrình tiết kiệm pin tự động tắt khi thiết bị của bạn đang sạc."</string>
+ <string name="battery_saver_description" msgid="1960431123816253034">"Để giúp tăng thời lượng pin, trình tiết kiệm pin sẽ giảm hiệu suất thiết bị và hạn chế rung, dịch vụ vị trí và hầu hết dữ liệu nền. Ứng dụng email, nhắn tin và các ứng dụng khác dựa trên đồng bộ hóa có thể không cập nhật nếu bạn không mở.\n\nTrình tiết kiệm pin tự động tắt khi thiết bị của bạn đang sạc."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Để giúp giảm mức sử dụng dữ liệu, Trình tiết kiệm dữ liệu chặn một số ứng dụng gửi hoặc nhận dữ liệu trong nền. Ứng dụng mà bạn hiện sử dụng có thể truy cập dữ liệu nhưng có thể thực hiện việc đó ít thường xuyên hơn. Ví dụ: hình ảnh sẽ không hiển thị cho đến khi bạn nhấn vào hình ảnh đó."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Bật Trình tiết kiệm dữ liệu?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Bật"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index f66faf6..962b05f 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"电话"</string>
<string name="map" msgid="6068210738233985748">"地图"</string>
<string name="browse" msgid="6993590095938149861">"浏览器"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"存储空间不足"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"某些系统功能可能无法正常使用"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"系统存储空间不足。请确保您有250MB的可用空间,然后重新启动。"</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"取消"</string>
<string name="yes" msgid="5362982303337969312">"确定"</string>
<string name="no" msgid="5141531044935541497">"取消"</string>
+ <string name="close" msgid="2318214661230355730">"关闭"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"注意"</string>
<string name="loading" msgid="7933681260296021180">"正在加载..."</string>
<string name="capital_on" msgid="1544682755514494298">"开启"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"缩放"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"始终显示"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"在“系统设置”>“应用”>“已下载”中重新启用此模式。"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"应用没有响应"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g>可能占用了过多内存。"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持当前的显示大小设置,因此可能无法正常显示。"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"一律显示"</string>
<string name="smv_application" msgid="3307209192155442829">"“<xliff:g id="APPLICATION">%1$s</xliff:g>”应用(<xliff:g id="PROCESS">%2$s</xliff:g> 进程)违反了自我强制执行的严格模式 (StrictMode) 政策。"</string>
@@ -1137,7 +1144,7 @@
<string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"点按即可查看相关设置"</string>
<string name="accept" msgid="1645267259272829559">"接受"</string>
<string name="decline" msgid="2112225451706137894">"拒绝"</string>
- <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"邀请已发送"</string>
+ <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"已发出邀请"</string>
<string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"连接邀请"</string>
<string name="wifi_p2p_from_message" msgid="570389174731951769">"发件人:"</string>
<string name="wifi_p2p_to_message" msgid="248968974522044099">"收件人:"</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"电视"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"手机"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"基座扬声器"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"耳机"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"系统"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"蓝牙音频"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"无线显示"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 52df581..4b5a4ec 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"撥打電話"</string>
<string name="map" msgid="6068210738233985748">"地圖"</string>
<string name="browse" msgid="6993590095938149861">"瀏覽器"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"儲存空間即將用盡"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"部分系統功能可能無法運作"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"系統儲存空間不足。請確認裝置有 250 MB 的可用空間,然後重新啟動。"</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"取消"</string>
<string name="yes" msgid="5362982303337969312">"確定"</string>
<string name="no" msgid="5141531044935541497">"取消"</string>
+ <string name="close" msgid="2318214661230355730">"關閉"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"注意"</string>
<string name="loading" msgid="7933681260296021180">"正在載入..."</string>
<string name="capital_on" msgid="1544682755514494298">"開啟"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"比例"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"永遠顯示"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"前往 [系統設定] > [應用程式] > [下載] 重新啟用這個模式。"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"應用程式沒有回應"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」可能佔用大量記憶體。"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援目前的「螢幕」尺寸設定,畫面可能無法如預期顯示。"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"永遠顯示"</string>
<string name="smv_application" msgid="3307209192155442829">"應用程式 <xliff:g id="APPLICATION">%1$s</xliff:g> (處理程序 <xliff:g id="PROCESS">%2$s</xliff:g>) 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"電視"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"手機"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"插座喇叭"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"耳機"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"系統"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音頻"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"無線螢幕分享"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index e7fa2f1..5166b87 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"電話"</string>
<string name="map" msgid="6068210738233985748">"地圖"</string>
<string name="browse" msgid="6993590095938149861">"瀏覽器"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"儲存空間即將用盡"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"部分系統功能可能無法運作"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"系統儲存空間不足。請確定你已釋出 250MB 的可用空間,然後重新啟動。"</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"取消"</string>
<string name="yes" msgid="5362982303337969312">"確定"</string>
<string name="no" msgid="5141531044935541497">"取消"</string>
+ <string name="close" msgid="2318214661230355730">"關閉"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"注意"</string>
<string name="loading" msgid="7933681260296021180">"載入中…"</string>
<string name="capital_on" msgid="1544682755514494298">"開啟"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"比例"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"一律顯示"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"前往 [系統設定] > [應用程式] > [下載] 重新啟用這個模式。"</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"應用程式沒有回應"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」可能使用了過多記憶體。"</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援目前的顯示大小設定,可能會發生非預期的行為。"</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"一律顯示"</string>
<string name="smv_application" msgid="3307209192155442829">"應用程式 <xliff:g id="APPLICATION">%1$s</xliff:g> (處理程序 <xliff:g id="PROCESS">%2$s</xliff:g>) 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"電視"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"手機"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"座架喇叭"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"耳機"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"系統"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音訊"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"無線螢幕分享"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 0c98667..b7a6ae4 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -980,6 +980,10 @@
<string name="dial" msgid="4204975095406423102">"Ifoni"</string>
<string name="map" msgid="6068210738233985748">"Amamephu"</string>
<string name="browse" msgid="6993590095938149861">"Isiphequluli"</string>
+ <!-- no translation found for sms (8250353543787396737) -->
+ <skip />
+ <!-- no translation found for add_contact (7990645816259405444) -->
+ <skip />
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Isikhala sokulondoloza siyaphela"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Eminye imisebenzi yohlelo ingahle ingasebenzi"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Akusona isitoreji esanele sesistimu. Qiniseka ukuthi unesikhala esikhululekile esingu-250MB uphinde uqalise kabusha."</string>
@@ -989,6 +993,7 @@
<string name="cancel" msgid="6442560571259935130">"Khansela"</string>
<string name="yes" msgid="5362982303337969312">"KULUNGILE"</string>
<string name="no" msgid="5141531044935541497">"Khansela"</string>
+ <string name="close" msgid="2318214661230355730">"VALA"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Qaphela"</string>
<string name="loading" msgid="7933681260296021180">"Iyalayisha…"</string>
<string name="capital_on" msgid="1544682755514494298">"VULIWE"</string>
@@ -1045,6 +1050,8 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Isilinganisi"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Bonisa njalo"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Yenza kuphinde kusebenze kuzilungiselelo Zesistimue > Izinhlelo zokusebenza > Okulayishiwe."</string>
+ <string name="top_app_killed_title" msgid="6814231368167994497">"I-App ayiphenduli"</string>
+ <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ingasebenzisa imemori eningi."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli isilungiselelo sosayizi sokubonisa samanje futhi ingasebenza ngokungalindelekile."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Bonisa njalo"</string>
<string name="smv_application" msgid="3307209192155442829">"Inqubo <xliff:g id="APPLICATION">%1$s</xliff:g> (yohlelo <xliff:g id="PROCESS">%2$s</xliff:g>) iphule inqubomgomo oziphoqelela yona Yemodi Ebukhali."</string>
@@ -1421,11 +1428,9 @@
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"I-TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Ifoni"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Izipikha ze-Dock"</string>
- <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
- <skip />
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Ama-headphone"</string>
- <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
- <skip />
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"I-USB"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Isistimu"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Umsindo we-Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Ukubonisa okungenazintambo"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 61b4123..11cdb76 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2056,11 +2056,11 @@
Corresponds to {@link android.view.Window#setNavigationBarColor(int)}. -->
<attr name="navigationBarColor" format="color" />
- <!-- @hide
- Shows 1dp line of the specified color between the navigation bar and the app content.
+ <!-- Shows a thin line of the specified color between the navigation bar and the app
+ content.
<p>For this to take effect, the window must be drawing the system bar backgrounds with
{@link android.R.attr#windowDrawsSystemBarBackgrounds} and the navigation bar must not
- have been requested to be translucent with
+ have been requested to be translucent with
{@link android.R.attr#windowTranslucentNavigation}. -->
<attr name="navigationBarDividerColor" format="color" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 07a1109..6bf5c63 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1127,6 +1127,11 @@
<!-- Is the lock-screen disabled for new users by default -->
<bool name="config_disableLockscreenByDefault">false</bool>
+ <!-- If true, enables verification of the lockscreen credential in the factory reset protection
+ flow. This should be true if gatekeeper / weaver credentials can still be checked after a
+ factory reset. -->
+ <bool name="config_enableCredentialFactoryResetProtection">true</bool>
+
<!-- Control the behavior when the user long presses the home button.
0 - Nothing
1 - Launch all apps intent
@@ -3035,7 +3040,7 @@
<bool name="config_handleVolumeKeysInWindowManager">false</bool>
<!-- Volume level of in-call notification tone playback [0..1] -->
- <item name="config_inCallNotificationVolume" format="float" type="dimen">.25</item>
+ <item name="config_inCallNotificationVolume" format="float" type="dimen">.10</item>
<!-- URI for in call notification sound -->
<string translatable="false" name="config_inCallNotificationSound">/system/media/audio/ui/InCallNotification.ogg</string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 9b2f185..e9d574a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2846,6 +2846,8 @@
<public name="showWhenLocked"/>
<public name="turnScreenOn"/>
<public name="classLoader" />
+ <public name="windowLightNavigationBar" />
+ <public name="navigationBarDividerColor" />
</public-group>
<public-group type="style" first-id="0x010302e0">
@@ -2875,10 +2877,6 @@
=============================================================== -->
<eat-comment />
- <public-group type="attr" first-id="0x0101056c">
- <public name="windowLightNavigationBar" />
- </public-group>
-
<!-- ===============================================================
DO NOT ADD UN-GROUPED ITEMS HERE
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7416113..6807e13 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2685,6 +2685,12 @@
<!-- Label for item in the text selection menu to trigger a Browser app [CHAR LIMIT=20] -->
<string name="browse">Browser</string>
+ <!-- Label for item in the text selection menu to trigger an SMS app [CHAR LIMIT=20] -->
+ <string name="sms">SMS</string>
+
+ <!-- Label for item in the text selection menu to trigger adding a contact [CHAR LIMIT=20] -->
+ <string name="add_contact">Contact</string>
+
<!-- If the device is getting low on internal storage, a notification is shown to the user. This is the title of that notification. -->
<string name="low_internal_storage_view_title">Storage space running out</string>
<!-- If the device is getting low on internal storage, a notification is shown to the user. This is the message of that notification. -->
@@ -2709,6 +2715,8 @@
<string name="yes">OK</string>
<!-- Preference framework strings. -->
<string name="no">Cancel</string>
+ <!-- Preference framework strings. -->
+ <string name="close">CLOSE</string>
<!-- This is the generic "attention" string to be used in attention dialogs. Typically
combined with setIconAttribute(android.R.attr.alertDialogIcon)
(or setIcon(android.R.drawable.ic_dialog_alert) on legacy versions of the platform) -->
@@ -2841,6 +2849,11 @@
<!-- [CHAR LIMIT=200] Compat mode dialog: hint to re-enable compat mode dialog. -->
<string name="screen_compat_mode_hint">Re-enable this in System settings > Apps > Downloaded.</string>
+ <!-- Text of the alert that is displayed when a top application is killed by lmk. -->
+ <string name="top_app_killed_title">App isn\'t responding</string>
+ <!-- Top app killed by lmk dialog message. -->
+ <string name="top_app_killed_message"><xliff:g id="app_name">%1$s</xliff:g> may be using too much memory.</string>
+
<!-- [CHAR LIMIT=200] Unsupported display size dialog: message. Refers to "Display size" setting. -->
<string name="unsupported_display_size_message"><xliff:g id="app_name">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly.</string>
<!-- [CHAR LIMIT=50] Unsupported display size dialog: check box label. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1877d42..0732f0d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -516,6 +516,8 @@
<java-symbol type="string" name="dial" />
<java-symbol type="string" name="map" />
<java-symbol type="string" name="browse" />
+ <java-symbol type="string" name="sms" />
+ <java-symbol type="string" name="add_contact" />
<java-symbol type="string" name="textSelectionCABTitle" />
<java-symbol type="string" name="BaMmi" />
<java-symbol type="string" name="CLIRDefaultOffNextCallOff" />
@@ -1893,6 +1895,9 @@
<java-symbol type="string" name="anr_application_process" />
<java-symbol type="string" name="anr_process" />
<java-symbol type="string" name="anr_title" />
+ <java-symbol type="string" name="top_app_killed_title" />
+ <java-symbol type="string" name="top_app_killed_message" />
+ <java-symbol type="string" name="close" />
<java-symbol type="string" name="car_mode_disable_notification_message" />
<java-symbol type="string" name="car_mode_disable_notification_title" />
<java-symbol type="string" name="chooser_wallpaper" />
@@ -3027,6 +3032,8 @@
<java-symbol type="string" name="foreground_service_tap_for_details" />
<java-symbol type="string" name="foreground_service_multiple_separator" />
+ <java-symbol type="bool" name="config_enableCredentialFactoryResetProtection" />
+
<!-- ETWS primary messages -->
<java-symbol type="string" name="etws_primary_default_message_earthquake" />
<java-symbol type="string" name="etws_primary_default_message_tsunami" />
diff --git a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf
new file mode 100644
index 0000000..1bad6fe
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf
Binary files differ
diff --git a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx
new file mode 100644
index 0000000..0cf0f79
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="0em"/>
+ <GlyphID id="2" name="1em"/>
+ <GlyphID id="3" name="3em"/>
+ <GlyphID id="4" name="5em"/>
+ <GlyphID id="5" name="7em"/>
+ <GlyphID id="6" name="10em"/>
+ <GlyphID id="7" name="50em"/>
+ <GlyphID id="8" name="100em"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="100"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="50" lsb="0"/>
+ <mtx name="0em" width="0" lsb="0"/>
+ <mtx name="1em" width="100" lsb="0"/>
+ <mtx name="3em" width="300" lsb="0"/>
+ <mtx name="5em" width="500" lsb="0"/>
+ <mtx name="7em" width="700" lsb="0"/>
+ <mtx name="10em" width="1000" lsb="0"/>
+ <mtx name="50em" width="5000" lsb="0"/>
+ <mtx name="100em" width="10000" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_12 format="12" reserved="0" length="6" nGroups="1" platformID="3" platEncID="10" language="0">
+ <map code="0x0020" name="10em" />
+ <map code="0x002e" name="10em" /> <!-- . -->
+ <map code="0x0043" name="100em" /> <!-- C -->
+ <map code="0x0049" name="1em" /> <!-- I -->
+ <map code="0x004c" name="50em" /> <!-- L -->
+ <map code="0x0056" name="5em" /> <!-- V -->
+ <map code="0x0058" name="10em" /> <!-- X -->
+ <map code="0x005f" name="0em" /> <!-- _ -->
+ <map code="0xfffd" name="7em" /> <!-- REPLACEMENT CHAR -->
+ <map code="0x10331" name="10em" />
+ </cmap_format_12>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="0em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="5em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="7em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="10em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="50em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="100em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Font for StaticLayoutLineBreakingTest
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Font for StaticLayoutLineBreakingTest
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/core/tests/coretests/src/android/content/pm/AppCacheTest.java b/core/tests/coretests/src/android/content/pm/AppCacheTest.java
deleted file mode 100644
index a5fdef6..0000000
--- a/core/tests/coretests/src/android/content/pm/AppCacheTest.java
+++ /dev/null
@@ -1,725 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.StatFs;
-import android.os.UserHandle;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.filters.Suppress;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class AppCacheTest extends AndroidTestCase {
- private static final boolean localLOGV = false;
- public static final String TAG="AppCacheTest";
- public final long MAX_WAIT_TIME=60*1000;
- public final long WAIT_TIME_INCR=10*1000;
- private static final long THRESHOLD=5;
- private static final long ACTUAL_THRESHOLD=10;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- if(localLOGV) Log.i(TAG, "Cleaning up cache directory first");
- cleanUpCacheDirectory();
- }
-
- void cleanUpDirectory(File pDir, String dirName) {
- File testDir = new File(pDir, dirName);
- if(!testDir.exists()) {
- return;
- }
- String fList[] = testDir.list();
- for(int i = 0; i < fList.length; i++) {
- File file = new File(testDir, fList[i]);
- if(file.isDirectory()) {
- cleanUpDirectory(testDir, fList[i]);
- } else {
- file.delete();
- }
- }
- testDir.delete();
- }
-
- void cleanUpCacheDirectory() {
- File testDir = mContext.getCacheDir();
- if(!testDir.exists()) {
- return;
- }
-
- String fList[] = testDir.list();
- if(fList == null) {
- testDir.delete();
- return;
- }
- for(int i = 0; i < fList.length; i++) {
- File file = new File(testDir, fList[i]);
- if(file.isDirectory()) {
- cleanUpDirectory(testDir, fList[i]);
- } else {
- file.delete();
- }
- }
- }
-
- @SmallTest
- public void testDeleteAllCacheFiles() {
- String testName="testDeleteAllCacheFiles";
- cleanUpCacheDirectory();
- }
-
- void failStr(String errMsg) {
- Log.w(TAG, "errMsg="+errMsg);
- fail(errMsg);
- }
-
- void failStr(Exception e) {
- Log.w(TAG, "e.getMessage="+e.getMessage());
- Log.w(TAG, "e="+e);
- }
-
- long getFreeStorageBlks(StatFs st) {
- st.restat("/data");
- return st.getFreeBlocks();
- }
-
- long getFreeStorageSize(StatFs st) {
- st.restat("/data");
- return (long) st.getFreeBlocks() * (long) st.getBlockSize();
- }
-
- @LargeTest
- @Suppress // Failing.
- public void testFreeApplicationCacheAllFiles() throws Exception {
- boolean TRACKING = true;
- StatFs st = new StatFs("/data");
- long blks1 = getFreeStorageBlks(st);
- long availableMem = getFreeStorageSize(st);
- File cacheDir = mContext.getCacheDir();
- assertNotNull(cacheDir);
- createTestFiles1(cacheDir, "testtmpdir", 5);
- long blks2 = getFreeStorageBlks(st);
- if(localLOGV || TRACKING) Log.i(TAG, "blk1="+blks1+", blks2="+blks2);
- //this should free up the test files that were created earlier
- if (!invokePMFreeApplicationCache(availableMem)) {
- fail("Could not successfully invoke PackageManager free app cache API");
- }
- long blks3 = getFreeStorageBlks(st);
- if(localLOGV || TRACKING) Log.i(TAG, "blks3="+blks3);
- verifyTestFiles1(cacheDir, "testtmpdir", 5);
- }
-
- public void testFreeApplicationCacheSomeFiles() throws Exception {
- StatFs st = new StatFs("/data");
- long blks1 = getFreeStorageBlks(st);
- File cacheDir = mContext.getCacheDir();
- assertNotNull(cacheDir);
- createTestFiles1(cacheDir, "testtmpdir", 5);
- long blks2 = getFreeStorageBlks(st);
- Log.i(TAG, "blk1="+blks1+", blks2="+blks2);
- long diff = (blks1-blks2-2);
- if (!invokePMFreeApplicationCache(diff * st.getBlockSize())) {
- fail("Could not successfully invoke PackageManager free app cache API");
- }
- long blks3 = getFreeStorageBlks(st);
- //blks3 should be greater than blks2 and less than blks1
- if(!((blks3 <= blks1) && (blks3 >= blks2))) {
- failStr("Expected "+(blks1-blks2)+" number of blocks to be freed but freed only "
- +(blks1-blks3));
- }
- }
-
- /**
- * This method opens an output file writes to it, opens the same file as an input
- * stream, reads the contents and verifies the data that was written earlier can be read
- */
- public void openOutFileInAppFilesDir(File pFile, String pFileOut) {
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(pFile);
- } catch (FileNotFoundException e1) {
- failStr("Error when opening file "+e1);
- return;
- }
- try {
- fos.write(pFileOut.getBytes());
- fos.close();
- } catch (FileNotFoundException e) {
- failStr(e.getMessage());
- } catch (IOException e) {
- failStr(e.getMessage());
- }
- int count = pFileOut.getBytes().length;
- byte[] buffer = new byte[count];
- try {
- FileInputStream fis = new FileInputStream(pFile);
- fis.read(buffer, 0, count);
- fis.close();
- } catch (FileNotFoundException e) {
- failStr("Failed when verifing output opening file "+e.getMessage());
- } catch (IOException e) {
- failStr("Failed when verifying output, reading from written file "+e);
- }
- String str = new String(buffer);
- assertEquals(str, pFileOut);
- }
-
- /*
- * This test case verifies that output written to a file
- * using Context.openFileOutput has executed successfully.
- * The operation is verified by invoking Context.openFileInput
- */
- @MediumTest
- public void testAppFilesCreateFile() {
- String fileName = "testFile1.txt";
- String fileOut = "abcdefghijklmnopqrstuvwxyz";
- Context con = super.getContext();
- try {
- FileOutputStream fos = con.openFileOutput(fileName, Context.MODE_PRIVATE);
- fos.close();
- } catch (FileNotFoundException e) {
- failStr(e);
- } catch (IOException e) {
- failStr(e);
- }
- }
-
- @SmallTest
- public void testAppCacheCreateFile() {
- String fileName = "testFile1.txt";
- String fileOut = "abcdefghijklmnopqrstuvwxyz";
- Context con = super.getContext();
- File file = new File(con.getCacheDir(), fileName);
- openOutFileInAppFilesDir(file, fileOut);
- cleanUpCacheDirectory();
- }
-
- @MediumTest
- public void testAppCreateCacheFiles() {
- File cacheDir = mContext.getCacheDir();
- String testDirName = "testtmp";
- File testTmpDir = new File(cacheDir, testDirName);
- testTmpDir.mkdir();
- int numDirs = 3;
- File fileArr[] = new File[numDirs];
- for(int i = 0; i < numDirs; i++) {
- fileArr[i] = new File(testTmpDir, "dir"+(i+1));
- fileArr[i].mkdir();
- }
- byte buffer[] = getBuffer();
- Log.i(TAG, "Size of bufer="+buffer.length);
- for(int i = 0; i < numDirs; i++) {
- for(int j = 1; j <= (i); j++) {
- File file1 = new File(fileArr[i], "testFile"+j+".txt");
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(file1);
- for(int k = 1; k < 10; k++) {
- fos.write(buffer);
- }
- Log.i(TAG, "wrote 10K bytes to "+file1);
- fos.close();
- } catch (FileNotFoundException e) {
- Log.i(TAG, "Excetion ="+e);
- fail("Error when creating outputstream "+e);
- } catch(IOException e) {
- Log.i(TAG, "Excetion ="+e);
- fail("Error when writing output "+e);
- }
- }
- }
- }
-
- byte[] getBuffer() {
- String sbuffer = "a";
- for(int i = 0; i < 10; i++) {
- sbuffer += sbuffer;
- }
- return sbuffer.getBytes();
- }
-
- long getFileNumBlocks(long fileSize, long blkSize) {
- long ret = fileSize/blkSize;
- if(ret*blkSize < fileSize) {
- ret++;
- }
- return ret;
- }
-
- //@LargeTest
- public void testAppCacheClear() {
- String dataDir="/data/data";
- StatFs st = new StatFs(dataDir);
- long blkSize = st.getBlockSize();
- long totBlks = st.getBlockCount();
- long availableBlks = st.getFreeBlocks();
- long thresholdBlks = (totBlks * THRESHOLD) / 100L;
- String testDirName = "testdir";
- //create directory in cache
- File testDir = new File(mContext.getCacheDir(), testDirName);
- testDir.mkdirs();
- byte[] buffer = getBuffer();
- int i = 1;
- if(localLOGV) Log.i(TAG, "availableBlks="+availableBlks+", thresholdBlks="+thresholdBlks);
- long createdFileBlks = 0;
- int imax = 300;
- while((availableBlks > thresholdBlks) &&(i < imax)) {
- File testFile = new File(testDir, "testFile"+i+".txt");
- if(localLOGV) Log.i(TAG, "Creating "+i+"th test file "+testFile);
- int jmax = i;
- i++;
- FileOutputStream fos;
- try {
- fos = new FileOutputStream(testFile);
- } catch (FileNotFoundException e) {
- Log.i(TAG, "Failed creating test file:"+testFile);
- continue;
- }
- boolean err = false;
- for(int j = 1; j <= jmax;j++) {
- try {
- fos.write(buffer);
- } catch (IOException e) {
- Log.i(TAG, "Failed to write to file:"+testFile);
- err = true;
- }
- }
- try {
- fos.close();
- } catch (IOException e) {
- Log.i(TAG, "Failed closing file:"+testFile);
- }
- if(err) {
- continue;
- }
- createdFileBlks += getFileNumBlocks(testFile.length(), blkSize);
- st.restat(dataDir);
- availableBlks = st.getFreeBlocks();
- }
- st.restat(dataDir);
- long availableBytes = st.getFreeBlocks()*blkSize;
- long shouldFree = (ACTUAL_THRESHOLD-THRESHOLD)*totBlks;
- //would have run out of memory
- //wait for some time and confirm cache is deleted
- try {
- Log.i(TAG, "Sleeping for 2 minutes...");
- Thread.sleep(2*60*1000);
- } catch (InterruptedException e) {
- fail("Exception when sleeping "+e);
- }
- boolean removedFlag = false;
- long existingFileBlks = 0;
- for(int k = 1; k <i; k++) {
- File testFile = new File(testDir, "testFile"+k+".txt");
- if(!testFile.exists()) {
- removedFlag = true;
- if(localLOGV) Log.i(TAG, testFile+" removed");
- } else {
- existingFileBlks += getFileNumBlocks(testFile.length(), blkSize);
- }
- }
- if(localLOGV) Log.i(TAG, "createdFileBlks="+createdFileBlks+
- ", existingFileBlks="+existingFileBlks);
- long fileSize = createdFileBlks-existingFileBlks;
- //verify fileSize number of bytes have been cleared from cache
- if(localLOGV) Log.i(TAG, "deletedFileBlks="+fileSize+" shouldFreeBlks="+shouldFree);
- if((fileSize > (shouldFree-blkSize) && (fileSize < (shouldFree+blkSize)))) {
- Log.i(TAG, "passed");
- }
- assertTrue("Files should have been removed", removedFlag);
- }
-
- //createTestFiles(new File(super.getContext().getCacheDir(), "testtmp", "dir", 3)
- void createTestFiles1(File cacheDir, String testFilePrefix, int numTestFiles) {
- byte buffer[] = getBuffer();
- for(int i = 0; i < numTestFiles; i++) {
- File file1 = new File(cacheDir, testFilePrefix+i+".txt");
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(file1);
- for(int k = 1; k < 10; k++) {
- fos.write(buffer);
- }
- fos.close();
- } catch (FileNotFoundException e) {
- Log.i(TAG, "Exception ="+e);
- fail("Error when creating outputstream "+e);
- } catch(IOException e) {
- Log.i(TAG, "Exception ="+e);
- fail("Error when writing output "+e);
- }
- try {
- //introduce sleep for 1 s to avoid common time stamps for files being created
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- fail("Exception when sleeping "+e);
- }
- }
- }
-
- void verifyTestFiles1(File cacheDir, String testFilePrefix, int numTestFiles) {
- List<String> files = new ArrayList<String>();
- for(int i = 0; i < numTestFiles; i++) {
- File file1 = new File(cacheDir, testFilePrefix+i+".txt");
- if(file1.exists()) {
- files.add(file1.getName());
- }
- }
- if (files.size() > 0) {
- fail("Files should have been deleted: "
- + Arrays.toString(files.toArray(new String[files.size()])));
- }
- }
-
- void createTestFiles2(File cacheDir, String rootTestDirName, String subDirPrefix, int numDirs, String testFilePrefix) {
- Context con = super.getContext();
- File testTmpDir = new File(cacheDir, rootTestDirName);
- testTmpDir.mkdir();
- File fileArr[] = new File[numDirs];
- for(int i = 0; i < numDirs; i++) {
- fileArr[i] = new File(testTmpDir, subDirPrefix+(i+1));
- fileArr[i].mkdir();
- }
- byte buffer[] = getBuffer();
- for(int i = 0; i < numDirs; i++) {
- for(int j = 1; j <= (i); j++) {
- File file1 = new File(fileArr[i], testFilePrefix+j+".txt");
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(file1);
- for(int k = 1; k < 10; k++) {
- fos.write(buffer);
- }
- fos.close();
- } catch (FileNotFoundException e) {
- Log.i(TAG, "Exception ="+e);
- fail("Error when creating outputstream "+e);
- } catch(IOException e) {
- Log.i(TAG, "Exception ="+e);
- fail("Error when writing output "+e);
- }
- try {
- //introduce sleep for 10 ms to avoid common time stamps for files being created
- Thread.sleep(10);
- } catch (InterruptedException e) {
- fail("Exception when sleeping "+e);
- }
- }
- }
- }
-
- class PackageDataObserver extends IPackageDataObserver.Stub {
- public boolean retValue = false;
- private boolean doneFlag = false;
- public void onRemoveCompleted(String packageName, boolean succeeded)
- throws RemoteException {
- synchronized(this) {
- retValue = succeeded;
- doneFlag = true;
- notifyAll();
- }
- }
- public boolean isDone() {
- return doneFlag;
- }
- }
-
- IPackageManager getPm() {
- return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
- }
-
- boolean invokePMDeleteAppCacheFiles() throws Exception {
- try {
- String packageName = mContext.getPackageName();
- PackageDataObserver observer = new PackageDataObserver();
- //wait on observer
- synchronized(observer) {
- getPm().deleteApplicationCacheFiles(packageName, observer);
- long waitTime = 0;
- while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) {
- observer.wait(WAIT_TIME_INCR);
- waitTime += WAIT_TIME_INCR;
- }
- if(!observer.isDone()) {
- throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted");
- }
- }
- return observer.retValue;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
- return false;
- } catch (InterruptedException e) {
- Log.w(TAG, "InterruptedException :"+e);
- return false;
- }
- }
-
- boolean invokePMFreeApplicationCache(long idealStorageSize) throws Exception {
- try {
- String packageName = mContext.getPackageName();
- PackageDataObserver observer = new PackageDataObserver();
- //wait on observer
- synchronized(observer) {
- getPm().freeStorageAndNotify(null, idealStorageSize, 0, observer);
- long waitTime = 0;
- while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) {
- observer.wait(WAIT_TIME_INCR);
- waitTime += WAIT_TIME_INCR;
- }
- if(!observer.isDone()) {
- throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted");
- }
- }
- return observer.retValue;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
- return false;
- } catch (InterruptedException e) {
- Log.w(TAG, "InterruptedException :"+e);
- return false;
- }
- }
-
- boolean invokePMFreeStorage(long idealStorageSize, FreeStorageReceiver r,
- PendingIntent pi) throws Exception {
- try {
- // Spin lock waiting for call back
- synchronized(r) {
- getPm().freeStorage(null, idealStorageSize, 0, pi.getIntentSender());
- long waitTime = 0;
- while(!r.isDone() && (waitTime < MAX_WAIT_TIME)) {
- r.wait(WAIT_TIME_INCR);
- waitTime += WAIT_TIME_INCR;
- }
- if(!r.isDone()) {
- throw new Exception("timed out waiting for call back from PendingIntent");
- }
- }
- return r.getResultCode() == 1;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
- return false;
- } catch (InterruptedException e) {
- Log.w(TAG, "InterruptedException :"+e);
- return false;
- }
- }
-
- @LargeTest
- public void testDeleteAppCacheFiles() throws Exception {
- String testName="testDeleteAppCacheFiles";
- File cacheDir = mContext.getCacheDir();
- createTestFiles1(cacheDir, "testtmpdir", 5);
- assertTrue(invokePMDeleteAppCacheFiles());
- //confirm files dont exist
- verifyTestFiles1(cacheDir, "testtmpdir", 5);
- }
-
- class PackageStatsObserver extends IPackageStatsObserver.Stub {
- public boolean retValue = false;
- public PackageStats stats;
- private boolean doneFlag = false;
-
- public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
- throws RemoteException {
- synchronized(this) {
- retValue = succeeded;
- stats = pStats;
- doneFlag = true;
- notifyAll();
- }
- }
- public boolean isDone() {
- return doneFlag;
- }
- }
-
- @SmallTest
- public void testGetSystemSharedLibraryNames() throws Exception {
- try {
- String[] sharedLibs = getPm().getSystemSharedLibraryNames();
- if (localLOGV) {
- for (String str : sharedLibs) {
- Log.i(TAG, str);
- }
- }
- } catch (RemoteException e) {
- fail("Failed invoking getSystemSharedLibraryNames with exception:" + e);
- }
- }
-
- class FreeStorageReceiver extends BroadcastReceiver {
- public static final String ACTION_FREE = "com.android.unit_tests.testcallback";
- private boolean doneFlag = false;
-
- public boolean isDone() {
- return doneFlag;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if(intent.getAction().equalsIgnoreCase(ACTION_FREE)) {
- if (localLOGV) Log.i(TAG, "Got notification: clear cache succeeded "+getResultCode());
- synchronized (this) {
- doneFlag = true;
- notifyAll();
- }
- }
- }
- }
-
- // TODO: flaky test, omit from LargeTest for now
- //@LargeTest
- public void testFreeStorage() throws Exception {
- boolean TRACKING = true;
- StatFs st = new StatFs("/data");
- long blks1 = getFreeStorageBlks(st);
- if(localLOGV || TRACKING) Log.i(TAG, "Available free blocks="+blks1);
- long availableMem = getFreeStorageSize(st);
- File cacheDir = mContext.getCacheDir();
- assertNotNull(cacheDir);
- createTestFiles1(cacheDir, "testtmpdir", 5);
- long blks2 = getFreeStorageBlks(st);
- if(localLOGV || TRACKING) Log.i(TAG, "Available blocks after writing test files in application cache="+blks2);
- // Create receiver and register it
- FreeStorageReceiver receiver = new FreeStorageReceiver();
- mContext.registerReceiver(receiver, new IntentFilter(FreeStorageReceiver.ACTION_FREE));
- PendingIntent pi = PendingIntent.getBroadcast(mContext,
- 0, new Intent(FreeStorageReceiver.ACTION_FREE), 0);
- // Invoke PackageManager api
- if (!invokePMFreeStorage(availableMem, receiver, pi)) {
- fail("Could not invoke PackageManager free storage API");
- }
- long blks3 = getFreeStorageBlks(st);
- if(localLOGV || TRACKING) Log.i(TAG, "Available blocks after freeing cache"+blks3);
- assertEquals(receiver.getResultCode(), 1);
- mContext.unregisterReceiver(receiver);
- // Verify result
- verifyTestFiles1(cacheDir, "testtmpdir", 5);
- }
-
- /* utility method used to create observer and check async call back from PackageManager.
- * ClearApplicationUserData
- */
- boolean invokePMClearApplicationUserData() throws Exception {
- try {
- String packageName = mContext.getPackageName();
- PackageDataObserver observer = new PackageDataObserver();
- //wait on observer
- synchronized(observer) {
- getPm().clearApplicationUserData(packageName, observer, 0 /* TODO: Other users */);
- long waitTime = 0;
- while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) {
- observer.wait(WAIT_TIME_INCR);
- waitTime += WAIT_TIME_INCR;
- }
- if(!observer.isDone()) {
- throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted");
- }
- }
- return observer.retValue;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
- return false;
- } catch (InterruptedException e) {
- Log.w(TAG, "InterruptedException :"+e);
- return false;
- }
- }
-
- void verifyUserDataCleared(File pDir) {
- if(localLOGV) Log.i(TAG, "Verifying "+pDir);
- if(pDir == null) {
- return;
- }
- String fileList[] = pDir.list();
- if(fileList == null) {
- return;
- }
- int imax = fileList.length;
- //look recursively in user data dir
- for(int i = 0; i < imax; i++) {
- if(localLOGV) Log.i(TAG, "Found entry "+fileList[i]+ "in "+pDir);
- if("lib".equalsIgnoreCase(fileList[i])) {
- if(localLOGV) Log.i(TAG, "Ignoring lib directory");
- continue;
- }
- fail(pDir+" should be empty or contain only lib subdirectory. Found "+fileList[i]);
- }
- }
-
- File getDataDir() {
- try {
- ApplicationInfo appInfo = getPm().getApplicationInfo(mContext.getPackageName(), 0,
- UserHandle.myUserId());
- return new File(appInfo.dataDir);
- } catch (RemoteException e) {
- throw new RuntimeException("Pacakge manager dead", e);
- }
- }
-
- @Suppress
- @LargeTest
- public void testClearApplicationUserDataWithTestData() throws Exception {
- File cacheDir = mContext.getCacheDir();
- createTestFiles1(cacheDir, "testtmpdir", 5);
- if(localLOGV) {
- Log.i(TAG, "Created test data Waiting for 60seconds before continuing");
- Thread.sleep(60*1000);
- }
- assertTrue(invokePMClearApplicationUserData());
- //confirm files dont exist
- verifyUserDataCleared(getDataDir());
- }
-
- @Suppress
- @SmallTest
- public void testClearApplicationUserDataWithNoTestData() throws Exception {
- assertTrue(invokePMClearApplicationUserData());
- //confirm files dont exist
- verifyUserDataCleared(getDataDir());
- }
-
- @Suppress
- @LargeTest
- public void testClearApplicationUserDataNoObserver() throws Exception {
- getPm().clearApplicationUserData(mContext.getPackageName(), null, UserHandle.myUserId());
- //sleep for 1 minute
- Thread.sleep(60*1000);
- //confirm files dont exist
- verifyUserDataCleared(getDataDir());
- }
-
-}
diff --git a/core/tests/coretests/src/android/content/pm/PackageHelperTests.java b/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
index 55092fa..b627619 100644
--- a/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
@@ -16,11 +16,9 @@
package android.content.pm;
+import static android.os.storage.VolumeInfo.STATE_MOUNTED;
+
import android.content.Context;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.test.AndroidTestCase;
@@ -36,16 +34,10 @@
import java.util.List;
import java.util.UUID;
-import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.os.storage.VolumeInfo.STATE_MOUNTED;
-
public class PackageHelperTests extends AndroidTestCase {
private static final boolean localLOGV = true;
public static final String TAG = "PackageHelperTests";
protected final String PREFIX = "android.content.pm";
- private IStorageManager mSm;
- private String fullId;
- private String fullId2;
private static final String sInternalVolPath = "/data";
private static final String sAdoptedVolPath = "/mnt/expand/123";
@@ -147,34 +139,11 @@
}
}
- private IStorageManager getSm() {
- IBinder service = ServiceManager.getService("mount");
- if (service != null) {
- return IStorageManager.Stub.asInterface(service);
- } else {
- Log.e(TAG, "Can't get mount service");
- }
- return null;
- }
-
- private void cleanupContainers() throws RemoteException {
- Log.d(TAG,"cleanUp");
- IStorageManager sm = getSm();
- String[] containers = sm.getSecureContainerList();
- for (int i = 0; i < containers.length; i++) {
- if (containers[i].startsWith(PREFIX)) {
- Log.d(TAG,"cleaing up "+containers[i]);
- sm.destroySecureContainer(containers[i], true);
- }
- }
- }
-
@Override
protected void setUp() throws Exception {
super.setUp();
sStorageManager = createStorageManagerMock();
if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
- cleanupContainers();
}
@Override
@@ -182,55 +151,6 @@
super.tearDown();
sStorageManager = null;
if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
- cleanupContainers();
- }
-
- public void testMountAndPullSdCard() throws Exception {
- fullId = PREFIX;
- fullId2 = PackageHelper.createSdDir(1024 * MB_IN_BYTES, fullId, "none",
- android.os.Process.myUid(), true);
-
- Log.d(TAG, "getSdDir=" + PackageHelper.getSdDir(fullId));
- PackageHelper.unMountSdDir(fullId);
-
- Runnable r1 = getMountRunnable();
- Runnable r2 = getDestroyRunnable();
- Thread thread = new Thread(r1);
- Thread thread2 = new Thread(r2);
- thread2.start();
- thread.start();
- }
-
- public Runnable getMountRunnable() {
- Runnable r = new Runnable () {
- public void run () {
- try {
- Thread.sleep(5);
- String path = PackageHelper.mountSdDir(fullId, "none",
- android.os.Process.myUid());
- Log.e(TAG, "mount done " + path);
- } catch (IllegalArgumentException iae) {
- throw iae;
- } catch (Throwable t) {
- Log.e(TAG, "mount failed", t);
- }
- }
- };
- return r;
- }
-
- public Runnable getDestroyRunnable() {
- Runnable r = new Runnable () {
- public void run () {
- try {
- PackageHelper.destroySdDir(fullId);
- Log.e(TAG, "destroy done: " + fullId);
- } catch (Throwable t) {
- Log.e(TAG, "destroy failed", t);
- }
- }
- };
- return r;
}
public void testResolveInstallVolumeInternal_SystemApp() throws IOException {
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index b8fa06c..a317c99 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -46,13 +46,8 @@
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.StatFs;
import android.os.SystemClock;
-import android.os.storage.IStorageManager;
-import android.os.storage.StorageListener;
-import android.os.storage.StorageManager;
-import android.os.storage.StorageResultCode;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.system.ErrnoException;
@@ -103,8 +98,6 @@
private static final int APP_INSTALL_SDCARD = PackageHelper.APP_INSTALL_EXTERNAL;
- private boolean mOrigState;
-
void failStr(String errMsg) {
Log.w(TAG, "errMsg=" + errMsg);
fail(errMsg);
@@ -114,29 +107,6 @@
failStr(e.getMessage());
}
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mOrigState = checkMediaState(Environment.MEDIA_MOUNTED);
- if (!mountMedia()) {
- Log.i(TAG, "sdcard not mounted? Some of these tests might fail");
- }
- }
-
- @Override
- protected void tearDown() throws Exception {
- // Restore media state.
- boolean newState = checkMediaState(Environment.MEDIA_MOUNTED);
- if (newState != mOrigState) {
- if (mOrigState) {
- mountMedia();
- } else {
- unmountMedia();
- }
- }
- super.tearDown();
- }
-
private abstract static class GenericReceiver extends BroadcastReceiver {
private boolean doneFlag = false;
@@ -782,17 +752,6 @@
sampleInstallFromRawResource(0, true);
}
- @LargeTest
- public void testInstallSdcard() throws Exception {
- // Do not run on devices with emulated external storage.
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- mountMedia();
- sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL, true);
- }
-
/* ------------------------- Test replacing packages -------------- */
class ReplaceReceiver extends GenericReceiver {
String pkgName;
@@ -1081,240 +1040,6 @@
deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.DELETE_KEEP_DATA);
}
- /* sdcard mount/unmount tests ***** */
-
- class SdMountReceiver extends GenericReceiver {
- String pkgNames[];
-
- boolean status = true;
-
- SdMountReceiver(String[] pkgNames) {
- this.pkgNames = pkgNames;
- IntentFilter filter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
- super.setFilter(filter);
- }
-
- public boolean notifyNow(Intent intent) {
- Log.i(TAG, "okay 1");
- String action = intent.getAction();
- if (!Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
- return false;
- }
- String rpkgList[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- for (String pkg : pkgNames) {
- boolean found = false;
- for (String rpkg : rpkgList) {
- if (rpkg.equals(pkg)) {
- found = true;
- break;
- }
- }
- if (!found) {
- status = false;
- return true;
- }
- }
- return true;
- }
- }
-
- class SdUnMountReceiver extends GenericReceiver {
- String pkgNames[];
-
- boolean status = true;
-
- SdUnMountReceiver(String[] pkgNames) {
- this.pkgNames = pkgNames;
- IntentFilter filter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- super.setFilter(filter);
- }
-
- public boolean notifyNow(Intent intent) {
- String action = intent.getAction();
- if (!Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
- return false;
- }
- String rpkgList[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- for (String pkg : pkgNames) {
- boolean found = false;
- for (String rpkg : rpkgList) {
- if (rpkg.equals(pkg)) {
- found = true;
- break;
- }
- }
- if (!found) {
- status = false;
- return true;
- }
- }
- return true;
- }
- }
-
- IStorageManager getSm() {
- IBinder service = ServiceManager.getService("mount");
- if (service != null) {
- return IStorageManager.Stub.asInterface(service);
- } else {
- Log.e(TAG, "Can't get storagemanager service");
- }
- return null;
- }
-
- boolean checkMediaState(String desired) {
- String actual = Environment.getExternalStorageState();
- if (desired.equals(actual)) {
- return true;
- } else {
- return false;
- }
- }
-
- boolean mountMedia() {
- // We can't mount emulated storage.
- if (Environment.isExternalStorageEmulated()) {
- return true;
- }
-
- if (checkMediaState(Environment.MEDIA_MOUNTED)) {
- return true;
- }
-
- final String path = Environment.getExternalStorageDirectory().toString();
- StorageListener observer = new StorageListener(Environment.MEDIA_MOUNTED);
- StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
- sm.registerListener(observer);
- try {
- // Wait on observer
- synchronized (observer) {
- int ret = getSm().mountVolume(path);
- if (ret != StorageResultCode.OperationSucceeded) {
- throw new Exception("Could not mount the media");
- }
- long waitTime = 0;
- while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
- observer.wait(WAIT_TIME_INCR);
- waitTime += WAIT_TIME_INCR;
- }
- if (!observer.isDone()) {
- throw new Exception("Timed out waiting for unmount media notification");
- }
- return true;
- }
- } catch (Exception e) {
- Log.e(TAG, "Exception : " + e);
- return false;
- } finally {
- sm.unregisterListener(observer);
- }
- }
-
- private boolean unmountMedia() {
- // We can't unmount emulated storage.
- if (Environment.isExternalStorageEmulated()) {
- return true;
- }
-
- if (checkMediaState(Environment.MEDIA_UNMOUNTED)) {
- return true;
- }
-
- final String path = Environment.getExternalStorageDirectory().getPath();
- StorageListener observer = new StorageListener(Environment.MEDIA_UNMOUNTED);
- StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
- sm.registerListener(observer);
- try {
- // Wait on observer
- synchronized (observer) {
- getSm().unmountVolume(path, true, false);
- long waitTime = 0;
- while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
- observer.wait(WAIT_TIME_INCR);
- waitTime += WAIT_TIME_INCR;
- }
- if (!observer.isDone()) {
- throw new Exception("Timed out waiting for unmount media notification");
- }
- return true;
- }
- } catch (Exception e) {
- Log.e(TAG, "Exception : " + e);
- return false;
- } finally {
- sm.unregisterListener(observer);
- }
- }
-
- private boolean mountFromRawResource() throws Exception {
- // Install pkg on sdcard
- InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL, false);
- if (localLOGV) Log.i(TAG, "Installed pkg on sdcard");
- boolean origState = checkMediaState(Environment.MEDIA_MOUNTED);
- boolean registeredReceiver = false;
- SdMountReceiver receiver = new SdMountReceiver(new String[]{ip.pkg.packageName});
- try {
- if (localLOGV) Log.i(TAG, "Unmounting media");
- // Unmount media
- assertTrue(unmountMedia());
- if (localLOGV) Log.i(TAG, "Unmounted media");
- // Register receiver here
- PackageManager pm = getPm();
- mContext.registerReceiver(receiver, receiver.filter);
- registeredReceiver = true;
-
- // Wait on receiver
- synchronized (receiver) {
- if (localLOGV) Log.i(TAG, "Mounting media");
- // Mount media again
- assertTrue(mountMedia());
- if (localLOGV) Log.i(TAG, "Mounted media");
- if (localLOGV) Log.i(TAG, "Waiting for notification");
- long waitTime = 0;
- // Verify we received the broadcast
- waitTime = 0;
- while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
- receiver.wait(WAIT_TIME_INCR);
- waitTime += WAIT_TIME_INCR;
- }
- if(!receiver.isDone()) {
- failStr("Timed out waiting for EXTERNAL_APPLICATIONS notification");
- }
- return receiver.received;
- }
- } catch (InterruptedException e) {
- failStr(e);
- return false;
- } finally {
- if (registeredReceiver) {
- mContext.unregisterReceiver(receiver);
- }
- // Restore original media state
- if (origState) {
- mountMedia();
- } else {
- unmountMedia();
- }
- if (localLOGV) Log.i(TAG, "Cleaning up install");
- cleanUpInstall(ip);
- }
- }
-
- /*
- * Install package on sdcard. Unmount and then mount the media.
- * (Use PackageManagerService private api for now)
- * Make sure the installed package is available.
- */
- @LargeTest
- public void testMountSdNormalInternal() throws Exception {
- // Do not run on devices with emulated external storage.
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertTrue(mountFromRawResource());
- }
-
void cleanUpInstall(InstallParams ip) throws Exception {
if (ip == null) {
return;
@@ -1713,64 +1438,6 @@
}
}
- /*
- * Test that an install error code is returned when media is unmounted
- * and package installed on sdcard via package manager flag.
- */
- @LargeTest
- public void testInstallSdcardUnmount() throws Exception {
- // Do not run on devices with emulated external storage.
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- boolean origState = checkMediaState(Environment.MEDIA_MOUNTED);
- try {
- // Unmount sdcard
- assertTrue(unmountMedia());
- // Try to install and make sure an error code is returned.
- installFromRawResource("install.apk", R.raw.install,
- PackageManager.INSTALL_EXTERNAL, false,
- true, PackageInstaller.STATUS_FAILURE_STORAGE,
- PackageInfo.INSTALL_LOCATION_AUTO);
- } finally {
- // Restore original media state
- if (origState) {
- mountMedia();
- } else {
- unmountMedia();
- }
- }
- }
-
- /*
- * Unmount sdcard. Try installing an app with manifest option to install
- * on sdcard. Make sure it gets installed on internal flash.
- */
- @LargeTest
- public void testInstallManifestSdcardUnmount() throws Exception {
- // Do not run on devices with emulated external storage.
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- boolean origState = checkMediaState(Environment.MEDIA_MOUNTED);
- try {
- // Unmount sdcard
- assertTrue(unmountMedia());
- InstallParams ip = new InstallParams("install.apk", R.raw.install_loc_sdcard);
- installFromRawResource(ip, 0, true, false, -1,
- PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- } finally {
- // Restore original media state
- if (origState) {
- mountMedia();
- } else {
- unmountMedia();
- }
- }
- }
-
/*---------- Recommended install location tests ----*/
/*
* PrecedenceSuffixes:
@@ -2527,133 +2194,6 @@
}
/*
- * Ensure that permissions are properly declared.
- */
- @LargeTest
- public void testInstallOnSdPermissionsUnmount() throws Exception {
- InstallParams ip = null;
- boolean origMediaState = checkMediaState(Environment.MEDIA_MOUNTED);
- try {
- // **: Upon installing a package, are its declared permissions published?
- int iFlags = PackageManager.INSTALL_INTERNAL;
- int iApk = R.raw.install_decl_perm;
- ip = installFromRawResource("install.apk", iApk,
- iFlags, false,
- false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
- assertPermissions(BASE_PERMISSIONS_DEFINED);
- // Unmount media here
- assertTrue(unmountMedia());
- // Mount media again
- mountMedia();
- //Check permissions now
- assertPermissions(BASE_PERMISSIONS_DEFINED);
- } finally {
- if (ip != null) {
- cleanUpInstall(ip);
- }
- }
- }
-
- /* This test creates a stale container via StorageManagerService and then installs
- * a package and verifies that the stale container is cleaned up and install
- * is successful.
- * Please note that this test is very closely tied to the framework's
- * naming convention for secure containers.
- */
- @LargeTest
- public void testInstallSdcardStaleContainer() throws Exception {
- // Do not run on devices with emulated external storage.
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- boolean origMediaState = checkMediaState(Environment.MEDIA_MOUNTED);
- try {
- // Mount media first
- mountMedia();
- String outFileName = "install.apk";
- int rawResId = R.raw.install;
- PackageManager pm = mContext.getPackageManager();
- File filesDir = mContext.getFilesDir();
- File outFile = new File(filesDir, outFileName);
- Uri packageURI = getInstallablePackage(rawResId, outFile);
- PackageParser.Package pkg = parsePackage(packageURI);
- assertNotNull(pkg);
- // Install an app on sdcard.
- installFromRawResource(outFileName, rawResId,
- PackageManager.INSTALL_EXTERNAL, false,
- false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- // Unmount sdcard
- unmountMedia();
- // Delete the app on sdcard to leave a stale container on sdcard.
- GenericReceiver receiver = new DeleteReceiver(pkg.packageName);
- assertTrue(invokeDeletePackage(pkg.packageName, 0, receiver));
- mountMedia();
- // Reinstall the app and make sure it gets installed.
- installFromRawResource(outFileName, rawResId,
- PackageManager.INSTALL_EXTERNAL, true,
- false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- } catch (Exception e) {
- failStr(e.getMessage());
- } finally {
- if (origMediaState) {
- mountMedia();
- } else {
- unmountMedia();
- }
-
- }
- }
-
- /* This test installs an application on sdcard and unmounts media.
- * The app is then re-installed on internal storage. The sdcard is mounted
- * and verified that the re-installation on internal storage takes precedence.
- */
- @LargeTest
- public void testInstallSdcardStaleContainerReinstall() throws Exception {
- // Do not run on devices with emulated external storage.
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- boolean origMediaState = checkMediaState(Environment.MEDIA_MOUNTED);
- try {
- // Mount media first
- mountMedia();
- String outFileName = "install.apk";
- int rawResId = R.raw.install;
- PackageManager pm = mContext.getPackageManager();
- File filesDir = mContext.getFilesDir();
- File outFile = new File(filesDir, outFileName);
- Uri packageURI = getInstallablePackage(rawResId, outFile);
- PackageParser.Package pkg = parsePackage(packageURI);
- assertNotNull(pkg);
- // Install an app on sdcard.
- installFromRawResource(outFileName, rawResId,
- PackageManager.INSTALL_EXTERNAL, false,
- false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- // Unmount sdcard
- unmountMedia();
- // Reinstall the app and make sure it gets installed on internal storage.
- installFromRawResource(outFileName, rawResId,
- PackageManager.INSTALL_REPLACE_EXISTING, false,
- false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- mountMedia();
- // Verify that the app installed is on internal storage.
- assertInstall(pkg, 0, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- } catch (Exception e) {
- failStr(e.getMessage());
- } finally {
- if (origMediaState) {
- mountMedia();
- } else {
- unmountMedia();
- }
- }
- }
-
- /*
* The following series of tests are related to upgrading apps with
* different certificates.
*/
diff --git a/core/tests/coretests/src/android/os/storage/AsecTests.java b/core/tests/coretests/src/android/os/storage/AsecTests.java
deleted file mode 100644
index e9a810d..0000000
--- a/core/tests/coretests/src/android/os/storage/AsecTests.java
+++ /dev/null
@@ -1,756 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os.storage;
-
-import android.content.Context;
-import android.os.Environment;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileOutputStream;
-
-public class AsecTests extends AndroidTestCase {
- private static final String SECURE_CONTAINER_PREFIX = "com.android.unittests.AsecTests.";
- private static final boolean localLOGV = true;
- public static final String TAG="AsecTests";
-
- private static final String FS_FAT = "fat";
- private static final String FS_EXT4 = "ext4";
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
- cleanupContainers();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
- cleanupContainers();
- }
-
- private void cleanupContainers() throws RemoteException {
- IStorageManager sm = getSm();
- String[] containers = sm.getSecureContainerList();
-
- for (int i = 0; i < containers.length; i++) {
- if (containers[i].startsWith(SECURE_CONTAINER_PREFIX)) {
- if (localLOGV)
- Log.i(TAG, "Cleaning: " + containers[i]);
- sm.destroySecureContainer(containers[i], true);
- }
- }
- }
-
- private boolean containerExists(String localId) throws RemoteException {
- IStorageManager sm = getSm();
- String[] containers = sm.getSecureContainerList();
- String fullId = SECURE_CONTAINER_PREFIX + localId;
-
- for (int i = 0; i < containers.length; i++) {
- if (containers[i].equals(fullId)) {
- return true;
- }
- }
- return false;
- }
-
- private int createContainer(String localId, int size, String key, String filesystem,
- boolean isExternal) throws Exception {
- assertTrue("Media should be mounted", isMediaMounted());
- String fullId = SECURE_CONTAINER_PREFIX + localId;
-
- IStorageManager sm = getSm();
- return sm.createSecureContainer(fullId, size, filesystem, key, android.os.Process.myUid(),
- isExternal);
- }
-
- private int mountContainer(String localId, String key) throws Exception {
- assertTrue("Media should be mounted", isMediaMounted());
- String fullId = SECURE_CONTAINER_PREFIX + localId;
-
- IStorageManager sm = getSm();
- return sm.mountSecureContainer(fullId, key, android.os.Process.myUid(), true);
- }
-
- private int renameContainer(String localId1, String localId2) throws Exception {
- assertTrue("Media should be mounted", isMediaMounted());
- String fullId1 = SECURE_CONTAINER_PREFIX + localId1;
- String fullId2 = SECURE_CONTAINER_PREFIX + localId2;
-
- IStorageManager sm = getSm();
- return sm.renameSecureContainer(fullId1, fullId2);
- }
-
- private int unmountContainer(String localId, boolean force) throws Exception {
- assertTrue("Media should be mounted", isMediaMounted());
- String fullId = SECURE_CONTAINER_PREFIX + localId;
-
- IStorageManager sm = getSm();
- return sm.unmountSecureContainer(fullId, force);
- }
-
- private int destroyContainer(String localId, boolean force) throws Exception {
- assertTrue("Media should be mounted", isMediaMounted());
- String fullId = SECURE_CONTAINER_PREFIX + localId;
-
- IStorageManager sm = getSm();
- return sm.destroySecureContainer(fullId, force);
- }
-
- private boolean isContainerMounted(String localId) throws Exception {
- assertTrue("Media should be mounted", isMediaMounted());
- String fullId = SECURE_CONTAINER_PREFIX + localId;
-
- IStorageManager sm = getSm();
- return sm.isSecureContainerMounted(fullId);
- }
-
- private IStorageManager getSm() {
- IBinder service = ServiceManager.getService("mount");
- if (service != null) {
- return IStorageManager.Stub.asInterface(service);
- } else {
- Log.e(TAG, "Can't get storagemanager service");
- }
- return null;
- }
-
- private boolean isMediaMounted() throws Exception {
- String mPath = Environment.getExternalStorageDirectory().toString();
- String state = getSm().getVolumeState(mPath);
- return Environment.MEDIA_MOUNTED.equals(state);
- }
-
-
- /*
- * CREATE
- */
-
- public void test_Fat_External_Create_Success() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testCreateContainer", 4, "none", FS_FAT, true));
- assertTrue(containerExists("testCreateContainer"));
- }
-
- public void test_Ext4_External_Create_Success() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testCreateContainer", 4, "none", FS_EXT4, true));
- assertTrue(containerExists("testCreateContainer"));
- }
-
- public void test_Fat_Internal_Create_Success() throws Exception {
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testCreateContainer", 4, "none", FS_FAT, false));
- assertTrue(containerExists("testCreateContainer"));
- }
-
- public void test_Ext4_Internal_Create_Success() throws Exception {
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testCreateContainer", 4, "none", FS_EXT4, false));
- assertTrue(containerExists("testCreateContainer"));
- }
-
-
- /*
- * CREATE MIN SIZE
- */
-
- public void test_Fat_External_CreateMinSize_Success() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testCreateContainer", 1, "none", FS_FAT, true));
- assertTrue(containerExists("testCreateContainer"));
- }
-
- public void test_Ext4_External_CreateMinSize_Success() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testCreateContainer", 1, "none", FS_EXT4, true));
- assertTrue(containerExists("testCreateContainer"));
- }
-
- public void test_Fat_Internal_CreateMinSize_Success() throws Exception {
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testCreateContainer", 1, "none", FS_FAT, false));
- assertTrue(containerExists("testCreateContainer"));
- }
-
- public void test_Ext4_Internal_CreateMinSize_Success() throws Exception {
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testCreateContainer", 1, "none", FS_EXT4, false));
- assertTrue(containerExists("testCreateContainer"));
- }
-
-
- /*
- * CREATE ZERO SIZE - FAIL CASE
- */
-
- public void test_Fat_External_CreateZeroSize_Failure() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationFailedInternalError,
- createContainer("testCreateZeroContainer", 0, "none", FS_FAT, true));
- }
-
- public void test_Ext4_External_CreateZeroSize_Failure() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationFailedInternalError,
- createContainer("testCreateZeroContainer", 0, "none", FS_EXT4, true));
- }
-
- public void test_Fat_Internal_CreateZeroSize_Failure() throws Exception {
- assertEquals(StorageResultCode.OperationFailedInternalError,
- createContainer("testCreateZeroContainer", 0, "none", FS_FAT, false));
- }
-
- public void test_Ext4_Internal_CreateZeroSize_Failure() throws Exception {
- assertEquals(StorageResultCode.OperationFailedInternalError,
- createContainer("testCreateZeroContainer", 0, "none", FS_EXT4, false));
- }
-
-
- /*
- * CREATE DUPLICATE - FAIL CASE
- */
-
- public void test_Fat_External_CreateDuplicate_Failure() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testCreateDupContainer", 4, "none", FS_FAT, true));
-
- assertEquals(StorageResultCode.OperationFailedInternalError,
- createContainer("testCreateDupContainer", 4, "none", FS_FAT, true));
- }
-
- public void test_Ext4_External_CreateDuplicate_Failure() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testCreateDupContainer", 4, "none", FS_EXT4, true));
-
- assertEquals(StorageResultCode.OperationFailedInternalError,
- createContainer("testCreateDupContainer", 4, "none", FS_EXT4, true));
- }
-
- public void test_Fat_Internal_CreateDuplicate_Failure() throws Exception {
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testCreateDupContainer", 4, "none", FS_FAT, false));
-
- assertEquals(StorageResultCode.OperationFailedInternalError,
- createContainer("testCreateDupContainer", 4, "none", FS_FAT, false));
- }
-
- public void test_Ext4_Internal_CreateDuplicate_Failure() throws Exception {
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testCreateDupContainer", 4, "none", FS_EXT4, false));
-
- assertEquals(StorageResultCode.OperationFailedInternalError,
- createContainer("testCreateDupContainer", 4, "none", FS_EXT4, false));
- }
-
-
- /*
- * DESTROY
- */
-
- public void test_Fat_External_Destroy_Success() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testDestroyContainer", 4, "none", FS_FAT, true));
- assertEquals(StorageResultCode.OperationSucceeded,
- destroyContainer("testDestroyContainer", false));
- }
-
- public void test_Ext4_External_Destroy_Success() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testDestroyContainer", 4, "none", FS_EXT4, true));
- assertEquals(StorageResultCode.OperationSucceeded,
- destroyContainer("testDestroyContainer", false));
- }
-
- public void test_Fat_Internal_Destroy_Success() throws Exception {
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testDestroyContainer", 4, "none", FS_FAT, false));
- assertEquals(StorageResultCode.OperationSucceeded,
- destroyContainer("testDestroyContainer", false));
- }
-
- public void test_Ext4_Internal_Destroy_Success() throws Exception {
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testDestroyContainer", 4, "none", FS_EXT4, false));
- assertEquals(StorageResultCode.OperationSucceeded,
- destroyContainer("testDestroyContainer", false));
- }
-
-
- /*
- * MOUNT
- */
-
- public void test_Fat_External_Mount() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testMountContainer", 4, "none", FS_FAT, true));
-
- assertEquals(StorageResultCode.OperationSucceeded,
- unmountContainer("testMountContainer", false));
-
- assertEquals(StorageResultCode.OperationSucceeded,
- mountContainer("testMountContainer", "none"));
- }
-
-
- /*
- * MOUNT BAD KEY - FAIL CASE
- */
-
- public void test_Fat_External_MountBadKey_Failure() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testMountBadKey", 4, "00000000000000000000000000000000", FS_FAT,
- true));
-
- assertEquals(StorageResultCode.OperationSucceeded,
- unmountContainer("testMountBadKey", false));
-
- assertEquals(StorageResultCode.OperationFailedInternalError,
- mountContainer("testMountContainer", "000000000000000000000000000000001"));
-
- assertEquals(StorageResultCode.OperationFailedInternalError,
- mountContainer("testMountContainer", "none"));
- }
-
-
- public void test_Fat_External_UnmountBusy_Success() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- IStorageManager sm = getSm();
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testUnmountBusyContainer", 4, "none", FS_FAT, true));
-
- String path = sm.getSecureContainerPath(SECURE_CONTAINER_PREFIX
- + "testUnmountBusyContainer");
-
- File f = new File(path, "reference");
- FileOutputStream fos = new FileOutputStream(f);
-
- assertEquals(StorageResultCode.OperationFailedStorageBusy,
- unmountContainer("testUnmountBusyContainer", false));
-
- fos.close();
- assertEquals(StorageResultCode.OperationSucceeded,
- unmountContainer("testUnmountBusyContainer", false));
- }
-
- public void test_Fat_External_DestroyBusy() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- IStorageManager sm = getSm();
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testDestroyBusyContainer", 4, "none", FS_FAT, true));
-
- String path = sm.getSecureContainerPath(SECURE_CONTAINER_PREFIX
- + "testDestroyBusyContainer");
-
- File f = new File(path, "reference");
- FileOutputStream fos = new FileOutputStream(f);
-
- assertEquals(StorageResultCode.OperationFailedStorageBusy,
- destroyContainer("testDestroyBusyContainer", false));
-
- fos.close();
- assertEquals(StorageResultCode.OperationSucceeded,
- destroyContainer("testDestroyBusyContainer", false));
- }
-
- public void test_Fat_External_Rename_Success() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testRenameContainer.1", 4, "none", FS_FAT, true));
-
- assertEquals(StorageResultCode.OperationSucceeded,
- unmountContainer("testRenameContainer.1", false));
-
- assertEquals(StorageResultCode.OperationSucceeded,
- renameContainer("testRenameContainer.1", "testRenameContainer.2"));
-
- assertFalse(containerExists("testRenameContainer.1"));
- assertTrue(containerExists("testRenameContainer.2"));
- }
-
- public void test_Fat_External_RenameSrcMounted_Failure() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testRenameContainer.1", 4, "none", FS_FAT, true));
-
- assertEquals(StorageResultCode.OperationFailedStorageMounted,
- renameContainer("testRenameContainer.1", "testRenameContainer.2"));
- }
-
- public void test_Fat_External_RenameDstMounted_Failure() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testRenameContainer.1", 4, "none", FS_FAT, true));
-
- assertEquals(StorageResultCode.OperationSucceeded,
- unmountContainer("testRenameContainer.1", false));
-
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testRenameContainer.2", 4, "none", FS_FAT, true));
-
- assertEquals(StorageResultCode.OperationFailedStorageMounted,
- renameContainer("testRenameContainer.1", "testRenameContainer.2"));
- }
-
- public void test_Fat_External_Size_Success() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- IStorageManager sm = getSm();
- assertEquals(StorageResultCode.OperationSucceeded,
- createContainer("testContainerSize", 1, "none", FS_FAT, true));
- String path = sm.getSecureContainerPath(SECURE_CONTAINER_PREFIX + "testContainerSize");
-
- byte[] buf = new byte[4096];
- File f = new File(path, "reference");
- FileOutputStream fos = new FileOutputStream(f);
- for (int i = 0; i < (1024 * 1024); i += buf.length) {
- fos.write(buf);
- }
- fos.close();
- }
-
- public void testGetSecureContainerPath_NonExistPath_Failure() throws Exception {
- IStorageManager sm = getSm();
- assertNull("Getting the path for an invalid container should return null",
- sm.getSecureContainerPath("jparks.broke.it"));
- }
-
- /*------------ Tests for unmounting volume ---*/
- public final long MAX_WAIT_TIME=120*1000;
- public final long WAIT_TIME_INCR=20*1000;
-
- boolean getMediaState() throws Exception {
- String mPath = Environment.getExternalStorageDirectory().toString();
- String state = getSm().getVolumeState(mPath);
- return Environment.MEDIA_MOUNTED.equals(state);
- }
-
- boolean mountMedia() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return true;
- }
-
- if (getMediaState()) {
- return true;
- }
-
- String mPath = Environment.getExternalStorageDirectory().toString();
- int ret = getSm().mountVolume(mPath);
- return ret == StorageResultCode.OperationSucceeded;
- }
-
- class StorageListener extends StorageEventListener {
- String oldState;
- String newState;
- String path;
- private boolean doneFlag = false;
-
- public void action() {
- synchronized (this) {
- doneFlag = true;
- notifyAll();
- }
- }
-
- public boolean isDone() {
- return doneFlag;
- }
-
- @Override
- public void onStorageStateChanged(String path, String oldState, String newState) {
- if (localLOGV) Log.i(TAG, "Storage state changed from " + oldState + " to " + newState);
- this.oldState = oldState;
- this.newState = newState;
- this.path = path;
- action();
- }
- }
-
- private void unmountMedia() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- if (!getMediaState()) {
- return;
- }
-
- String path = Environment.getExternalStorageDirectory().toString();
- StorageListener observer = new StorageListener();
- StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
- sm.registerListener(observer);
- try {
- // Wait on observer
- synchronized(observer) {
- getSm().unmountVolume(path, false, false);
- long waitTime = 0;
- while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
- observer.wait(WAIT_TIME_INCR);
- waitTime += WAIT_TIME_INCR;
- }
- if(!observer.isDone()) {
- fail("Timed out waiting for packageInstalled callback");
- }
- }
- } finally {
- sm.unregisterListener(observer);
- }
- }
-
- public void testUnmount() throws Exception {
- boolean oldStatus = getMediaState();
- Log.i(TAG, "oldStatus="+oldStatus);
- try {
- // Mount media firsts
- if (!getMediaState()) {
- mountMedia();
- }
- unmountMedia();
- } finally {
- // Restore old status
- boolean currStatus = getMediaState();
- if (oldStatus != currStatus) {
- if (oldStatus) {
- // Mount media
- mountMedia();
- } else {
- unmountMedia();
- }
- }
- }
- }
-
- class MultipleStorageLis extends StorageListener {
- int count = 0;
- public void onStorageStateChanged(String path, String oldState, String newState) {
- count++;
- super.action();
- }
- }
- /*
- * This test invokes unmount multiple time and expects the call back
- * to be invoked just once.
- */
- public void testUnmountMultiple() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- boolean oldStatus = getMediaState();
- StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
- MultipleStorageLis observer = new MultipleStorageLis();
- try {
- // Mount media firsts
- if (!getMediaState()) {
- mountMedia();
- }
- String path = Environment.getExternalStorageDirectory().toString();
- sm.registerListener(observer);
- // Wait on observer
- synchronized(observer) {
- for (int i = 0; i < 5; i++) {
- getSm().unmountVolume(path, false, false);
- }
- long waitTime = 0;
- while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
- observer.wait(WAIT_TIME_INCR);
- waitTime += WAIT_TIME_INCR;
- }
- if(!observer.isDone()) {
- fail("Timed out waiting for packageInstalled callback");
- }
- }
- assertEquals(observer.count, 1);
- } finally {
- sm.unregisterListener(observer);
- // Restore old status
- boolean currStatus = getMediaState();
- if (oldStatus != currStatus) {
- if (oldStatus) {
- // Mount media
- mountMedia();
- } else {
- unmountMedia();
- }
- }
- }
- }
-
- class ShutdownObserver extends IStorageShutdownObserver.Stub{
- private boolean doneFlag = false;
- int statusCode;
-
- public void action() {
- synchronized (this) {
- doneFlag = true;
- notifyAll();
- }
- }
-
- public boolean isDone() {
- return doneFlag;
- }
- public void onShutDownComplete(int statusCode) throws RemoteException {
- this.statusCode = statusCode;
- action();
- }
-
- }
-
- void invokeShutdown() throws Exception {
- IStorageManager sm = getSm();
- ShutdownObserver observer = new ShutdownObserver();
- synchronized (observer) {
- sm.shutdown(observer);
- }
- }
-
- public void testShutdown() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- boolean oldStatus = getMediaState();
- try {
- // Mount media firsts
- if (!getMediaState()) {
- mountMedia();
- }
- invokeShutdown();
- } finally {
- // Restore old status
- boolean currStatus = getMediaState();
- if (oldStatus != currStatus) {
- if (oldStatus) {
- // Mount media
- mountMedia();
- } else {
- unmountMedia();
- }
- }
- }
- }
-
- /*
- * This test invokes unmount multiple time and expects the call back
- * to be invoked just once.
- */
- public void testShutdownMultiple() throws Exception {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- boolean oldStatus = getMediaState();
- try {
- // Mount media firsts
- if (!getMediaState()) {
- mountMedia();
- }
- IStorageManager sm = getSm();
- ShutdownObserver observer = new ShutdownObserver();
- synchronized (observer) {
- sm.shutdown(observer);
- for (int i = 0; i < 4; i++) {
- sm.shutdown(null);
- }
- }
- } finally {
- // Restore old status
- boolean currStatus = getMediaState();
- if (oldStatus != currStatus) {
- if (oldStatus) {
- // Mount media
- mountMedia();
- } else {
- unmountMedia();
- }
- }
- }
- }
-
-}
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
index 90cb9a5..56629d4 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
@@ -18,24 +18,21 @@
import android.content.Context;
import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
-import android.os.Environment;
-import android.os.SystemClock;
import android.test.InstrumentationTestCase;
import android.util.Log;
-import android.os.Environment;
-import android.os.FileUtils;
-import android.os.storage.OnObbStateChangeListener;
-import android.os.storage.StorageManager;
+
+import libcore.io.Streams;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.FileReader;
-import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.io.StringReader;
public class StorageManagerBaseTest extends InstrumentationTestCase {
@@ -219,46 +216,21 @@
}
/**
- * Helper to copy a raw resource file to an actual specified file
- *
- * @param rawResId The raw resource ID of the OBB resource file
- * @param outFile A File representing the file we want to copy the OBB to
- * @throws NotFoundException If the resource file could not be found
- */
- private void copyRawToFile(int rawResId, File outFile) throws NotFoundException {
- Resources res = mContext.getResources();
- InputStream is = null;
- try {
- is = res.openRawResource(rawResId);
- } catch (NotFoundException e) {
- Log.i(LOG_TAG, "Failed to load resource with id: " + rawResId);
- throw e;
- }
- FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
- | FileUtils.S_IRWXO, -1, -1);
- assertTrue(FileUtils.copyToFile(is, outFile));
- FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
- | FileUtils.S_IRWXO, -1, -1);
- }
-
- /**
* Creates an OBB file (with the given name), into the app's standard files directory
*
* @param name The name of the OBB file we want to create/write to
* @param rawResId The raw resource ID of the OBB file in the package
* @return A {@link File} representing the file to write to
*/
- protected File createObbFile(String name, int rawResId) {
- File outFile = null;
- try {
- final File filesDir = mContext.getFilesDir();
- outFile = new File(filesDir, name);
- copyRawToFile(rawResId, outFile);
- } catch (NotFoundException e) {
- if (outFile != null) {
- outFile.delete();
- }
+ protected File createObbFile(String name, int rawResId) throws IOException, Resources.NotFoundException {
+ final File outFile = new File(mContext.getObbDir(), name);
+ outFile.delete();
+
+ try (InputStream in = mContext.getResources().openRawResource(rawResId);
+ OutputStream out = new FileOutputStream(outFile)) {
+ Streams.copy(in, out);
}
+
return outFile;
}
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
index fbba6ff..5f8bd03 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
@@ -16,61 +16,27 @@
package android.os.storage;
-import android.content.Context;
-import android.os.Environment;
-import android.os.ProxyFileDescriptorCallback;
import android.os.ParcelFileDescriptor;
+import android.os.ProxyFileDescriptorCallback;
import android.system.ErrnoException;
-import android.system.Os;
-import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
import com.android.frameworks.coretests.R;
-import com.android.internal.os.FuseAppLoop;
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.util.concurrent.ThreadFactory;
-import java.io.File;
-import java.io.FileInputStream;
-import junit.framework.AssertionFailedError;
+import java.io.File;
+import java.util.concurrent.ThreadFactory;
public class StorageManagerIntegrationTest extends StorageManagerBaseTest {
-
- private static String LOG_TAG = "StorageManagerBaseTest.StorageManagerIntegrationTest";
- protected File mFile = null;
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setUp() throws Exception {
- super.setUp();
- mContext = getInstrumentation().getContext();
- mFile = null;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void tearDown() throws Exception {
- if (mFile != null) {
- mFile.delete();
- mFile = null;
- }
- super.tearDown();
- }
+ private static String LOG_TAG = "StorageManagerIntegrationTest";
/**
* Tests mounting a single OBB file and verifies its contents.
*/
@LargeTest
- public void testMountSingleObb() {
- mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1);
- String filePath = mFile.getAbsolutePath();
+ public void testMountSingleObb() throws Exception {
+ final File file = createObbFile(OBB_FILE_1, R.raw.obb_file1);
+ String filePath = file.getAbsolutePath();
mountObb(filePath);
verifyObb1Contents(filePath);
unmountObb(filePath, DONT_FORCE);
@@ -80,7 +46,7 @@
* Tests mounting several OBB files and verifies its contents.
*/
@LargeTest
- public void testMountMultipleObb() {
+ public void testMountMultipleObb() throws Exception {
File file1 = null;
File file2 = null;
File file3 = null;
@@ -120,9 +86,9 @@
* Tests mounting a single encrypted OBB file and verifies its contents.
*/
@LargeTest
- public void testMountSingleEncryptedObb() {
- mFile = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3);
- String filePath = mFile.getAbsolutePath();
+ public void testMountSingleEncryptedObb() throws Exception {
+ final File file = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3);
+ String filePath = file.getAbsolutePath();
mountObb(filePath, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED);
verifyObb3Contents(filePath);
unmountObb(filePath, DONT_FORCE);
@@ -132,19 +98,17 @@
* Tests mounting a single encrypted OBB file using an invalid password.
*/
@LargeTest
- @Suppress // Failing.
- public void testMountSingleEncryptedObbInvalidPassword() {
- mFile = createObbFile("bad password@$%#@^*(!&)", R.raw.obb_enc_file100_orig3);
- String filePath = mFile.getAbsolutePath();
- mountObb(filePath, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
- unmountObb(filePath, DONT_FORCE);
+ public void testMountSingleEncryptedObbInvalidPassword() throws Exception {
+ final File file = createObbFile("bad password@$%#@^*(!&)", R.raw.obb_enc_file100_orig3);
+ String filePath = file.getAbsolutePath();
+ mountObb(filePath, OBB_FILE_1_PASSWORD, OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
}
/**
* Tests simultaneously mounting 2 encrypted OBBs with different keys and verifies contents.
*/
@LargeTest
- public void testMountTwoEncryptedObb() {
+ public void testMountTwoEncryptedObb() throws Exception {
File file3 = null;
File file1 = null;
try {
@@ -174,9 +138,9 @@
* Tests that we can not force unmount when a file is currently open on the OBB.
*/
@LargeTest
- public void testUnmount_DontForce() {
- mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1);
- String obbFilePath = mFile.getAbsolutePath();
+ public void testUnmount_DontForce() throws Exception {
+ final File file = createObbFile(OBB_FILE_1, R.raw.obb_file1);
+ String obbFilePath = file.getAbsolutePath();
MountingObbThread mountingThread = new MountingObbThread(obbFilePath,
OBB_FILE_1_CONTENTS_1);
@@ -218,9 +182,9 @@
* Tests mounting a single OBB that isn't signed.
*/
@LargeTest
- public void testMountUnsignedObb() {
- mFile = createObbFile(OBB_FILE_2_UNSIGNED, R.raw.obb_file2_nosign);
- String filePath = mFile.getAbsolutePath();
+ public void testMountUnsignedObb() throws Exception {
+ final File file = createObbFile(OBB_FILE_2_UNSIGNED, R.raw.obb_file2_nosign);
+ String filePath = file.getAbsolutePath();
mountObb(filePath, OBB_FILE_2_UNSIGNED, OnObbStateChangeListener.ERROR_INTERNAL);
}
@@ -228,9 +192,9 @@
* Tests mounting a single OBB that is signed with a different package.
*/
@LargeTest
- public void testMountBadPackageNameObb() {
- mFile = createObbFile(OBB_FILE_3_BAD_PACKAGENAME, R.raw.obb_file3_bad_packagename);
- String filePath = mFile.getAbsolutePath();
+ public void testMountBadPackageNameObb() throws Exception {
+ final File file = createObbFile(OBB_FILE_3_BAD_PACKAGENAME, R.raw.obb_file3_bad_packagename);
+ String filePath = file.getAbsolutePath();
mountObb(filePath, OBB_FILE_3_BAD_PACKAGENAME,
OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
}
@@ -239,9 +203,9 @@
* Tests remounting a single OBB that has already been mounted.
*/
@LargeTest
- public void testRemountObb() {
- mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1);
- String filePath = mFile.getAbsolutePath();
+ public void testRemountObb() throws Exception {
+ final File file = createObbFile(OBB_FILE_1, R.raw.obb_file1);
+ String filePath = file.getAbsolutePath();
mountObb(filePath);
verifyObb1Contents(filePath);
mountObb(filePath, null, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
@@ -291,4 +255,4 @@
return thread;
}
}
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/src/android/text/StaticLayoutLineBreakingTest.java b/core/tests/coretests/src/android/text/StaticLayoutLineBreakingTest.java
index 2ee855e..5f2b9e5 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutLineBreakingTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutLineBreakingTest.java
@@ -18,6 +18,9 @@
import static org.junit.Assert.assertEquals;
+import android.content.Context;;
+import android.graphics.Typeface;
+import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.Layout.Alignment;
@@ -45,57 +48,24 @@
private static final int[] NO_BREAK = new int[] {};
- private static final TextPaint sTextPaint = new MockTextPaint();
+ private static final TextPaint sTextPaint = new TextPaint();
- private static class MockTextPaint extends TextPaint {
-
- @Override
- public float getTextRunAdvances(char[] chars, int index, int count,
- int contextIndex, int contextCount, boolean isRtl, float[] advances,
- int advancesIndex) {
-
- // Conditions copy pasted from Paint
- if (chars == null) {
- throw new IllegalArgumentException("text cannot be null");
- }
-
- if ((index | count | contextIndex | contextCount | advancesIndex
- | (index - contextIndex) | (contextCount - count)
- | ((contextIndex + contextCount) - (index + count))
- | (chars.length - (contextIndex + contextCount))
- | (advances == null ? 0 :
- (advances.length - (advancesIndex + count)))) < 0) {
- throw new IndexOutOfBoundsException();
- }
-
- float res = 0.0f;
-
- if (advances != null) {
- for (int i = 0; i < count; i++) {
- float width = getCharWidth(chars[index + i]);
- advances[advancesIndex + i] = width;
- res += width;
- }
- }
-
- return res;
- }
- }
-
- private static float getCharWidth(char c) {
- switch (Character.toUpperCase(c)) {
- // Roman figures
- case 'I': return 1.0f;
- case 'V': return 5.0f;
- case 'X': return 10.0f;
- case 'L': return 50.0f;
- case 'C': return 100.0f; // equals to WIDTH
- case ' ': return 10.0f;
- case '_': return 0.0f; // 0-width character
- case SURR_FIRST: return 7.0f;
- case SURR_SECOND: return 3.0f; // Sum of SURR_FIRST-SURR_SECOND is 10
- default: return 10.0f;
- }
+ static {
+ // The test font has following coverage and width.
+ // U+0020: 10em
+ // U+002E (,): 10em
+ // U+0043 (C): 100em
+ // U+0049 (I): 1em
+ // U+004C (L): 50em
+ // U+0056 (V): 5em
+ // U+0058 (X): 10em
+ // U+005F (_): 0em
+ // U+FFFD (invalid surrogate will be replaced to this): 7em
+ // U+10331 (\uD800\uDF31): 10em
+ Context context = InstrumentationRegistry.getTargetContext();
+ sTextPaint.setTypeface(Typeface.createFromAsset(context.getAssets(),
+ "fonts/StaticLayoutLineBreakingTestFont.ttf"));
+ sTextPaint.setTextSize(1.0f); // Make 1em == 1px.
}
private static StaticLayout getStaticLayout(CharSequence source, int width) {
@@ -406,13 +376,13 @@
public void testWithSurrogate() {
layout("LX" + SURR_FIRST + SURR_SECOND, NO_BREAK);
layout("LXXXX" + SURR_FIRST + SURR_SECOND, NO_BREAK);
- // LXXXXI (91) + SURR_FIRST (7) fits. But we should not break the surrogate pair
- // Bug: surrogate pair is broken, should be 6 (breaking after the 'V')
- // Maybe not: may be ok if the second character of a pair always has a 0-width
- layout("LXXXXI" + SURR_FIRST + SURR_SECOND, new int[] {7});
+ // LXXXXI (91) + SURR_FIRST + SURR_SECOND (10). Do not break in the middle point of
+ // surrogatge pair.
+ layout("LXXXXI" + SURR_FIRST + SURR_SECOND, new int[] {6});
- // LXXXXI (95) + SURR_SECOND (3) fits, but this is not a valid surrogate pair, breaking it
- layout("LXXXXV" + SURR_SECOND + SURR_FIRST, new int[] {7});
+ // LXXXXI (91) + SURR_SECOND (replaced with REPLACEMENT CHARACTER. width is 7px) fits.
+ // Break just after invalid trailing surrogate.
+ layout("LXXXXI" + SURR_SECOND + SURR_FIRST, new int[] {7});
layout("C" + SURR_FIRST + SURR_SECOND, new int[] {1});
}
diff --git a/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java b/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java
index b881053..28a3b67 100644
--- a/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java
+++ b/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java
@@ -18,6 +18,8 @@
import static org.junit.Assert.assertEquals;
+import static java.util.function.Function.identity;
+
import android.graphics.PointF;
import android.graphics.RectF;
@@ -105,7 +107,7 @@
final PointF point = new PointF(pointX, pointY);
final PointF adjustedPoint =
SelectionActionModeHelper.movePointInsideNearestRectangle(point,
- mRectFList);
+ mRectFList, identity());
assertEquals(expectedPointX, adjustedPoint.x, 0.0f);
assertEquals(expectedPointY, adjustedPoint.y, 0.0f);
@@ -254,7 +256,8 @@
final List<RectF> result = new ArrayList<>();
final int size = inputRectangles.length;
for (int index = 0; index < size; ++index) {
- SelectionActionModeHelper.mergeRectangleIntoList(result, inputRectangles[index]);
+ SelectionActionModeHelper.mergeRectangleIntoList(result, inputRectangles[index],
+ identity(), identity());
}
assertEquals(expectedOutput, result);
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index 2784193..c5e112b 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -33,29 +33,17 @@
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
- -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-
-#################################
-include $(BUILD_SYSTEM)/configure_local_jack.mk
-#################################
-
-ifdef LOCAL_JACK_ENABLED
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
-endif
LOCAL_MIN_SDK_VERSION := 8
include $(BUILD_PACKAGE)
-ifndef LOCAL_JACK_ENABLED
$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
$(hide) mkdir -p $(dir $@)
$(MAINDEXCLASSES) $< 1>$@
echo "com/android/multidexlegacytestapp/Test.class" >> $@
$(built_dex_intermediate): $(mainDexList)
-endif
## The application with a full main dex
include $(CLEAR_VARS)
@@ -76,26 +64,14 @@
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList2)
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=multidex -D jack.preprocessor=true\
- -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-
-#################################
-include $(BUILD_SYSTEM)/configure_local_jack.mk
-#################################
-
-ifdef LOCAL_JACK_ENABLED
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
-endif
LOCAL_MIN_SDK_VERSION := 8
include $(BUILD_PACKAGE)
-ifndef LOCAL_JACK_ENABLED
$(mainDexList2): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
$(hide) mkdir -p $(dir $@)
$(MAINDEXCLASSES) $< 1>$@
echo "com/android/multidexlegacytestapp/Test.class" >> $@
$(built_dex_intermediate): $(mainDexList2)
-endif
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/test.jpp b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/test.jpp
deleted file mode 100644
index a1f5656..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/test.jpp
+++ /dev/null
@@ -1,3 +0,0 @@
-test:
- @@com.android.jack.annotations.ForceInMainDex
- class com.android.multidexlegacytestapp.Test
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
index 1c7d807..da48df9 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
@@ -32,24 +32,12 @@
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
- -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-
-#################################
-include $(BUILD_SYSTEM)/configure_local_jack.mk
-#################################
-
-ifdef LOCAL_JACK_ENABLED
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
-endif
include $(BUILD_PACKAGE)
-ifndef LOCAL_JACK_ENABLED
$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
$(hide) mkdir -p $(dir $@)
$(MAINDEXCLASSES) $< 1>$@
echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
$(built_dex_intermediate): $(mainDexList)
-endif
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/test.jpp b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/test.jpp
deleted file mode 100644
index 6d384e3..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/test.jpp
+++ /dev/null
@@ -1,3 +0,0 @@
-test:
- @@com.android.jack.annotations.ForceInMainDex
- class com.android.framework.multidexlegacyversionedtestapp.MultiDexUpdateTest
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
index b77cf31..02b3f53 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
@@ -32,24 +32,12 @@
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
- -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-
-#################################
-include $(BUILD_SYSTEM)/configure_local_jack.mk
-#################################
-
-ifdef LOCAL_JACK_ENABLED
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
-endif
include $(BUILD_PACKAGE)
-ifndef LOCAL_JACK_ENABLED
$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
$(hide) mkdir -p $(dir $@)
$(MAINDEXCLASSES) $< 1>$@
echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
$(built_dex_intermediate): $(mainDexList)
-endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/test.jpp b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/test.jpp
deleted file mode 100644
index 6d384e3..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/test.jpp
+++ /dev/null
@@ -1,3 +0,0 @@
-test:
- @@com.android.jack.annotations.ForceInMainDex
- class com.android.framework.multidexlegacyversionedtestapp.MultiDexUpdateTest
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
index 3631626..4808684 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
@@ -32,25 +32,13 @@
LOCAL_DEX_PREOPT := false
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
- -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-
-#################################
-include $(BUILD_SYSTEM)/configure_local_jack.mk
-#################################
-
-ifdef LOCAL_JACK_ENABLED
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
-endif
include $(BUILD_PACKAGE)
-ifndef LOCAL_JACK_ENABLED
$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
$(hide) mkdir -p $(dir $@)
$(MAINDEXCLASSES) $< 1>$@
echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
$(built_dex_intermediate): $(mainDexList)
-endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/test.jpp b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/test.jpp
deleted file mode 100644
index 6d384e3..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/test.jpp
+++ /dev/null
@@ -1,3 +0,0 @@
-test:
- @@com.android.jack.annotations.ForceInMainDex
- class com.android.framework.multidexlegacyversionedtestapp.MultiDexUpdateTest
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 7a2df85..9948f7e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -64,7 +64,7 @@
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
</privapp-permissions>
- <privapp-permissions package="com.android.launcher">
+ <privapp-permissions package="com.android.launcher3">
<permission name="android.permission.BIND_APPWIDGET"/>
<permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
</privapp-permissions>
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index 0209cea..40288f5 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -159,8 +159,10 @@
if (mNativeInstance == 0) {
mNativeInstance = createNativeInstance(mLocalMatrix == null
? 0 : mLocalMatrix.native_instance);
- mCleaner = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
- this, mNativeInstance);
+ if (mNativeInstance != 0) {
+ mCleaner = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+ this, mNativeInstance);
+ }
}
return mNativeInstance;
}
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index 6bd2646..3bf4f90 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -104,7 +104,7 @@
final AnimatorSet set = new AnimatorSet();
// Linear exit after enter is completed.
- final ObjectAnimator exit = ObjectAnimator.ofFloat(this, RippleBackground.OPACITY, 0);
+ final ObjectAnimator exit = ObjectAnimator.ofFloat(this, OPACITY, 0);
exit.setInterpolator(LINEAR_INTERPOLATOR);
exit.setDuration(OPACITY_EXIT_DURATION);
exit.setAutoCancel(true);
@@ -115,7 +115,7 @@
final int fastEnterDuration = mIsBounded ?
(int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST) : 0;
if (fastEnterDuration > 0) {
- final ObjectAnimator enter = ObjectAnimator.ofFloat(this, RippleBackground.OPACITY, 1);
+ final ObjectAnimator enter = ObjectAnimator.ofFloat(this, OPACITY, 1);
enter.setInterpolator(LINEAR_INTERPOLATOR);
enter.setDuration(fastEnterDuration);
enter.setAutoCancel(true);
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 8f314c9..b090681 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -266,8 +266,9 @@
}
}
- setRippleActive(enabled && pressed);
- setBackgroundActive(hovered || focused || (enabled && pressed), focused || hovered);
+ setRippleActive(focused || (enabled && pressed));
+
+ setBackgroundActive(hovered, hovered);
return changed;
}
@@ -693,7 +694,9 @@
// have a mask or content and the ripple bounds if we're projecting.
final Rect bounds = getDirtyBounds();
final int saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
- canvas.clipRect(bounds);
+ if (isBounded()) {
+ canvas.clipRect(bounds);
+ }
drawContent(canvas);
drawBackgroundAndRipples(canvas);
diff --git a/graphics/java/android/graphics/drawable/RippleForeground.java b/graphics/java/android/graphics/drawable/RippleForeground.java
index 829733e..0de3f11 100644
--- a/graphics/java/android/graphics/drawable/RippleForeground.java
+++ b/graphics/java/android/graphics/drawable/RippleForeground.java
@@ -80,9 +80,6 @@
private float mTweenX = 0;
private float mTweenY = 0;
- /** Whether this ripple is bounded. */
- private boolean mIsBounded;
-
/** Whether this ripple has finished its exit animation. */
private boolean mHasFinishedExit;
@@ -90,7 +87,6 @@
boolean isBounded, boolean forceSoftware) {
super(owner, bounds, forceSoftware);
- mIsBounded = isBounded;
mStartingX = startingX;
mStartingY = startingY;
@@ -162,11 +158,6 @@
@Override
protected Animator createSoftwareEnter(boolean fast) {
- // Bounded ripples don't have enter animations.
- if (mIsBounded) {
- return null;
- }
-
final int duration = (int)
(1000 * Math.sqrt(mTargetRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensityScale) + 0.5);
@@ -215,31 +206,15 @@
return (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
}
- /**
- * Compute target values that are dependent on bounding.
- */
- private void computeBoundedTargetValues() {
- mTargetX = (mClampedStartingX - mBounds.exactCenterX()) * .7f;
- mTargetY = (mClampedStartingY - mBounds.exactCenterY()) * .7f;
- mTargetRadius = mBoundedRadius;
- }
-
@Override
protected Animator createSoftwareExit() {
final int radiusDuration;
final int originDuration;
final int opacityDuration;
- if (mIsBounded) {
- computeBoundedTargetValues();
- radiusDuration = BOUNDED_RADIUS_EXIT_DURATION;
- originDuration = BOUNDED_ORIGIN_EXIT_DURATION;
- opacityDuration = BOUNDED_OPACITY_EXIT_DURATION;
- } else {
- radiusDuration = getRadiusExitDuration();
- originDuration = radiusDuration;
- opacityDuration = getOpacityExitDuration();
- }
+ radiusDuration = getRadiusExitDuration();
+ originDuration = radiusDuration;
+ opacityDuration = getOpacityExitDuration();
final ObjectAnimator tweenRadius = ObjectAnimator.ofFloat(this, TWEEN_RADIUS, 1);
tweenRadius.setAutoCancel(true);
@@ -268,17 +243,10 @@
final int radiusDuration;
final int originDuration;
final int opacityDuration;
- if (mIsBounded) {
- computeBoundedTargetValues();
- radiusDuration = BOUNDED_RADIUS_EXIT_DURATION;
- originDuration = BOUNDED_ORIGIN_EXIT_DURATION;
- opacityDuration = BOUNDED_OPACITY_EXIT_DURATION;
- } else {
- radiusDuration = getRadiusExitDuration();
- originDuration = radiusDuration;
- opacityDuration = getOpacityExitDuration();
- }
+ radiusDuration = getRadiusExitDuration();
+ originDuration = radiusDuration;
+ opacityDuration = getOpacityExitDuration();
final float startX = getCurrentX();
final float startY = getCurrentY();
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index e764034..c4c14c9e 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -79,7 +79,7 @@
"libutils",
],
shared_libs: [
- "libz-host",
+ "libz",
],
},
windows: {
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index a5b1d29..0e577d1 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -30,6 +30,8 @@
namespace android {
+ApkAssets::ApkAssets() : zip_handle_(nullptr, ::CloseArchive) {}
+
std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system) {
return ApkAssets::LoadImpl(path, system, false /*load_as_shared_library*/);
}
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index ab7e14d..f1f2e2d 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -902,26 +902,32 @@
return true;
}
- if (asset_manager_ != o.asset_manager_) {
- return false;
- }
-
type_spec_flags_ = o.type_spec_flags_;
+ const bool copy_only_system = asset_manager_ != o.asset_manager_;
+
for (size_t p = 0; p < packages_.size(); p++) {
const Package* package = o.packages_[p].get();
- if (package == nullptr) {
+ if (package == nullptr || (copy_only_system && p != 0x01)) {
+ // The other theme doesn't have this package, clear ours.
packages_[p].reset();
continue;
}
+ if (packages_[p] == nullptr) {
+ // The other theme has this package, but we don't. Make one.
+ packages_[p].reset(new Package());
+ }
+
for (size_t t = 0; t < package->types.size(); t++) {
const Type* type = package->types[t].get();
if (type == nullptr) {
+ // The other theme doesn't have this type, clear ours.
packages_[p]->types[t].reset();
continue;
}
+ // Create a new type and update it to theirs.
const size_t type_alloc_size = sizeof(Type) + (type->entry_capacity * sizeof(Entry));
void* copied_data = malloc(type_alloc_size);
memcpy(copied_data, type, type_alloc_size);
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index b7e66fb..2e392d5 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -21,7 +21,6 @@
#include <string>
#include "android-base/macros.h"
-#include "ziparchive/zip_archive.h"
#include "androidfw/Asset.h"
#include "androidfw/LoadedArsc.h"
@@ -52,14 +51,9 @@
static std::unique_ptr<const ApkAssets> LoadImpl(const std::string& path, bool system,
bool load_as_shared_library);
- ApkAssets() = default;
+ ApkAssets();
- struct ZipArchivePtrCloser {
- void operator()(::ZipArchiveHandle handle) { ::CloseArchive(handle); }
- };
-
- using ZipArchivePtr =
- std::unique_ptr<typename std::remove_pointer<::ZipArchiveHandle>::type, ZipArchivePtrCloser>;
+ using ZipArchivePtr = std::unique_ptr<void, void(*)(void*)>;
ZipArchivePtr zip_handle_;
std::string path_;
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index d2bc6ee..fd94144 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -70,9 +70,8 @@
};
// AssetManager2 is the main entry point for accessing assets and resources.
-// AssetManager2 provides caching of resources retrieved via the underlying
-// ApkAssets.
-class AssetManager2 : public ::AAssetManager {
+// AssetManager2 provides caching of resources retrieved via the underlying ApkAssets.
+class AssetManager2 {
public:
struct ResourceName {
const char* package = nullptr;
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index dfff9c0..feb454e 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -23,6 +23,7 @@
#include "data/lib_one/R.h"
#include "data/libclient/R.h"
#include "data/styles/R.h"
+#include "data/system/R.h"
namespace app = com::android::app;
namespace lib_one = com::android::lib_one;
@@ -33,6 +34,9 @@
class ThemeTest : public ::testing::Test {
public:
void SetUp() override {
+ system_assets_ = ApkAssets::Load(GetTestDataPath() + "/system/system.apk", true /*system*/);
+ ASSERT_NE(nullptr, system_assets_);
+
style_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
ASSERT_NE(nullptr, style_assets_);
@@ -47,6 +51,7 @@
}
protected:
+ std::unique_ptr<const ApkAssets> system_assets_;
std::unique_ptr<const ApkAssets> style_assets_;
std::unique_ptr<const ApkAssets> libclient_assets_;
std::unique_ptr<const ApkAssets> lib_one_assets_;
@@ -262,20 +267,30 @@
EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
}
-TEST_F(ThemeTest, FailToCopyThemeWithDifferentAssetManager) {
+TEST_F(ThemeTest, OnlyCopySystemThemeWhenAssetManagersDiffer) {
AssetManager2 assetmanager_one;
- assetmanager_one.SetApkAssets({style_assets_.get()});
+ assetmanager_one.SetApkAssets({system_assets_.get(), style_assets_.get()});
AssetManager2 assetmanager_two;
- assetmanager_two.SetApkAssets({style_assets_.get()});
+ assetmanager_two.SetApkAssets({system_assets_.get(), style_assets_.get()});
auto theme_one = assetmanager_one.NewTheme();
ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne));
auto theme_two = assetmanager_two.NewTheme();
+ ASSERT_TRUE(theme_two->ApplyStyle(R::style::Theme_One));
ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleTwo));
- EXPECT_FALSE(theme_one->SetTo(*theme_two));
+ EXPECT_TRUE(theme_one->SetTo(*theme_two));
+
+ Res_value value;
+ uint32_t flags;
+
+ // No app resources.
+ EXPECT_EQ(kInvalidCookie, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags));
+
+ // Only system.
+ EXPECT_NE(kInvalidCookie, theme_one->GetAttribute(R::attr::foreground, &value, &flags));
}
} // namespace android
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index f5bb821..69ead58 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -71,9 +71,11 @@
void AnimatorManager::pushStaging() {
if (mNewAnimators.size()) {
- LOG_ALWAYS_FATAL_IF(!mAnimationHandle,
- "Trying to start new animators on %p (%s) without an animation handle!",
- &mParent, mParent.getName());
+ if (CC_UNLIKELY(!mAnimationHandle)) {
+ ALOGW("Trying to start new animators on %p (%s) without an animation handle!",
+ &mParent, mParent.getName());
+ return;
+ }
// Only add new animators that are not already in the mAnimators list
for (auto& anim : mNewAnimators) {
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index 2b29542..a5b4c42 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -104,14 +104,14 @@
std::shared_ptr<minikin::MinikinFont> MinikinFontSkia::createFontWithVariation(
const std::vector<minikin::FontVariation>& variations) const {
- SkFontMgr::FontParameters params;
+ SkFontArguments params;
int ttcIndex;
- SkStreamAsset* stream = mTypeface->openStream(&ttcIndex);
+ std::unique_ptr<SkStreamAsset> stream(mTypeface->openStream(&ttcIndex));
LOG_ALWAYS_FATAL_IF(stream == nullptr, "openStream failed");
params.setCollectionIndex(ttcIndex);
- std::vector<SkFontMgr::FontParameters::Axis> skAxes;
+ std::vector<SkFontArguments::Axis> skAxes;
skAxes.resize(variations.size());
for (size_t i = 0; i < variations.size(); i++) {
skAxes[i].fTag = variations[i].axisTag;
@@ -119,7 +119,7 @@
}
params.setAxes(skAxes.data(), skAxes.size());
sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
- sk_sp<SkTypeface> face(fm->createFromStream(stream, params));
+ sk_sp<SkTypeface> face(fm->makeFromStream(std::move(stream), params));
return std::make_shared<MinikinFontSkia>(std::move(face), mFontData, mFontSize, ttcIndex,
variations);
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 17438e5..5c6078d 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -36,22 +36,18 @@
bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer) {
// transform the matrix based on the layer
- int saveCount = -1;
- if (!layer->getTransform().isIdentity()) {
- saveCount = canvas->save();
- SkMatrix transform;
- layer->getTransform().copyTo(transform);
- canvas->concat(transform);
- }
-
+ SkMatrix layerTransform;
+ layer->getTransform().copyTo(layerTransform);
sk_sp<SkImage> layerImage;
+ int layerWidth = layer->getWidth();
+ int layerHeight = layer->getHeight();
if (layer->getApi() == Layer::Api::OpenGL) {
GlLayer* glLayer = static_cast<GlLayer*>(layer);
GrGLTextureInfo externalTexture;
externalTexture.fTarget = glLayer->getRenderTarget();
externalTexture.fID = glLayer->getTextureId();
- GrBackendTexture backendTexture(glLayer->getWidth(), glLayer->getHeight(),
- kRGBA_8888_GrPixelConfig, externalTexture);
+ GrBackendTexture backendTexture(layerWidth, layerHeight, kRGBA_8888_GrPixelConfig,
+ externalTexture);
layerImage = SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin,
kPremul_SkAlphaType, nullptr);
} else {
@@ -62,15 +58,29 @@
}
if (layerImage) {
+ SkMatrix textureMatrix;
+ layer->getTexTransform().copyTo(textureMatrix);
+ //TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
+ // use bottom left origin and remove flipV and invert transformations.
+ SkMatrix flipV;
+ flipV.setAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
+ textureMatrix.preConcat(flipV);
+ textureMatrix.preScale(1.0f/layerWidth, 1.0f/layerHeight);
+ textureMatrix.postScale(layerWidth, layerHeight);
+ SkMatrix textureMatrixInv;
+ if (!textureMatrix.invert(&textureMatrixInv)) {
+ textureMatrixInv = textureMatrix;
+ }
+
+ SkMatrix matrix = SkMatrix::Concat(textureMatrixInv, layerTransform);
+
SkPaint paint;
paint.setAlpha(layer->getAlpha());
paint.setBlendMode(layer->getMode());
paint.setColorFilter(sk_ref_sp(layer->getColorFilter()));
- canvas->drawImage(layerImage, 0, 0, &paint);
- }
- // restore the original matrix
- if (saveCount >= 0) {
- canvas->restoreToCount(saveCount);
+ // draw image with a shader to avoid save/restore of the matrix
+ paint.setShader(layerImage->makeShader(&matrix));
+ canvas->drawRect(SkRect::MakeWH(layerWidth, layerHeight), paint);
}
return layerImage;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 6f117de..c4bd1e1 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -45,6 +45,10 @@
mVectorDrawables.reserve(30);
}
+SkiaPipeline::~SkiaPipeline() {
+ unpinImages();
+}
+
TaskManager* SkiaPipeline::getTaskManager() {
return mRenderThread.cacheManager().getTaskManager();
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 2b0c419..3e6ae30 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -28,7 +28,7 @@
class SkiaPipeline : public renderthread::IRenderPipeline {
public:
SkiaPipeline(renderthread::RenderThread& thread);
- virtual ~SkiaPipeline() {}
+ virtual ~SkiaPipeline();
TaskManager* getTaskManager() override;
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
index 345cfd6..439d690 100644
--- a/libs/hwui/tests/unit/TypefaceTests.cpp
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -52,7 +52,7 @@
SkData::MakeWithProc(data, st.st_size, unmap, reinterpret_cast<void*>(st.st_size));
std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(skData));
sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
- sk_sp<SkTypeface> typeface(fm->createFromStream(fontData.release()));
+ sk_sp<SkTypeface> typeface(fm->makeFromStream(std::move(fontData)));
LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", fileName);
std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
diff --git a/libs/protoutil/Android.mk b/libs/protoutil/Android.mk
new file mode 100644
index 0000000..a534816
--- /dev/null
+++ b/libs/protoutil/Android.mk
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotoutil
+
+LOCAL_CFLAGS := \
+ -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ liblog \
+ libutils
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include
+
+LOCAL_SRC_FILES := \
+ src/EncodedBuffer.cpp \
+ src/protobuf.cpp \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/libs/protoutil/include/android/util/EncodedBuffer.h b/libs/protoutil/include/android/util/EncodedBuffer.h
new file mode 100644
index 0000000..cf09609
--- /dev/null
+++ b/libs/protoutil/include/android/util/EncodedBuffer.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UTIL_ENCODED_BUFFER_H
+#define ANDROID_UTIL_ENCODED_BUFFER_H
+
+#include <stdint.h>
+#include <vector>
+
+namespace android {
+namespace util {
+
+using namespace std;
+
+/**
+ * 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: Index of a buffer within the mBuffers list.
+ * *Offset: Position within a buffer.
+ */
+class EncodedBuffer
+{
+public:
+ EncodedBuffer();
+ EncodedBuffer(size_t chunkSize);
+ ~EncodedBuffer();
+
+ class Pointer {
+ public:
+ Pointer();
+ Pointer(size_t chunkSize);
+
+ size_t pos() const;
+ size_t index() const;
+ size_t offset() const;
+
+ void move(size_t amt);
+ inline void move() { move(1); };
+
+ void rewind();
+ Pointer copy() const;
+
+ private:
+ size_t mChunkSize;
+ size_t mIndex;
+ size_t mOffset;
+ };
+
+ /******************************** Write APIs ************************************************/
+
+ /**
+ * Returns the number of bytes written in the buffer
+ */
+ size_t size() const;
+
+ /**
+ * Returns the write pointer.
+ */
+ Pointer* wp();
+
+ /**
+ * Returns the current position of write pointer, if the write buffer is full, it will automatically
+ * rotate to a new buffer with given chunkSize. If NULL is returned, it means NO_MEMORY
+ */
+ uint8_t* writeBuffer();
+
+ /**
+ * Returns the writeable size in the current write buffer .
+ */
+ size_t currentToWrite();
+
+ /**
+ * Write a varint into a vector. Return the size of the varint.
+ */
+ size_t writeRawVarint(uint32_t val);
+
+ /**
+ * Write a protobuf header. Return the size of the header.
+ */
+ size_t writeHeader(uint32_t fieldId, uint8_t wireType);
+
+ /********************************* Read APIs ************************************************/
+ class iterator;
+ friend class iterator;
+ class iterator {
+ public:
+ iterator(const EncodedBuffer& buffer);
+
+ /**
+ * Returns the number of bytes written in the buffer
+ */
+ size_t size() const;
+
+ /**
+ * Returns the size of total bytes read.
+ */
+ size_t bytesRead() const;
+
+ /**
+ * Returns the read pointer.
+ */
+ Pointer* rp();
+
+ /**
+ * Returns the current position of read pointer, if NULL is returned, it reaches end of buffer.
+ */
+ uint8_t const* readBuffer();
+
+ /**
+ * Returns the readable size in the current read buffer.
+ */
+ size_t currentToRead();
+
+ /**
+ * Returns true if next bytes is available for read.
+ */
+ bool hasNext();
+
+ /**
+ * Reads the current byte and moves pointer 1 bit.
+ */
+ uint8_t next();
+
+ /**
+ * Read varint from iterator, the iterator will point to next available byte.
+ * Return the number of bytes of the varint.
+ */
+ uint32_t readRawVarint();
+
+ private:
+ const EncodedBuffer& mData;
+ Pointer mRp;
+ };
+
+ /**
+ * Returns the iterator of EncodedBuffer so it guarantees consumers won't be able to modified the buffer.
+ */
+ iterator begin() const;
+
+private:
+ size_t mChunkSize;
+ vector<uint8_t*> mBuffers;
+
+ Pointer mWp;
+
+ inline uint8_t* at(const Pointer& p) const; // helper function to get value
+};
+
+} // util
+} // android
+
+#endif // ANDROID_UTIL_ENCODED_BUFFER_H
\ No newline at end of file
diff --git a/cmds/incidentd/src/protobuf.h b/libs/protoutil/include/android/util/protobuf.h
similarity index 74%
rename from cmds/incidentd/src/protobuf.h
rename to libs/protoutil/include/android/util/protobuf.h
index 263c864..f4e8d09 100644
--- a/cmds/incidentd/src/protobuf.h
+++ b/libs/protoutil/include/android/util/protobuf.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-#ifndef PROTOBUF_H
-#define PROTOBUF_H
+#ifndef ANDROID_UTIL_PROTOBUF_H
+#define ANDROID_UTIL_PROTOBUF_H
#include <stdint.h>
-#include <vector>
+
+namespace android {
+namespace util {
using namespace std;
@@ -50,19 +52,7 @@
*/
uint8_t* write_length_delimited_tag_header(uint8_t* buf, uint32_t fieldId, size_t size);
-/**
- * Write a varint into a vector. Return the size of the varint.
- */
-size_t write_raw_varint(vector<uint8_t>* buf, uint32_t val);
+} // util
+} // android
-/**
- * Write a protobuf header. Return the size of the header.
- */
-size_t write_header(vector<uint8_t>* buf, uint32_t fieldId, uint8_t wireType);
-
-enum {
- // IncidentProto.header
- FIELD_ID_INCIDENT_HEADER = 1
-};
-
-#endif // PROTOBUF_H
+#endif // ANDROID_UTIL_PROTOUBUF_H
diff --git a/libs/protoutil/src/EncodedBuffer.cpp b/libs/protoutil/src/EncodedBuffer.cpp
new file mode 100644
index 0000000..84dc5b6
--- /dev/null
+++ b/libs/protoutil/src/EncodedBuffer.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/util/EncodedBuffer.h>
+
+#include <stdlib.h>
+
+namespace android {
+namespace util {
+
+const size_t BUFFER_SIZE = 8 * 1024; // 8 KB
+
+EncodedBuffer::Pointer::Pointer() : Pointer(BUFFER_SIZE)
+{
+}
+
+EncodedBuffer::Pointer::Pointer(size_t chunkSize)
+ :mIndex(0),
+ mOffset(0)
+{
+ mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
+}
+
+size_t
+EncodedBuffer::Pointer::pos() const
+{
+ return mIndex * mChunkSize + mOffset;
+}
+
+size_t
+EncodedBuffer::Pointer::index() const
+{
+ return mIndex;
+}
+
+size_t
+EncodedBuffer::Pointer::offset() const
+{
+ return mOffset;
+}
+
+void
+EncodedBuffer::Pointer::move(size_t amt)
+{
+ size_t newOffset = mOffset + amt;
+ mIndex += newOffset / mChunkSize;
+ mOffset = newOffset % mChunkSize;
+}
+
+void
+EncodedBuffer::Pointer::rewind()
+{
+ mIndex = 0;
+ mOffset = 0;
+}
+
+EncodedBuffer::Pointer
+EncodedBuffer::Pointer::copy() const
+{
+ Pointer p = Pointer(mChunkSize);
+ p.mIndex = mIndex;
+ p.mOffset = mOffset;
+ return p;
+}
+
+// ===========================================================
+EncodedBuffer::EncodedBuffer() : EncodedBuffer(0)
+{
+}
+
+EncodedBuffer::EncodedBuffer(size_t chunkSize)
+ :mBuffers()
+{
+ mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
+ mWp = Pointer(mChunkSize);
+}
+
+EncodedBuffer::~EncodedBuffer()
+{
+ for (size_t i=0; i<mBuffers.size(); i++) {
+ uint8_t* buf = mBuffers[i];
+ free(buf);
+ }
+}
+
+inline uint8_t*
+EncodedBuffer::at(const Pointer& p) const
+{
+ return mBuffers[p.index()] + p.offset();
+}
+
+/******************************** Write APIs ************************************************/
+size_t
+EncodedBuffer::size() const
+{
+ return mWp.pos();
+}
+
+EncodedBuffer::Pointer*
+EncodedBuffer::wp()
+{
+ return &mWp;
+}
+
+uint8_t*
+EncodedBuffer::writeBuffer()
+{
+ // This prevents write pointer move too fast than allocating the buffer.
+ if (mWp.index() > mBuffers.size()) return NULL;
+ uint8_t* buf = NULL;
+ if (mWp.index() == mBuffers.size()) {
+ buf = (uint8_t*)malloc(mChunkSize);
+
+ if (buf == NULL) return NULL; // This indicates NO_MEMORY
+
+ mBuffers.push_back(buf);
+ }
+ return at(mWp);
+}
+
+size_t
+EncodedBuffer::currentToWrite()
+{
+ return mChunkSize - mWp.offset();
+}
+
+size_t
+EncodedBuffer::writeRawVarint(uint32_t val)
+{
+ size_t size = 0;
+ while (true) {
+ size++;
+ if ((val & ~0x7F) == 0) {
+ *writeBuffer() = (uint8_t) val;
+ mWp.move();
+ return size;
+ } else {
+ *writeBuffer() = (uint8_t)((val & 0x7F) | 0x80);
+ mWp.move();
+ val >>= 7;
+ }
+ }
+}
+
+size_t
+EncodedBuffer::writeHeader(uint32_t fieldId, uint8_t wireType)
+{
+ return writeRawVarint((fieldId << 3) | wireType);
+}
+
+/********************************* Read APIs ************************************************/
+EncodedBuffer::iterator
+EncodedBuffer::begin() const
+{
+ return EncodedBuffer::iterator(*this);
+}
+
+EncodedBuffer::iterator::iterator(const EncodedBuffer& buffer)
+ :mData(buffer),
+ mRp(buffer.mChunkSize)
+{
+}
+
+size_t
+EncodedBuffer::iterator::size() const
+{
+ return mData.size();
+}
+
+size_t
+EncodedBuffer::iterator::bytesRead() const
+{
+ return mRp.pos();
+}
+
+EncodedBuffer::Pointer*
+EncodedBuffer::iterator::rp()
+{
+ return &mRp;
+}
+
+uint8_t const*
+EncodedBuffer::iterator::readBuffer()
+{
+ return hasNext() ? const_cast<uint8_t const*>(mData.at(mRp)) : NULL;
+}
+
+size_t
+EncodedBuffer::iterator::currentToRead()
+{
+ return (mData.mWp.index() > mRp.index()) ?
+ mData.mChunkSize - mRp.offset() :
+ mData.mWp.offset() - mRp.offset();
+}
+
+bool
+EncodedBuffer::iterator::hasNext()
+{
+ return mRp.pos() < mData.mWp.pos();
+}
+
+uint8_t
+EncodedBuffer::iterator::next()
+{
+ uint8_t res = *(mData.at(mRp));
+ mRp.move();
+ return res;
+}
+
+uint32_t
+EncodedBuffer::iterator::readRawVarint()
+{
+ uint32_t val = 0, shift = 0;
+ while (true) {
+ uint8_t byte = next();
+ val += (byte & 0x7F) << shift;
+ if ((byte & 0x80) == 0) break;
+ shift += 7;
+ }
+ return val;
+}
+
+} // util
+} // android
diff --git a/cmds/incidentd/src/protobuf.cpp b/libs/protoutil/src/protobuf.cpp
similarity index 67%
rename from cmds/incidentd/src/protobuf.cpp
rename to libs/protoutil/src/protobuf.cpp
index 4fffec1..ec5325c 100644
--- a/cmds/incidentd/src/protobuf.cpp
+++ b/libs/protoutil/src/protobuf.cpp
@@ -14,14 +14,19 @@
* limitations under the License.
*/
-#include "protobuf.h"
+#include <android/util/protobuf.h>
-uint8_t read_wire_type(uint32_t varint)
+namespace android {
+namespace util {
+
+uint8_t
+read_wire_type(uint32_t varint)
{
return (uint8_t) (varint & 0x07);
}
-uint32_t read_field_id(uint32_t varint)
+uint32_t
+read_field_id(uint32_t varint)
{
return varint >> 3;
}
@@ -49,24 +54,5 @@
return buf;
}
-size_t
-write_raw_varint(vector<uint8_t>* buf, uint32_t val)
-{
- size_t size = 0;
- while (true) {
- size++;
- if ((val & ~0x7F) == 0) {
- buf->push_back((uint8_t) val);
- return size;
- } else {
- buf->push_back((uint8_t)((val & 0x7F) | 0x80));
- val >>= 7;
- }
- }
-}
-
-size_t
-write_header(vector<uint8_t>* buf, uint32_t fieldId, uint8_t wireType)
-{
- return write_raw_varint(buf, (fieldId << 3) | wireType);
-}
\ No newline at end of file
+} // util
+} // android
diff --git a/media/java/android/media/AmrInputStream.java b/media/java/android/media/AmrInputStream.java
index fb91bbb..13c3ac4 100644
--- a/media/java/android/media/AmrInputStream.java
+++ b/media/java/android/media/AmrInputStream.java
@@ -25,7 +25,7 @@
/**
- * AmrInputStream
+ * DO NOT USE
* @hide
*/
public final class AmrInputStream extends InputStream {
@@ -51,10 +51,10 @@
private byte[] mOneByte = new byte[1];
/**
- * Create a new AmrInputStream, which converts 16 bit PCM to AMR
- * @param inputStream InputStream containing 16 bit PCM.
+ * DO NOT USE - use MediaCodec instead
*/
public AmrInputStream(InputStream inputStream) {
+ Log.w(TAG, "@@@@ AmrInputStream is not a public API @@@@");
mInputStream = inputStream;
MediaFormat format = new MediaFormat();
@@ -83,17 +83,26 @@
mInfo = new BufferInfo();
}
+ /**
+ * DO NOT USE
+ */
@Override
public int read() throws IOException {
int rtn = read(mOneByte, 0, 1);
return rtn == 1 ? (0xff & mOneByte[0]) : -1;
}
+ /**
+ * DO NOT USE
+ */
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
+ /**
+ * DO NOT USE
+ */
@Override
public int read(byte[] b, int offset, int length) throws IOException {
if (mCodec == null) {
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index d733ad9..70ab863 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -600,14 +600,20 @@
@Override
public void onRestoreRoute() {
- // Skip restoring route if the selected route is not a system audio route, or
- // MediaRouter is initializing.
- if ((mSelectedRoute != mDefaultAudioVideo && mSelectedRoute != mBluetoothA2dpRoute)
- || mSelectedRoute == null) {
- return;
- }
- Log.v(TAG, "onRestoreRoute() : a2dp=" + isBluetoothA2dpOn());
- mSelectedRoute.select();
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ // Skip restoring route if the selected route is not a system audio route,
+ // MediaRouter is initializing, or mClient was changed.
+ if (Client.this != mClient || mSelectedRoute == null
+ || (mSelectedRoute != mDefaultAudioVideo
+ && mSelectedRoute != mBluetoothA2dpRoute)) {
+ return;
+ }
+ Log.v(TAG, "onRestoreRoute() : route=" + mSelectedRoute);
+ mSelectedRoute.select();
+ }
+ });
}
}
}
diff --git a/media/jni/android_media_MediaDescrambler.cpp b/media/jni/android_media_MediaDescrambler.cpp
index bee5218..e77e855 100644
--- a/media/jni/android_media_MediaDescrambler.cpp
+++ b/media/jni/android_media_MediaDescrambler.cpp
@@ -21,7 +21,7 @@
#include "android_media_MediaDescrambler.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_os_HwRemoteBinder.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include <android/hardware/cas/native/1.0/BpHwDescrambler.h>
#include <android/hardware/cas/native/1.0/BnHwDescrambler.h>
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index c9657b1..d2fa8f5 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -27,7 +27,7 @@
#include "android_runtime/Log.h"
#include "android_util_Binder.h"
#include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include <android/hardware/cas/1.0/BpHwCas.h>
#include <android/hardware/cas/1.0/BnHwCas.h>
diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/media/jni/android_media_MediaMetricsJNI.cpp
index 8979cec..38f7a7e 100644
--- a/media/jni/android_media_MediaMetricsJNI.cpp
+++ b/media/jni/android_media_MediaMetricsJNI.cpp
@@ -16,7 +16,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <jni.h>
-#include <JNIHelp.h>
+#include <nativehelper/JNIHelp.h>
#include "android_media_MediaMetricsJNI.h"
#include <media/MediaAnalyticsItem.h>
diff --git a/media/jni/android_media_MediaMetricsJNI.h b/media/jni/android_media_MediaMetricsJNI.h
index d174212..16081b4 100644
--- a/media/jni/android_media_MediaMetricsJNI.h
+++ b/media/jni/android_media_MediaMetricsJNI.h
@@ -19,7 +19,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <jni.h>
-#include <JNIHelp.h>
+#include <nativehelper/JNIHelp.h>
#include <media/MediaAnalyticsItem.h>
namespace android {
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index ceab478..497684c 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -35,7 +35,7 @@
#include <nativehelper/ScopedUtfChars.h>
#include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include "android_media_MediaMetricsJNI.h"
#include "android_runtime/AndroidRuntime.h"
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 3800e6f..4a771eb 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -16,8 +16,6 @@
package com.android.defcontainer;
-import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
-
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
@@ -31,21 +29,15 @@
import android.content.res.ObbInfo;
import android.content.res.ObbScanner;
import android.os.Binder;
-import android.os.Environment;
import android.os.Environment.UserEnvironment;
-import android.os.FileUtils;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.StructStatVfs;
import android.util.Slog;
import com.android.internal.app.IMediaContainerService;
-import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
import com.android.internal.os.IParcelFileDescriptorFactory;
import com.android.internal.util.ArrayUtils;
@@ -72,51 +64,6 @@
private IMediaContainerService.Stub mBinder = new IMediaContainerService.Stub() {
/**
- * Creates a new container and copies package there.
- *
- * @param packagePath absolute path to the package to be copied. Can be
- * a single monolithic APK file or a cluster directory
- * containing one or more APKs.
- * @param containerId the id of the secure container that should be used
- * for creating a secure container into which the resource
- * will be copied.
- * @param key Refers to key used for encrypting the secure container
- * @return Returns the new cache path where the resource has been copied
- * into
- */
- @Override
- public String copyPackageToContainer(String packagePath, String containerId, String key,
- boolean isExternal, boolean isForwardLocked, String abiOverride) {
- if (packagePath == null || containerId == null) {
- return null;
- }
-
- if (isExternal) {
- // Make sure the sdcard is mounted.
- String status = Environment.getExternalStorageState();
- if (!status.equals(Environment.MEDIA_MOUNTED)) {
- Slog.w(TAG, "Make sure sdcard is mounted.");
- return null;
- }
- }
-
- PackageLite pkg = null;
- NativeLibraryHelper.Handle handle = null;
- try {
- final File packageFile = new File(packagePath);
- pkg = PackageParser.parsePackageLite(packageFile, 0);
- handle = NativeLibraryHelper.Handle.create(pkg);
- return copyPackageToContainerInner(pkg, handle, containerId, key, isExternal,
- isForwardLocked, abiOverride);
- } catch (PackageParserException | IOException e) {
- Slog.w(TAG, "Failed to copy package at " + packagePath, e);
- return null;
- } finally {
- IoUtils.closeQuietly(handle);
- }
- }
-
- /**
* Copy package to the target location.
*
* @param packagePath absolute path to the package to be copied. Can be
@@ -153,7 +100,6 @@
public PackageInfoLite getMinimalPackageInfo(String packagePath, int flags,
String abiOverride) {
final Context context = DefaultContainerService.this;
- final boolean isForwardLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
PackageInfoLite ret = new PackageInfoLite();
if (packagePath == null) {
@@ -167,7 +113,7 @@
final long sizeBytes;
try {
pkg = PackageParser.parsePackageLite(packageFile, 0);
- sizeBytes = PackageHelper.calculateInstalledSize(pkg, isForwardLocked, abiOverride);
+ sizeBytes = PackageHelper.calculateInstalledSize(pkg, abiOverride);
} catch (PackageParserException | IOException e) {
Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);
@@ -230,13 +176,13 @@
* containing one or more APKs.
*/
@Override
- public long calculateInstalledSize(String packagePath, boolean isForwardLocked,
- String abiOverride) throws RemoteException {
+ public long calculateInstalledSize(String packagePath, String abiOverride)
+ throws RemoteException {
final File packageFile = new File(packagePath);
final PackageParser.PackageLite pkg;
try {
pkg = PackageParser.parsePackageLite(packageFile, 0);
- return PackageHelper.calculateInstalledSize(pkg, isForwardLocked, abiOverride);
+ return PackageHelper.calculateInstalledSize(pkg, abiOverride);
} catch (PackageParserException | IOException e) {
Slog.w(TAG, "Failed to calculate installed size: " + e);
return Long.MAX_VALUE;
@@ -292,60 +238,6 @@
return mBinder;
}
- private String copyPackageToContainerInner(PackageLite pkg, NativeLibraryHelper.Handle handle,
- String newCid, String key, boolean isExternal, boolean isForwardLocked,
- String abiOverride) throws IOException {
-
- // Calculate container size, rounding up to nearest MB and adding an
- // extra MB for filesystem overhead
- final long sizeBytes = PackageHelper.calculateInstalledSize(pkg, handle,
- isForwardLocked, abiOverride);
-
- // Create new container
- final String newMountPath = PackageHelper.createSdDir(sizeBytes, newCid, key,
- Process.myUid(), isExternal);
- if (newMountPath == null) {
- throw new IOException("Failed to create container " + newCid);
- }
- final File targetDir = new File(newMountPath);
-
- try {
- // Copy all APKs
- copyFile(pkg.baseCodePath, targetDir, "base.apk", isForwardLocked);
- if (!ArrayUtils.isEmpty(pkg.splitNames)) {
- for (int i = 0; i < pkg.splitNames.length; i++) {
- copyFile(pkg.splitCodePaths[i], targetDir,
- "split_" + pkg.splitNames[i] + ".apk", isForwardLocked);
- }
- }
-
- // Extract native code
- final File libraryRoot = new File(targetDir, LIB_DIR_NAME);
- final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
- abiOverride);
- if (res != PackageManager.INSTALL_SUCCEEDED) {
- throw new IOException("Failed to extract native code, res=" + res);
- }
-
- if (!PackageHelper.finalizeSdDir(newCid)) {
- throw new IOException("Failed to finalize " + newCid);
- }
-
- if (PackageHelper.isContainerMounted(newCid)) {
- PackageHelper.unMountSdDir(newCid);
- }
-
- } catch (ErrnoException e) {
- PackageHelper.destroySdDir(newCid);
- throw e.rethrowAsIOException();
- } catch (IOException e) {
- PackageHelper.destroySdDir(newCid);
- throw e;
- }
-
- return newMountPath;
- }
-
private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target)
throws IOException, RemoteException {
copyFile(pkg.baseCodePath, target, "base.apk");
@@ -373,28 +265,4 @@
IoUtils.closeQuietly(in);
}
}
-
- private void copyFile(String sourcePath, File targetDir, String targetName,
- boolean isForwardLocked) throws IOException, ErrnoException {
- final File sourceFile = new File(sourcePath);
- final File targetFile = new File(targetDir, targetName);
-
- Slog.d(TAG, "Copying " + sourceFile + " to " + targetFile);
- if (!FileUtils.copyFile(sourceFile, targetFile)) {
- throw new IOException("Failed to copy " + sourceFile + " to " + targetFile);
- }
-
- if (isForwardLocked) {
- final String publicTargetName = PackageHelper.replaceEnd(targetName,
- ".apk", ".zip");
- final File publicTargetFile = new File(targetDir, publicTargetName);
-
- PackageHelper.extractPublicFiles(sourceFile, publicTargetFile);
-
- Os.chmod(targetFile.getAbsolutePath(), 0640);
- Os.chmod(publicTargetFile.getAbsolutePath(), 0644);
- } else {
- Os.chmod(targetFile.getAbsolutePath(), 0644);
- }
- }
}
diff --git a/packages/InputDevices/res/values-da/strings.xml b/packages/InputDevices/res/values-da/strings.xml
index 334952c..08ff4ca 100644
--- a/packages/InputDevices/res/values-da/strings.xml
+++ b/packages/InputDevices/res/values-da/strings.xml
@@ -3,7 +3,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="8016145283189546017">"Inputenheder"</string>
<string name="keyboard_layouts_label" msgid="6688773268302087545">"Android-tastatur"</string>
- <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"Engelsk (UK)"</string>
+ <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"Engelsk (Storbritannien)"</string>
<string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"engelsk (USA)"</string>
<string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Engelsk (USA), international stil"</string>
<string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Engelsk (USA), Colemak-stil"</string>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 0e0d9ae..cf9515e 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Niks"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Wag vir ontfouter"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Ontfoutde program wag vir ontfouter om te heg voordat dit uitgevoer word"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telefonie-monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Telefonie-monitor sal loglêers insamel wanneer dit \'n probleem met telefonie-/modemfunksionaliteit bespeur en \'n kennisgewing aan die gebruiker stuur om \'n fout in te dien"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Invoer"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Skets"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardeware-versnelde lewering"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 017722f..a84ee81 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"ምንም"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"ስህተት ማስወገጃውን ጠብቅ"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"ስህተቱ የተወገደለት መተግበሪያ ከመፈጸሙ በፊት የስህተት ማስወገጃው እስኪያያዝ ድረስ እየጠበቀው ነው"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"የቴሌፎኒ መከታተያ"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor በቴሌፎኒ/ሞደም ተግባር ላይ ችግር እንዳለ ሲያገኝ የምዝግብ ማስታወሻዎችን ይሰበስብና ተጠቃሚው ሳንካ እንዲያስመዘግቡ በማሳወቂያ ይጠይቃቸዋል"</string>
<string name="debug_input_category" msgid="1811069939601180246">"ግብዓት"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"ስዕል"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"የተፋጠነ የሃርድዌር አሰጣጥ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 2c39566..b9a16b96 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"لا شيء"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"انتظار برنامج التصحيح"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"ينتظر التطبيق قيد التصحيح انضمام برنامج التصحيح قبل التنفيذ"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"خدمة مراقبة الاتصالات الهاتفية"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"ستجمع خدمة مراقبة الاتصالات الهاتفية سجلات عند اكتشاف مشكلة متعلقة بوظائف الاتصالات الهاتفية أو المودم، وإرسال إشعار إلى المستخدم لإرسال تقرير بالخطأ"</string>
<string name="debug_input_category" msgid="1811069939601180246">"الإدخال"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"رسم"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"عرض تسارع الأجهزة"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 33e9e85..0a86706 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Heç nə"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Sazlamanı gözləyin"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Sazlanmış tətbiq icradan əvvəl qoşulmaq üçün sazlayıcı gözləyir"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telefoniya Monitoru"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Telefoniya Monitoru telefoniya/modem funksionallığı ilə bağlı problem aşkar etdikdə qeydiyyatları toplayır və baq haqqında istifadəçiyə bildiriş göndərir"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Daxiletmə"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Təsvir"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Avadanlıq qaldırma renderi"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 48e8e6d..1e84d3d 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nijedna"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Sačekaj program za otklanjanje grešaka"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Aplikacija čeka program za otklanjanje grešaka da priloži pre izvršavanja"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"TelephonyMonitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor će prikupljati evidenciju kada otkrije problem sa funkcionisanjem telefonije/modema i zatražiće od korisnika da prijavi grešku"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Unos"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Crtanje"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardverski ubrzano prikazivanje"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 551a86d..e47bc43 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Нічога"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Пачакайце адладчык"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Адладжанае прыкладанне чакае далучэння да iнструмента для адладкi перад працай"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Сродак адсочвання тэлефаніі"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Праграма TelephonyMonitor будзе заносіць у журналы выпадкі выяўлення праблем, што датычацца фукнцый тэлефаніі/мадэма, а таксама паказваць карыстальніку адпаведнае апавяшчэнне з прапановай адпраўкі паведамлення пра памылку"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Увод"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Чарцёж"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Апаратнае паскарэнне рэндэрынгу"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 802e66e..77beb4c 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Няма"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Изчакване на инструмента за отстраняване на грешки"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Прил. изчаква инстр. за отстраняване на грешки да се прикачи преди изпълнение"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Наблюдение на телефонията"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Функцията за наблюдение на телефонията ще събира регистрационни файлове, когато установи проблем с функционалността на телефонията/модема, и ще изпрати на потребителя известие с подкана да подаде сигнал за програмна грешка"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Въвеждане"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Начертаване"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Хардуерно ускорено изобразяване"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 9e2ef59..424e7b9 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"কিছুই না"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"ডিবাগারের জন্য অপেক্ষা করুন"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"চালানোর আগে সংযুক্ত করতে জন্য ডিবাগ করা অ্যাপ্লিকেশনটি ডিবাগারের জন্য অপেক্ষা করছে"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"টেলিফোনি মনিটর"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"টেলিফোনি মনিটর টেলিফোনি/মোডেমের কার্যকারিতায় কোনও সমস্যা শনাক্ত করলে সমস্যাটি লগ করবে এবং সমস্যাটি জানাতে একটি বাগ ফাইল করার জন্য ব্যবহারকারিকে বিজ্ঞপ্তি পাঠাবে"</string>
<string name="debug_input_category" msgid="1811069939601180246">"ইনপুট"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"অঙ্কন"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"হার্ডওয়্যার দ্বারা চালিত রেন্ডারিং"</string>
@@ -289,7 +287,7 @@
<string name="transition_animation_scale_title" msgid="387527540523595875">"ট্র্যানজিশন অ্যানিমেশন স্কেল"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"অ্যানিমেটর সময়কাল স্কেল"</string>
<string name="overlay_display_devices_title" msgid="5364176287998398539">"গৌণ প্রদর্শনগুলি নকল করুন"</string>
- <string name="debug_applications_category" msgid="4206913653849771549">"অ্যাপ্লিকেশানগুলি"</string>
+ <string name="debug_applications_category" msgid="4206913653849771549">"অ্যাপ"</string>
<string name="immediately_destroy_activities" msgid="1579659389568133959">"কার্যকলাপ রাখবেন না"</string>
<string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"ব্যবহারকারী এটি ছেড়ে যাওয়ার পরে যত তাড়াতাড়ি সম্ভব প্রতিটি কার্যকলাপ ধ্বংস করুন"</string>
<string name="app_process_limit_title" msgid="4280600650253107163">"পশ্চাদপট প্রক্রিয়ার সীমা"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index d16ec3c..97cbfbf 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -71,7 +71,7 @@
<string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Dijeljenje kontakta"</string>
<string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Koristi za dijeljenje kontakta"</string>
<string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Dijeljenje internet veze"</string>
- <string name="bluetooth_profile_map" msgid="1019763341565580450">"Tekstualne poruke"</string>
+ <string name="bluetooth_profile_map" msgid="1019763341565580450">"SMS-ovi"</string>
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"Pristup SIM-u"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string>
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Ništa"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Pričekajte na program za otklanjanje grešaka"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Aplikacija u kojoj se otklanjaju greške čeka da se priloži program za otklanjanje grešaka prije izvršavanja"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Nadzor telefonije"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Nadzor telefonije će prikupiti zapisnike kada otkrije problem u funkcioniranju telefona/modema i obavijestiti korisnika da prijavi grešku"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Ulaz"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Crtanje"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Prikaz s hardverskom akceleracijom"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index ded9352..479cf38 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Cap"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Espera el depurador"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Abans d\'executar-se, l\'aplicació de depuració espera que es connecti el depurador"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Monitor de telefonia"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Quan el monitor de telefonia detecta un problema amb la funció de telefonia/mòdem, recopila registres i mostra una notificació a l\'usuari perquè informi de l\'error"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Entrada"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Dibuix"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Renderització accelerada per maquinari"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 5afa00c..97a76f7 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nic"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Počkat na ladicí program"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Aplikace čeká na připojení ladicího programu"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Služba Telephony Monitor bude zaznamenávat protokoly problémů s funkcemi telefonu či modemu a zobrazí uživateli oznámení, že je třeba vyplnit hlášení o chybě"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Vstup"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Vykreslování"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardwarově urychlené vykreslování"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 275822c..6a006cc 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Ingen"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Vent på fejlfinder"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Fejlrettet app venter på tilknytning af fejlfinder før udførelse"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Overvågning af telefoni"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Overvågning af telefoni indsamler logfiler, når der registreres et problem med telefoni-/modemfunktioner, og sender brugeren en underretning, der beder vedkommende om at indsende en fejlrapport"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Input"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Tegning"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardware-accelereret gengivelse"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 5f11b51..2203bc6 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Keine"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Auf Debugger warten"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"App wartet vor der Ausführung auf den Start des Debuggers"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Mit Telephony Monitor werden Protokolle erfasst, wenn ein Problem mit der Telefon- oder der Modemfunktion entdeckt wird. Nutzer werden dazu aufgefordert, den Programmfehler zu melden."</string>
<string name="debug_input_category" msgid="1811069939601180246">"Eingabe"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Zeichnung"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardwarebeschleunigtes Rendering"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index cdb9518..514cfd8 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Καμία"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Περιμένετε το εργαλείο εντοπισμού σφαλμάτων"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Αναμονή εφαρμογής για να συνδεθεί ο εντοπισμός σφαλμάτων"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Παρακολούθηση τηλεφωνίας"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Η υπηρεσία TelephonyMonitor θα συλλέξει αρχεία καταγραφής μόλις εντοπίσει κάποιο πρόβλημα στη λειτουργία του τηλεφώνου/μόντεμ και θα εμφανίσει μια ειδοποίηση στον χρήστη για να υποβάλει αναφορά σφάλματος"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Εισαγωγή"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Σχέδιο"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Απόδοση με επιτάχυνση από υλικό εξοπλισμό"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index c964367..aa5af8e 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nothing"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Wait for debugger"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Debugged application waits for debugger to attach before executing"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor will collect logs when it detects a problem with telephony/modem functionality and prompt notification to user to file a bug"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Input"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Drawing"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardware accelerated rendering"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index c964367..aa5af8e 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nothing"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Wait for debugger"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Debugged application waits for debugger to attach before executing"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor will collect logs when it detects a problem with telephony/modem functionality and prompt notification to user to file a bug"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Input"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Drawing"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardware accelerated rendering"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index c964367..aa5af8e 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nothing"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Wait for debugger"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Debugged application waits for debugger to attach before executing"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor will collect logs when it detects a problem with telephony/modem functionality and prompt notification to user to file a bug"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Input"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Drawing"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardware accelerated rendering"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index c964367..aa5af8e 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nothing"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Wait for debugger"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Debugged application waits for debugger to attach before executing"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor will collect logs when it detects a problem with telephony/modem functionality and prompt notification to user to file a bug"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Input"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Drawing"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardware accelerated rendering"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 9c313ee..66d8fe0 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nothing"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Wait for debugger"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Debugged application waits for debugger to attach before executing"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor will collect logs when it detects a problem with telephony/modem functionality and prompt notification to user to file a bug"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Input"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Drawing"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardware accelerated rendering"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index fdf39c8..743700e 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Ninguna"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Esperar al depurador"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Esperar que se conecte el depurador para iniciar la aplicación"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Telephony Monitor recopilará registros cuando se detecte un problema con la funcionalidad de telefonía/módem y además enviará al usuario una notificación para que reporte el error"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Entrada"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Dibujo"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Representación acelerada mediante hardware"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 6065bb0..d964728 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Ninguna"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Esperar al depurador"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"La aplicación depurada espera a que se active el depurador para ejecutarse"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Monitor de telefonía"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor recopilará los registros al detectar un problema con la función de módem o telefonía y mostrará una notificación al usuario para registrar un error"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Entrada"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Dibujo"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Renderización acelerada por hardware"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 48b7719..cfcc4c6 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Mitte ühtegi"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Oodake silurit"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Silutud rakendus ootab toimimiseks siluri lisamist"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Teenus Telephony Monitor kogub telefoni/modemi funktsioonide probleemide korral logisid ja esitab kasutajale märguande veaaruande esitamiseks"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Sisend"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Joonis"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Tarkvarakiirendusega renderdamine"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index fc60954..d7595e8 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Ezer ez"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Itxaron araztaileari"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Araztutako aplikazioa araztailea erantsi arte itxaroten ari da exekutatu aurretik"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telefono-gainbegiratzailea"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Telefono-gainbegiratzaileak erregistroak bilduko ditu telefono/modem funtzioarekin arazoren bat dagoela hautematen duenean, eta akatsaren berri emateko eskatuko dio erabiltzaileari"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Sarrera"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Marrazkia"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardware bidez bizkortutako errendatzea"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 2500d5d..f582486 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"هیچ چیز"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"انتظار برای اشکالزدا"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"برنامه اشکالزدایی شده منتظر پیوست شدن اشکالزدا قبل از اجرا است"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor وقتی مشکلی در ارتباط با عملکرد تلفن/مودم تشخیص میدهد، گزارش جمعآوری میکند و با اعلانی از کاربر میخواهد گزارش اشکال تهیه کند"</string>
<string name="debug_input_category" msgid="1811069939601180246">"ورودی"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"طراحی"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"پردازش سختافزاری سریع"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 414a4c7f..83073d1 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Ei mitään"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Odota vianetsintää"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Sovellus odottaa vianetsinnän lisäämistä, ja käynnistyy sen jälkeen."</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Puhelinpalvelujen seuranta"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Puhelinpalvelujen seuranta kerää tietoja virheistä puhelinpalvelujen tai modeemin toiminnassa ja kehottaa käyttäjää tekemään virheilmoituksen."</string>
<string name="debug_input_category" msgid="1811069939601180246">"Syöte"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Piirustus"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Laitteistokiihdytetty hahmonnus"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 6306306..54d6864 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Aucune"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Attendre l\'intervention du débogueur"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Avant de s\'exécuter, l\'application déboguée doit attendre que le débogueur soit attaché."</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"TelephonyMonitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor recueille des journaux lorsqu\'il détecte un problème lié à la fonctionnalité de téléphonie ou de modem, puis invite l\'utilisateur à soumettre un bogue."</string>
<string name="debug_input_category" msgid="1811069939601180246">"Entrée"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Dessin"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Accélération matérielle"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index f8cf107..e35d330 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Aucune"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Attendre l\'intervention du débogueur"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Avant de s\'exécuter, l\'application déboguée doit attendre que le débogueur soit attaché."</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Telephony Monitor recueille des journaux lorsqu\'il détecte un problème lié à la fonctionnalité de téléphonie ou de modem, puis invite l\'utilisateur à créer un bug"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Saisie"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Tracé"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Accélération matérielle"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 39fd72c..8291cb1 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nada"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Agardar polo depurador"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"A aplicación depurada agarda a que o depurador se conecte antes de executarse"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Monitor de telefonía"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"O monitor de telefonía recompilará rexistros cando detecte un problema coa función da telefonía ou do módem e enviará unha notificación ao usuario para solicitarlle que informe dun erro"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Entrada"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Debuxo"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Procesamento acelerado mediante hardware"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index fccac47..ca14118 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"કંઈ નહીં"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"ડીબગર માટે રાહ જુઓ"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"ડીબગ કરેલ ઍપ્લિકેશનો ક્રિયાન્વિત થતા પહેલાં ડીબગર જોડાઈ તેની રાહ જુએ છે"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor ને જ્યારે ટેલિફોની/મૉડેમની કાર્યક્ષમતામાં કોઈ સમસ્યા મળે ત્યારે તે લૉગ એકત્રિત કરશે અને વપરાશકર્તાને બગની જાણ કરવાની સૂચનાનો સંકેત આપશે"</string>
<string name="debug_input_category" msgid="1811069939601180246">"ઇનપુટ"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"રેખાંકન"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"હાર્ડવેર પ્રવેગક રેન્ડરિંગ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 7b01903..bde80f2 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -45,7 +45,7 @@
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s के ज़रिए उपलब्ध"</string>
<string name="speed_label_very_slow" msgid="1867055264243608530">"अत्यधिक धीमी"</string>
<string name="speed_label_slow" msgid="813109590815810235">"धीमी"</string>
- <string name="speed_label_okay" msgid="2331665440671174858">"ठीक"</string>
+ <string name="speed_label_okay" msgid="2331665440671174858">"ठीक है"</string>
<string name="speed_label_medium" msgid="3175763313268941953">"मध्यम"</string>
<string name="speed_label_fast" msgid="7715732164050975057">"तेज़"</string>
<string name="speed_label_very_fast" msgid="2265363430784523409">"अत्यधिक तेज़"</string>
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"कुछ भी नहीं"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"डीबगर की प्रतीक्षा करें"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"डीबग किया गया ऐप्स निष्पादन के पहले अनुलग्न करने के लिए डीबगर की प्रतीक्षा करता है"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"टेलीफ़ोनी मॉनिटर"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"टेलीफ़ोनी मॉनिटर को जब टेलीफ़ोनी/मॉडेम के फंक्शन में कोई समस्या मिलती है, तो वह लॉग इकट्ठा करता है और उपयोगकर्ता को एक गड़बड़ी दर्ज करने के लिए सूचना देता है"</string>
<string name="debug_input_category" msgid="1811069939601180246">"हिंदी में लिखें"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"ड्रॉइंग"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"हार्डवेयर त्वरित रेंडरिंग"</string>
@@ -289,7 +287,7 @@
<string name="transition_animation_scale_title" msgid="387527540523595875">"संक्रमण एनिमेशन स्केल"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"एनिमेटर अवधि स्केल"</string>
<string name="overlay_display_devices_title" msgid="5364176287998398539">"द्वितीयक डिस्प्ले अनुरूपित करें"</string>
- <string name="debug_applications_category" msgid="4206913653849771549">"ऐप्स"</string>
+ <string name="debug_applications_category" msgid="4206913653849771549">"ऐप"</string>
<string name="immediately_destroy_activities" msgid="1579659389568133959">"गतिविधियों को न रखें"</string>
<string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"उपयोगकर्ता के छोड़ते ही हर गतिविधि को खत्म करें"</string>
<string name="app_process_limit_title" msgid="4280600650253107163">"पृष्ठभूमि प्रक्रिया सीमा"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index a58561a..ec2b9cf 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Ništa"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Čeka se program za otklanjanje pogrešaka"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Aplikacija čeka priključivanje programa za otklanjanje pogrešaka"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"TelephonyMonitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor prikupljat će zapisnike kada otkrije problem s funkcioniranjem telefona/modema i obavijestiti korisnika da prijavi programsku pogrešku"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Ulaz"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Crtež"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardverski ubrzano renderiranje"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 82e7432..3fe6a78 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Semmi"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Várjon a hibakeresőre."</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"A javított alkalmazás a hibakeresőre vár."</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"A TelephonyMonitor begyűjti a naplókat, ha problémát észlel a telefonos szolgáltatások vagy a modem működésében, és javasolja a felhasználónak a hiba jelentését"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Bevitel"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Rajz"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardveres gyorsítású megjelenítés"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 9e6e101..119e24c 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Ոչինչ"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Սպասել վրիպազերծիչին"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Վրիպազերծված ծրագրիը սպասում է վրիպազերծիչի կցմանը մինչ կատարումը"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Հեռախոսակապի/մոդեմի հետ կապված խնդիրներ հայտնաբերելու դեպքում TelephonyMonitor-ը կհավաքի մատյանները և օգտվողին կհուշի վրիպակ գրանցելու անհրաժեշտության մասին"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Մուտքագրում"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Պատկերում"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Սարքաշարի արագացված նյութավորում"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 5dcc045..c2db508 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Tidak ada"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Tunggu debugger"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Aplikasi yang di-debug menunggu debugger menempel sebelum berjalan"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Monitor Telefoni"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Monitor Telefoni akan mengumpulkan log jika mendeteksi masalah pada fungsi telefoni/modem dan mengirimkan notifikasi ke pengguna untuk melaporkan bug"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Masukan"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Gambar"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Render yang dipercepat hardware"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index c4d6777..883e909 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Ekkert"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Bíða eftir villuleit"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Villuleituð forrit bíða eftir að villuleit tengist fyrir keyrslu"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Fjarskiptaumsjón"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Fjarskiptaumsjón mun safna annálum þegar það skynjar vandamál með fjarskipti/virkni mótalds og veita notanda beiðni um að senda inn villutilkynningu"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Inntak"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Teikning"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Myndþýðing með vélbúnaðarhröðun"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 85993aa..e53e4da 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nessuna"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Attendi debugger"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"L\'app in debug attende il debugger prima dell\'esecuzione"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"TelephonyMonitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor raccoglierà log quando rileverà un problema con la funzionalità di telefonia/del modem e avviserà tempestivamente l\'utente per segnalare il bug"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Input"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Disegno"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Rendering con accelerazione hardware"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index df690ef..363b064 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"אף אחת"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"המתן למנקה באגים"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"אפליקציה שנוקו בה הבאגים ממתינה למנקה הבאגים לצירוף לפני ביצוע"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor יאסוף מידע ביומנים כשיזהה בעיה בפונקציונליות של טלפוניה/מודם. הוא ישלח הודעה למשתמש כדי שיוכל להגיש דוח על באג"</string>
<string name="debug_input_category" msgid="1811069939601180246">"קלט"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"שרטוט"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"עיבוד מואץ של חומרה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 46b51d1..dfd199a 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"なし"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"デバッガを待機"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"アプリは実行前にデバッガのアタッチを待機します"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Telephony Monitor は、電話やモデムの機能で問題が検出されたときにログを収集し、バグを報告するようユーザーに通知を表示します"</string>
<string name="debug_input_category" msgid="1811069939601180246">"入力"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"描画"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"ハードウェアアクセラレーテッドレンダリング"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 49a6902..7fac639 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"არაფერი"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"დაილოდეთ, სანამ ჩაირთვება გამმართველი"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"გამართული აპლიკაცია ელოდება გამმართველის ჩართვას გაშვებამდე"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"ტელეფონიის კონტროლიორი"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"ტელეფონიის/მოდემის გამართულ მუშაობასთან დაკავშირებული პრობლემის გამოვლენისას, ტელეფონიის კონტროლიორი შეაგროვებს ჟურნალების ჩანაწერებს, ხოლო მომხმარებელს შეცდომის შესახებ მოხსენებას შეთავაზებს"</string>
<string name="debug_input_category" msgid="1811069939601180246">"ტექსტის შეყვანა"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"ნახაზი"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"აპარატურით დაჩქარებული გამოსახულება"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 7dea44a..3b806a5 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Ешнәрсе"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Жөндеушіні күту"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Орындау алдында бекіту үшін жөнделген қолданба жөндеушіні күтеді."</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Telephony Monitor функциясы телефон не модем жұмысында ақау байқаған жағдайда деректерді жинайды да, пайдаланушыға қате туралы ақпаратты жіберуді ұсынады"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Кіріс"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Сызу"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Бейнелеуді жабдықпен жылдамдату"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 4dd298d..2160bae 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"គ្មានអ្វីទេ"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"រង់ចាំកម្មវិធីកែកំហុស"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"កម្មវិធីបានកែកំហុសរង់ចាំឲ្យភ្ជាប់កម្មវិធីកែកំហុសមុនពេលអនុវត្ត"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor នឹងប្រមូលកំណត់ហេតុ នៅពេលវារកឃើញបញ្ហាទាក់ទងនឹងមុខងារទូរសព្ទ/ម៉ូដឹម និងបញ្ជូនការជូនដំណឹងទៅកាន់អ្នកប្រើប្រាស់ដើម្បីរាយការណ៍ពីបញ្ហា"</string>
<string name="debug_input_category" msgid="1811069939601180246">"បញ្ចូល"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"គំនូរ"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"បង្ហាញផ្នែករឹងបានបង្កើនល្បឿន"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index bbfef4b..a47a92c 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"ಏನೂ ಇಲ್ಲ"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"ಡೀಬಗರ್ಗಾಗಿ ನಿರೀಕ್ಷಿಸಿ"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"ಲಗತ್ತನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸುವ ಮೊದಲು ಡೀಬಗರ್ಗಾಗಿ ಡೀಬಗ್ ಮಾಡಿದ ಅಪ್ಲಿಕೇಶನ್ ಕಾಯುತ್ತದೆ"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"ದೂರವಾಣಿ ಮಾನಿಟರ್"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"ದೂರವಾಣಿ/ಮೊಡೆಮ್ ಕಾರ್ಯಾಚರಣೆಯಲ್ಲಿ ಸಮಸ್ಯೆಗಳು ಕಂಡುಬಂದಾಗ, ದೂರವಾಣಿ ಮಾನಿಟರ್ ಲಾಗ್ಗಳನ್ನು ಸಂಗ್ರಹಿಸುತ್ತದೆ ಮತ್ತು ದೋಷದ ಕುರಿತು ವರದಿ ಸಲ್ಲಿಸಲು ಬಳಕೆದಾರನಿಗೆ ಸೂಚನೆ ನೀಡುತ್ತದೆ"</string>
<string name="debug_input_category" msgid="1811069939601180246">"ಇನ್ಪುಟ್"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"ಚಿತ್ರಣ"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"ಹಾರ್ಡ್ವೇರ್ ವೇಗವರ್ಧಿತ ರೆಂಡರಿಂಗ್"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 6633558..852c78e 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"없음"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"디버거 연결을 위해 대기"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"디버깅된 애플리케이션이 실행되기 전에 디버거 연결을 위해 대기"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"통신 모니터"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"통신 모니터는 통신/모뎀 기능에서 문제가 감지될 경우 로그를 수집하며 사용자에게 버그를 신고하라는 알림을 표시합니다."</string>
<string name="debug_input_category" msgid="1811069939601180246">"입력"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"그림"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"하드웨어 가속 렌더링"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index e59d3f8..380d0ff 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Эч бирөө"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Жөндөөчү күтүлүүдө"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Жөндөлүүчү колдонмо аткаруудан мурун жөндөөчүнүнүн тиркелишин күтүп жатат"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor телефондун/модемдин функцияларында көйгөй тапса, анын таржымалын аныктайт жана мүчүлүштүк тууралуу кабарлоо үчүн колдонуучуга эскертме жөнөтөт"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Киргизүү"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Тартуу"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Визуалдаштырууну аппарат менен ылдамдатуу"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 20869a7..eb10dbb 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"ບໍ່ມີຫຍັງ"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"ລໍຖ້າໂຕດີບັ໊ກ"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"ແອັບພລິເຄຊັນທີ່ດີບັ໊ກແລ້ວ ຈະຖ້າໂຕດີບັ໊ກກ່ອນການເຮັດວຽກ"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor ຈະເກັບກຳບັນທຶກການເຮັດວຽກເມື່ອມັນກວດພົບບັນຫາກັບການເຮັດວຽກຂອງລະບົບໂທລະສັບ/ໂມເດັມ ແລະ ແຈ້ງເຕືອນໃຫ້ຜູ້ໃຊ້ໃຫ້ລາຍງານບັກ"</string>
<string name="debug_input_category" msgid="1811069939601180246">"ການປ້ອນຂໍ້ມູນ"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"ການແຕ້ມ"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"ການສະແດງຜົນໂດຍໃຊ້ຮາດແວຊ່ວຍ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 8d17a3a..adf6f8a 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nieko"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Laukti derintuvės"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Derinta progr. laukia derint., kad galėtų tęsti."</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telefonijos stebėjimo priemonė"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Telefonijos stebėjimo priemonė rinks žurnalus, kai aptiks problemą dėl telefonijos / modemo funkcijų, ir naudotojui pateiks raginimą pranešti apie riktą"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Įvestis"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Atvaizdavimas"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Aparatinės įrangos paspartintas pateikimas"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 101b30b..280900a 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nekas"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Gaidīt atkļūdotāju"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Gaida atkļūdotāju, ko pirms izp. piev. atkļ. liet."</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telefonijas pārraugs"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Ja tiks konstatēta problēma saistībā ar telefonijas/modema funkcionalitāti, telefonijas pārraugs apkopos žurnālus un paziņojumā aicinās lietotāju reģistrēt kļūdu."</string>
<string name="debug_input_category" msgid="1811069939601180246">"Ievade"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Zīmējums"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Aparatūras paātrinātā atveidošana"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 40feed0..51697bd 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Ништо"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Почекај ја програмата за отстранување грешки"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Пред да се изврши, апликација за отстранување грешки чека програмата за отстранување грешки да се закачи"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Монитор за телефонија"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Мониторот за телефонија ќе води евиденција кога ќе открие проблем со функционалноста на телефонијата/модемот и ќе го извести корисникот да пријави проблем"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Внес"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Цртање"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Прикажување забрзување на хардвер"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 40525ed..d96607e 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"ഒന്നുമില്ല"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"ഡീബഗ്ഗറിനായി കാത്തിരിക്കുക"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"ഡീബഗ്ഗുചെയ്ത അപ്ലിക്കേഷൻ നിർവ്വഹണത്തിനുമുമ്പായി അറ്റാച്ചുചെയ്യുന്നതിന് ഡീബഗ്ഗറിനായി കാത്തിരിക്കുന്നു."</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"ടെലിഫോണി മോണിറ്റർ"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"ടെലിഫോണി മോണിറ്റർ, ടെലിഫോണി/മോഡവുമായി ബന്ധപ്പെട്ട് എന്തെങ്കിലും പ്രശ്നം കണ്ടെത്തുമ്പോൾ, അതിന്റെ ലോഗുകൾ ശേഖരിക്കുകയും ഒരു ബഗ് ഫയൽ ചെയ്യാൻ ഉപയോക്താവിന് അറിയിപ്പ് നൽകുകയും ചെയ്യും"</string>
<string name="debug_input_category" msgid="1811069939601180246">"ഇൻപുട്ട്"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"ഡ്രോയിംഗ്"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"ഹാർഡ്വെയർ ത്വരിതപ്പെടുത്തിയ റെൻഡർ ചെയ്യൽ"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index f6abd54..e13886d 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Юуг ч биш"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Согог засагчийг хүлээх"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Согог засагдсан аппликейшн ажиллахын өмнө согог засагчийг хавсаргагдахыг хүлээнэ"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Утасны хяналт"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Утасны хяналт нь утас/модемын ажиллагаанд асуудал илрүүлсэн тохиолдолд лог цуглуулж, хэрэглэгчид алдааг засах мэдэгдэл илгээнэ"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Оруулах"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Зураг"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Техник хангамжийн хурдатгалтай үзүүлэлт"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 5e9ecdb..ae61916 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"काहीही नाही"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"डीबगरची प्रतीक्षा करा"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"डीबग केलेले अॅप्लिकेशन अंमलात आणण्यापूर्वी डीबगर संलग्न करण्याची प्रतीक्षा करतो"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"टेलिफोनी मॉनिटर"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"टेलिफोनी/मोडेमच्या कार्यक्षमतेत समस्या आढळल्यावर टेलिफोनी मॉनिटर लॉग्ज गोळा करेल आणि दोष फाइल करण्यासाठी वापरकर्त्याला सूचनेचे संकेत देईल"</string>
<string name="debug_input_category" msgid="1811069939601180246">"इनपुट"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"रेखांकन"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"हार्डवेअर प्रवेगक प्रस्तुती"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index f252c2a..a44e5b1 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Tiada apa-apa"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Nantikan penyahpepijat"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Menanti penyahpepijat sebelum aplikasi melaksana"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor akan mengumpulkan log apabila apl ini mengesan masalah berhubung kefungsian telefoni/modem dan memaparkan pemberitahuan kepada pengguna supaya memfailkan pepijat"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Input"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Lukisan"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Pemaparan dipercepat perkakasan"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 74302a0..af95eac 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"တခုမှမရှိ"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"အပြစ်ရှာဖွေ ဖယ်ရှားချက်ကိုစောင့်ရန်"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"အမှားပြင်ဆင်ရှာဖွေသည့် အပလီကေးရှင်းသည် လုပ်ငန်းမစမီ တွဲဖက်ရန် အမှားရှာဖွေမည့်သူကို စောင့်နေသည်။"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"တယ်လီဖုန်းဆက်သွယ်မှု မော်နီတာ"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"တယ်လီဖုန်းဆက်သွယ်မှု မော်နီတာသည် တယ်လီဖုန်းဆက်သွယ်မှု/မိုဒမ် လုပ်ဆောင်ချက်တို့တွင် ပြဿနာရှိနေလျှင် မှတ်တမ်းပြုစုပြီး ချွတ်ယွင်းချက် အစီရင်ခံရန် အသုံးပြုသူကို အကြောင်းကြားပေးမည် ဖြစ်သည်။"</string>
<string name="debug_input_category" msgid="1811069939601180246">"ထည့်သွင်းရန်"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"ရေးဆွဲခြင်း"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"ဟာ့ဒ်ဝဲ အရှိန်မြှင့် ပုံဖော်ခြင်း"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index cc73ef9..13d27ac 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Ingen"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Vent på feilsøkingsverktøyet"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Feilsøkt app venter til feilsøkingsverktøyet er lagt til før den kjører"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telefonimonitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor logger problemer som oppdages med funksjonaliteten til telefoni/modem, og varsler brukeren om å sende inn en feilrapport."</string>
<string name="debug_input_category" msgid="1811069939601180246">"Inndata"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Tegning"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Maskinvareakselerert gjengivelse"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index fef1ebe..58c5ffc 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"केही पनि होइन"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"डिबग गर्नेलाई पर्खनुहोस्"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"डिबग भएको अनुप्रयोग कार्यन्वयन हुनु अघि संलग्न हुन डिबग गर्नेलाई पर्खन्छ"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"टेलिफोनी मनिटर"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor ले टेलिफोन/मोडेमको सञ्चालनमा कुनै समस्या भेट्टायो भने लगहरू सङ्कलन गर्नेछ र प्रयोगकर्तालाई बग बारे रिपोर्ट गर्न सूचना पठाउनेछ"</string>
<string name="debug_input_category" msgid="1811069939601180246">"इनपुट"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"रेखाचित्र"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"हार्डवेयर प्रतिपादन फुर्तिलो बनाइयो"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 25d7cc5..5cce79e 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Niets"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Wachten op debugger"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Gedebugde app wacht op koppelen van debugger vóór uitvoering"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor verzamelt logbestanden wanneer een probleem wordt gedetecteerd met de functionaliteit van telefonie/modem. De gebruiker krijgt een melding te zien waarin wordt gevraagd of hij een bug wil indienen."</string>
<string name="debug_input_category" msgid="1811069939601180246">"Invoer"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Tekening"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Rendering met hardwareversnelling"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 6e93e869..becb559 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"ਕੁਝ ਨਹੀਂ"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"ਡੀਬੱਗਰ ਦੀ ਉਡੀਕ ਕਰੋ"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"ਡੀਬੱਗ ਕੀਤੇ ਐਪਲੀਕੇਸ਼ਨ ਐਗਜੀਕਿਊਟ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਅਟੈਚ ਕਰਨ ਲਈ ਡੀਬੱਗਰ ਦੀ ਉਡੀਕ ਕਰਦੇ ਹਨ"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"ਟੈਲੀਫ਼ੋਨੀ ਮੋਨੀਟਰ"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"ਟੈਲੀਫ਼ੋਨੀ ਮੋਨੀਟਰ ਟੈਲੀਫ਼ੋਨੀ/ਮੌਡਮ ਪ੍ਰਕਾਰਜਾਤਮਕਤਾ ਵਿੱਚ ਕਿਸੇ ਸਮੱਸਿਆ ਦਾ ਪਤਾ ਲੱਗਣ \'ਤੇ ਲੌਗਾਂ ਨੂੰ ਇਕੱਤਰ ਕਰੇਗਾ ਅਤੇ ਵਰਤੋਂਕਾਰ ਨੂੰ ਇੱਕ ਬੱਗ ਦਾਇਰ ਕਰਨ ਲਈ ਸੂਚਨਾ ਦੇਵੇਗਾ"</string>
<string name="debug_input_category" msgid="1811069939601180246">"ਇਨਪੁਟ"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"ਡਰਾਇੰਗ"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"ਹਾਰਡਵੇਅਰ ਐਕਸੇਲਰੇਟਿਡ ਰੈਂਡਰਿੰਗ"</string>
@@ -331,7 +329,7 @@
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ਤਬਦੀਲ ਕਰੋ ..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ਫ਼ਾਈਲ ਪਹਿਲਾਂ ਤੋਂ ਇਨਕ੍ਰਿਪਟਡ ਹੈ"</string>
<string name="title_convert_fbe" msgid="1263622876196444453">"ਫ਼ਾਈਲ ਆਧਾਰਿਤ ਇਨਕ੍ਰਿਪਸ਼ਨ ਵਿੱਚ ਤਬਦੀਲ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
- <string name="convert_to_fbe_warning" msgid="6139067817148865527">" ਡਾਟਾ ਪਾਰਟੀਸ਼ਨ ਦਾ ਫ਼ਾਈਲ ਆਧਾਰਿਤ ਇਨਕ੍ਰਿਪਸ਼ਨ ਵਿੱਚ ਰੁਪਾਂਤਰਣ ਕਰੋ\n !! ਚਿਤਾਵਨੀ !! ਇਹ ਤੁਹਾਡੇ ਸਾਰੇ ਡੈਟੇ ਨੂੰ ਮਿਟਾ ਦੇਵੇਗਾ\n ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਪ੍ਰਯੋਗਿਕ ਹੈ, ਅਤੇ ਸ਼ਾਇਦ ਸਹੀ ਢੰਗ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ।\n ਜਾਰੀ ਰੱਖਣ ਲਈ \'ਮਿਟਾਓ ਅਤੇ ਰੁਪਾਂਤਰਣ ਕਰੋ...\' ਨੂੰ ਦਬਾਓ।"</string>
+ <string name="convert_to_fbe_warning" msgid="6139067817148865527">" ਡਾਟਾ ਪਾਰਟੀਸ਼ਨ ਦਾ ਫ਼ਾਈਲ ਆਧਾਰਿਤ ਇਨਕ੍ਰਿਪਸ਼ਨ ਵਿੱਚ ਰੁਪਾਂਤਰਣ ਕਰੋ\n !! ਚਿਤਾਵਨੀ !! ਇਹ ਤੁਹਾਡੇ ਸਾਰੇ ਡਾਟੇ ਨੂੰ ਮਿਟਾ ਦੇਵੇਗਾ\n ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਪ੍ਰਯੋਗਿਕ ਹੈ, ਅਤੇ ਸ਼ਾਇਦ ਸਹੀ ਢੰਗ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ।\n ਜਾਰੀ ਰੱਖਣ ਲਈ \'ਮਿਟਾਓ ਅਤੇ ਰੁਪਾਂਤਰਣ ਕਰੋ...\' ਨੂੰ ਦਬਾਓ।"</string>
<string name="button_convert_fbe" msgid="5152671181309826405">"ਮਿਟਾਓ ਅਤੇ ਰੁਪਾਂਤਰਣ ਕਰੋ..."</string>
<string name="picture_color_mode" msgid="4560755008730283695">"ਤਸਵੀਰ ਰੰਗ ਮੋਡ"</string>
<string name="picture_color_mode_desc" msgid="1141891467675548590">"sRGB ਵਰਤੋਂ ਕਰੋ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 59d4724..e3c69fb 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Brak"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Poczekaj na debugera"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Aplikacja do debugowania czeka na przyłączenie debugera"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Monitorowanie telefonii"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor zbiera dzienniki po wykryciu problemu z funkcją telefonu/modemu i powiadamia użytkownika o możliwości zgłoszenia błędu"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Ekran dotykowy"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Rysowanie"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Sprzętowa akceleracja renderowania"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 4e85684..88c69eb 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nada"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Aguardar depurador"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"App depurado espera conexão com debugger antes de ser executado."</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Monitor de telefonia"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Ao detectar um problema com a funcionalidade de modem/telefonia, o Monitor de telefonia coletará registros e enviará uma notificação ao usuário para informar um bug"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Entrada"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Desenho"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Renderização acelerada por hardware"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 44035d4..dd73f3c 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nenhuma"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Aguarde pelo depurador"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"A aplicação depurada aguarda a anexação do depurador antes da execução"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Monitor de telefonia"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"O Monitor de telefonia recolhe registos quando deteta um problema de funcionalidade de telefonia/modem e apresenta uma notificação ao utilizador para reportar um erro"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Introdução"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Desenho"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Conversão acelerada de hardware"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 4e85684..88c69eb 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nada"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Aguardar depurador"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"App depurado espera conexão com debugger antes de ser executado."</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Monitor de telefonia"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Ao detectar um problema com a funcionalidade de modem/telefonia, o Monitor de telefonia coletará registros e enviará uma notificação ao usuário para informar um bug"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Entrada"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Desenho"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Renderização acelerada por hardware"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 09bcc8f..93ad315 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Niciuna"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Așteptați depanatorul"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Înaintea executării, aplicația așteaptă atașarea depanatorului"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor colectează jurnale când detectează o problemă privind performanțele serviciilor de telefonie/modemului și trimite notificări utilizatorului să semnaleze o eroare"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Intrare"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Desen"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Redare accelerată hardware"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 6563ac1..ee5169b 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Нет"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Подождите, пока подключится отладчик"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Приложение ожидает подключения отладчика"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Обнаружив проблему в работе модема или телефонной связи, Telephony Monitor будет собирать журналы и предлагать пользователю отправить информацию об ошибке"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Ввод"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Отрисовка"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Аппаратное ускорение визуализации"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 3fb05b0..1ce6786 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"කිසිවක් නැත"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"නිදොස්කරණය සඳහා රැඳෙන්න"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"නිදොස් කළ යෙදුම් ක්රියාකිරීමට පෙර ඇමිණීම සඳහා නිදොස්කරණය වෙත බලා සිටියි"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"දුරකථන/මොඩම් ක්රියාකාරිත්වයේ ගැටළුවක් හඳුනාගත් විට TelephonyMonitor ලොග එකතු කර දෝෂයක්ගොනු කිරීමට පරිශීලකයා වෙත දැනුම් දෙයි"</string>
<string name="debug_input_category" msgid="1811069939601180246">"ආදානය"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"ඇඳීම්"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"දෘඩාංග වේගය වැඩි කළ පිරිනැමීම"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 1ccfda6..b1d2fa3 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nič"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Čakať na ladiaci nástroj"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Aplikácia čaká na pripojenie ladiaceho nástroja"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Monitorovanie telefonických služieb"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Keď monitorovanie telefonických služieb zistí problém s fungovaním telefonických služieb alebo modemu, bude zhromažďovať denníky a zobrazí používateľovi upozornenie s výzvou na nahlásenie chyby"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Vstup"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Vykreslovanie"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardvérom zrýchlené vykresľovanie"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index de13147..21badd6 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Nič"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Počakajte na iskalnik napak"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Aplikacija, v kateri iščete napako, pred izvajanjem čaka na povezavo z iskalnikom napak"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Nadziranje telefonije"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Funkcija Nadziranje telefonije pridobi dnevnike, ko zazna težavo s funkcijami telefonije/modema, in uporabnika z obvestilom pozove, naj prijavi napako."</string>
<string name="debug_input_category" msgid="1811069939601180246">"Vnos"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Risba"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Upodabljanje s strojnim pospeševanjem"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index f77818d..54cde3c 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Asnjë"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Prit për korrigjuesin"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Aplikacioni i korrigjimit të gabimeve pret që korrigjuesi të bashkëngjitet para ekzekutimit"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Monitori i telefonisë"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Monitori i telefonisë do të mbledhë regjistrat kur të zbulojë një problem me funksionalitetin e telefonisë/modemit dhe do t\'i paraqesë një njoftim përdoruesit që të regjistrojë një defekt në kod"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Hyrja"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Vizatime"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Interpretimi i përshpejtuar i harduerit"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 2b59fee..4e0bee0 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Ниједна"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Сачекај програм за отклањање грешака"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Апликација чека програм за отклањање грешака да приложи пре извршавања"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"TelephonyMonitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor ће прикупљати евиденцију када открије проблем са функционисањем телефоније/модема и затражиће од корисника да пријави грешку"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Унос"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Цртање"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Хардверски убрзано приказивање"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 6ab3799..dea265d 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Ingen"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Vänta på felsökningen"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Felsökaren måste ansluta till appen först"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor samlar in loggar när ett problem upptäcks i telefoni-/modemfunktionen och uppmanar användaren att skicka in en felrapport"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Indata"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Ritning"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Maskinvaruaccelererad rendering"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index e5aa83f..7126594 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Hakuna chochote"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Subiri kitatuaji"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Programu ya utatuaji husubiri kitatuaji ili kuambatisha kabla ya kutekeleza"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Kichunguzi cha Shughuli za Simu"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Kichunguzi cha Shughuli za Simu kitakusanya kumbukumbu wakati kinatambua tatizo katika utendaji wa simu au modemu, na kumwarifu mtumiaji kuwasilisha ripoti ya hitilafu"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Ingizo"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Uchoraji"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Kutunguliza kwa maunzi kulikoharakishwa"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 75420bd..4f563fa 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"ஒன்றுமில்லை"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"பிழைதிருத்திக்குக் காத்திருக்கவும்"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"பிழைதிருத்தப்பட்ட பயன்பாடு செயல்படுவதற்கு முன்பு பிழைதிருத்தியை இணைப்பதற்குக் காத்திருக்கிறது"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"டெலிஃபோனி மானிட்டர்"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor ஆனது டெலிஃபோனி/மோடம் செயல்பாட்டில் சிக்கல் இருப்பதைக் கண்டறியும் போது, பதிவுகளைச் சேகரிக்கும். அத்துடன், பிழையைப் புகாரளிக்கும்படி பயனருக்கு அறிவிப்பைக் காட்டும்"</string>
<string name="debug_input_category" msgid="1811069939601180246">"உள்ளீடு"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"வரைபொருள்"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"வன்பொருள் முடுக்கத்துடன் கூடிய காட்சியாக்கம்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 23a98c2..0d1ca375 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"ఏదీ వద్దు"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"డీబగ్గర్ కోసం వేచి ఉండండి"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"డీబగ్ చేయబడిన యాప్ అమలు కావడానికి ముందు జోడించాల్సిన డీబగ్గర్ కోసం వేచి ఉంటుంది"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"టెలిఫోనీ మానిటర్"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"టెలిఫోనీ/మోడెమ్ కార్యాచరణలో సమస్యను గుర్తించినప్పుడు TelephonyMonitor లాగ్లను సేకరిస్తుంది మరియు బగ్ని ఫైల్ చేయమని వినియోగదారును ప్రోత్సహిస్తుంది"</string>
<string name="debug_input_category" msgid="1811069939601180246">"ఇన్పుట్"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"డ్రాయింగ్"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"హార్డ్వేర్ వేగవంతమైన భాషాంతరీకరణ"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 8608ac4..f7ba20a 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"ไม่มี"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"รอโปรแกรมแก้ไขข้อบกพร่อง"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"แอปพลิเคชันที่มีการแก้ปัญหาจะรอให้โปรแกรมแก้ไขข้อบกพร่องแนบข้อมูลก่อนปฏิบัติการ"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"การตรวจสอบโทรศัพท์"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"การตรวจสอบโทรศัพท์จะรวบรวมบันทึกเมื่อตรวจพบปัญหาด้านฟังก์ชันการทำงานของโทรศัพท์/โมเด็มและแจ้งเตือนให้ผู้ใช้ส่งข้อบกพร่อง"</string>
<string name="debug_input_category" msgid="1811069939601180246">"อินพุต"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"การวาดภาพ"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"การแสดงผลที่มีการเร่งด้วยฮาร์ดแวร์"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index cc6121e..10d8102 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Wala"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Maghintay ng debugger"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Hinihintay ng na-debug na application na ma-attach ang debugger bago magsagawa"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Mangongolekta ang TelephonyMonitor ng mga log kapag nakatukoy ito ng problema sa functionality ng telephony/modem at magpo-prompt ito ng notification sa user na mag-file ng bug"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Input"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Pagguhit"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Pag-render na pinapabilis ng hardware"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index fda52ef..3d8d0d3 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Hiçbiri"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Hata ayıklayıcıyı bekle"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Hata ayıklanan uygulama, çalıştırılmadan önce hata ayıklayıcının eklenmesini bekler"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor, telefon/modem işleviyle ilgili bir sorun algıladığında günlükleri toplar ve hatayı bildirmesi için kullanıcıya bir bildirim gösterir."</string>
<string name="debug_input_category" msgid="1811069939601180246">"Girdi"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Çizim"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Donanım hızlandırmalı oluşturma"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 6d86a8d..7d2c6fd 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Нічого"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Зачекайте на налагоджувач"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Додаток очікує підключення налагоджувача"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Коли функція Telephony Monitor виявить проблеми в роботі телефона чи модема, вона збере дані та запропонує користувачеві повідомити про помилку"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Ввід"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Рисування"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Апаратне прискорення"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 3dd1b3e..63c040e 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -110,11 +110,11 @@
<string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
<string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ہٹائی گئی ایپس"</string>
<string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ہٹائی گئی ایپس اور صارفین"</string>
- <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ٹیتھرنگ"</string>
+ <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ٹیدرنگ"</string>
<string name="tether_settings_title_wifi" msgid="3277144155960302049">"پورٹیبل ہاٹ اسپاٹ"</string>
- <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"بلوٹوتھ ٹیتھرنگ"</string>
- <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"ٹیتھرنگ"</string>
- <string name="tether_settings_title_all" msgid="8356136101061143841">"ٹیتھرنگ و پورٹیبل ہاٹ اسپاٹ"</string>
+ <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"بلوٹوتھ ٹیدرنگ"</string>
+ <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"ٹیدرنگ"</string>
+ <string name="tether_settings_title_all" msgid="8356136101061143841">"ٹیدرنگ و پورٹیبل ہاٹ اسپاٹ"</string>
<string name="managed_user_title" msgid="8109605045406748842">"تمام کام کی ایپس"</string>
<string name="user_guest" msgid="8475274842845401871">"مہمان"</string>
<string name="unknown" msgid="1592123443519355854">"نامعلوم"</string>
@@ -168,7 +168,7 @@
<string name="development_settings_summary" msgid="1815795401632854041">"ایپ ڈویلپمنٹ کیلئے اختیارات سیٹ کریں"</string>
<string name="development_settings_not_available" msgid="4308569041701535607">"اس صارف کیلئے ڈیولپر کے اختیارات دستیاب نہیں ہیں"</string>
<string name="vpn_settings_not_available" msgid="956841430176985598">"VPN ترتیبات اس صارف کیلئے دستیاب نہیں ہیں"</string>
- <string name="tethering_settings_not_available" msgid="6765770438438291012">"ٹیتھرنگ ترتیبات اس صارف کیلئے دستیاب نہیں ہیں"</string>
+ <string name="tethering_settings_not_available" msgid="6765770438438291012">"ٹیدرنگ ترتیبات اس صارف کیلئے دستیاب نہیں ہیں"</string>
<string name="apn_settings_not_available" msgid="7873729032165324000">"رسائی کی جگہ کے نام کی ترتیبات اس صارف کیلئے دستیاب نہیں ہیں"</string>
<string name="enable_adb" msgid="7982306934419797485">"USB ڈیبگ کرنا"</string>
<string name="enable_adb_summary" msgid="4881186971746056635">"USB مربوط ہونے پر ڈيبگ کرنے کی وضع"</string>
@@ -192,7 +192,7 @@
<string name="wifi_aggressive_handover" msgid="5309131983693661320">"Wi‑Fi سے موبائل کو جارحانہ ہینڈ اوور"</string>
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ہمیشہ Wi‑Fi روم اسکینز کی اجازت دیں"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"موبائل ڈیٹا ہمیشہ فعال رکھیں"</string>
- <string name="tethering_hardware_offload" msgid="7470077827090325814">"ہارڈویئر کی سرعت کاری میں ربط بنایا جا رہا ہے"</string>
+ <string name="tethering_hardware_offload" msgid="7470077827090325814">"ٹیدرنگ ہارڈویئر سرعت کاری"</string>
<string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"بغیر نام والے بلوٹوتھ آلات دکھائیں"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"مطلق والیوم کو غیر فعال کریں"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ان بینڈ رنگنگ فعال کریں"</string>
@@ -225,7 +225,7 @@
<string name="allow_mock_location_summary" msgid="317615105156345626">"فرضی مقامات کی اجازت دیں"</string>
<string name="debug_view_attributes" msgid="6485448367803310384">"منظر انتساب کے معائنہ کو فعال کریں"</string>
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Wi‑Fi فعال ہونے پر بھی موبائل ڈیٹا کو ہمیشہ فعال رکھیں (تیزی سے نیٹ ورک سوئچ کرنے کیلئے)۔"</string>
- <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"اگر دستیاب ہو، تو ہارڈویئر کی سرعت کاری میں ربط کاری کا استعمال کریں"</string>
+ <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"اگر دستیاب ہو تو ٹیدرنگ ہارڈویئر سرعت کاری کا استعمال کریں"</string>
<string name="adb_warning_title" msgid="6234463310896563253">"USB ڈیبگ کرنے کی اجازت دیں؟"</string>
<string name="adb_warning_message" msgid="7316799925425402244">"USB ڈیبگ کرنا صرف ڈیولپمنٹ کے مقاصد کیلئے ہے۔ اپنے کمپیوٹر اور اپنے آلہ کے درمیان ڈیٹا کاپی کرنے کیلئے اسے استعمال کریں، بغیر اطلاع کے اپنے آلہ پر ایپس انسٹال کریں اور لاگ ڈیٹا پڑھیں۔"</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"اپنے ذریعہ پہلے سے اجازت یافتہ سبھی کمپیوٹرز سے USB ڈیبگ کرنے کی رسائی کو کالعدم کریں؟"</string>
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"کچھ نہیں"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"ڈیبگر کا انتظار کریں"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"ڈیبگ کردہ ایپلیکیشن کاروائی سے پہلے ڈیبگر کے منسلک ہونے کا انتظار کرتی ہے"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"ٹیلیفونی/موڈم کی فعالیت کے ساتھ در پیش مسئلہ کا پتہ چلنے پر TelephonyMonitor لاگز اکٹھا کر کے بگ دائر کرنے کیلئے صارف کو اطلاع بھیجے گا"</string>
<string name="debug_input_category" msgid="1811069939601180246">"ان پٹ"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"ڈرائنگ"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"ہارڈ ویئر کے ذریعے تیز کردہ رینڈرنگ"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index dbdcb1c..fbe9026 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Yo‘q"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Tuzatuvchi dasturni kuting"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Ilova nosozliklarni tuzatuvchi dasturga ulanishni kutmoqda"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telefoniya nazorati"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Telefoniya nazorati telefoniya/model funksiyalari bilan bog‘liq muammolar aniqlansa va foydalanuvchiga xatolikni yuborishi uchun bildirishnoma yuborib, jurnallarni to‘playdi"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Matn kiritish"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Chizma"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Vizualizatsiyani apparatli tezlatish"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index e6d4eb7..07d0999 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Không có ứng dụng"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Đợi trình gỡ lỗi"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Ứng dụng được gỡ lỗi chờ trình gỡ lỗi đính kèm trước khi thực hiện"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Giám sát điện thoại"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"TelephonyMonitor sẽ thu thập nhật ký khi phát hiện thấy sự cố với chức năng điện thoại/modem và gửi thông báo khẩn cấp tới người dùng để gửi lỗi"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Nhập"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Vẽ"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Kết xuất có tăng tốc phần cứng"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 45d9835..1850f61 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"无"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"等待调试程序"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"调试应用会在执行前等待附加调试器"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"电话监控器"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"电话监控器会在检测到电话/调制解调器功能存在问题时收集相关日志,并向用户发出通知,提醒用户提交错误报告"</string>
<string name="debug_input_category" msgid="1811069939601180246">"输入"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"绘图"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"硬件加速渲染"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index a47e1e8..379a1f1 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"無"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"等待除錯程式"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"執行已除錯的應用程式前等待附加除錯程式"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"電話監控工具"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Telephony Monitor 會在偵測到電話/數據機功能發生問題時收集記錄,並通知使用者報告錯誤"</string>
<string name="debug_input_category" msgid="1811069939601180246">"輸入"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"繪圖"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"硬件加速轉譯"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index d13a4f6..2abca68 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"無"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"等待偵錯程式"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"執行受偵錯的應用程式之前,先等待偵錯程序附加完成"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Telephony Monitor"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Telephony Monitor 會在偵測到電話/數據機功能發生問題時收集相關紀錄,並顯示通知方便使用者回報錯誤"</string>
<string name="debug_input_category" msgid="1811069939601180246">"輸入"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"繪圖"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"硬體加速轉譯"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 35d84a2..1de1312 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -248,8 +248,6 @@
<string name="no_application" msgid="2813387563129153880">"Lutho"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Linda isilungisi senkinga"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"Uhlelo lokusebenza olulungiswe inkinga lulinda isilungisi senkinga ukuba sinamathisele ngaphambi kokuphuma"</string>
- <string name="telephony_monitor_switch" msgid="1764958220062121194">"Ukuqashwa kwefoni"</string>
- <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"I-TelephonyMonitor izoqoqa amalogi uma ithola inkinga ngokusebenza kwefoni/imodemu iphinde ikhiphe isaziso esiya kumsebenzisi ukuthi athumele isiphazamisi"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Okufakwayo"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Umdwebo"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Ukunikezelwa okusheshisiwe kwezingxenyekazi zekhompyutha"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index bd884a3..fbfa725 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -608,11 +608,6 @@
<string name="wait_for_debugger_summary">Debugged application waits for debugger to
attach before executing</string>
- <!-- UI debug setting: title for Telephonymonitor switch [CHAR LIMIT=50] -->
- <string name="telephony_monitor_switch">Telephony Monitor</string>
- <!-- UI debug setting: summary for switch of Telephonymonitor [CHAR LIMIT=500] -->
- <string name="telephony_monitor_switch_summary">TelephonyMonitor will collect logs when it detects a problem with telephony/modem functionality and prompt notification to user to file a bug</string>
-
<!-- Preference category for input debugging development settings. [CHAR LIMIT=25] -->
<string name="debug_input_category">Input</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 40c2b1f..fa2499f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -52,6 +52,11 @@
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnDestroy;
+import com.android.settingslib.core.lifecycle.events.OnPause;
+import com.android.settingslib.core.lifecycle.events.OnResume;
import java.io.File;
import java.io.IOException;
@@ -180,7 +185,11 @@
}
public Session newSession(Callbacks callbacks) {
- Session s = new Session(callbacks);
+ return newSession(callbacks, null);
+ }
+
+ public Session newSession(Callbacks callbacks, Lifecycle lifecycle) {
+ Session s = new Session(callbacks, lifecycle);
synchronized (mEntriesMap) {
mSessions.add(s);
}
@@ -586,7 +595,7 @@
.replaceAll("").toLowerCase();
}
- public class Session {
+ public class Session implements LifecycleObserver, OnPause, OnResume, OnDestroy {
final Callbacks mCallbacks;
boolean mResumed;
@@ -600,11 +609,19 @@
ArrayList<AppEntry> mLastAppList;
boolean mRebuildForeground;
- Session(Callbacks callbacks) {
+ private final boolean mHasLifecycle;
+
+ Session(Callbacks callbacks, Lifecycle lifecycle) {
mCallbacks = callbacks;
+ if (lifecycle != null) {
+ lifecycle.addObserver(this);
+ mHasLifecycle = true;
+ } else {
+ mHasLifecycle = false;
+ }
}
- public void resume() {
+ public void onResume() {
if (DEBUG_LOCKING) Log.v(TAG, "resume about to acquire lock...");
synchronized (mEntriesMap) {
if (!mResumed) {
@@ -616,7 +633,7 @@
if (DEBUG_LOCKING) Log.v(TAG, "...resume releasing lock");
}
- public void pause() {
+ public void onPause() {
if (DEBUG_LOCKING) Log.v(TAG, "pause about to acquire lock...");
synchronized (mEntriesMap) {
if (mResumed) {
@@ -735,8 +752,11 @@
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
- public void release() {
- pause();
+ public void onDestroy() {
+ if (!mHasLifecycle) {
+ // TODO: Legacy, remove this later once all usages are switched to Lifecycle
+ onPause();
+ }
synchronized (mEntriesMap) {
mSessions.remove(this);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java b/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java
index b7fd404..3c5ac8d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java
@@ -73,7 +73,7 @@
final Drawable deviceDrawable = context.getDrawable(resId);
final BatteryMeterDrawable batteryDrawable = new BatteryMeterDrawable(context,
- R.color.meter_background_color, batteryLevel);
+ context.getColor(R.color.meter_background_color), batteryLevel);
final int pad = context.getResources().getDimensionPixelSize(R.dimen.bt_battery_padding);
batteryDrawable.setPadding(pad, pad, pad, pad);
@@ -107,6 +107,8 @@
@VisibleForTesting
static class BatteryMeterDrawable extends BatteryMeterDrawableBase {
private final float mAspectRatio;
+ @VisibleForTesting
+ int mFrameColor;
public BatteryMeterDrawable(Context context, int frameColor, int batteryLevel) {
super(context, frameColor);
@@ -118,6 +120,7 @@
final int tintColor = Utils.getColorAttr(context, android.R.attr.colorControlNormal);
setColorFilter(new PorterDuffColorFilter(tintColor, PorterDuff.Mode.SRC_IN));
setBatteryLevel(batteryLevel);
+ mFrameColor = frameColor;
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java b/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java
index f121480..4ca5bef 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java
@@ -139,11 +139,11 @@
/**
* Gets information about a particular package from the package manager.
+ *
* @param packageName The name of the package we would like information about.
- * @param i additional options flags. see javadoc for
- * {@link PackageManager#getPackageInfo(String, int)}
+ * @param i additional options flags. see javadoc for
+ * {@link PackageManager#getPackageInfo(String, int)}
* @return The PackageInfo for the requested package
- * @throws NameNotFoundException
*/
public PackageInfo getPackageInfo(String packageName, int i) throws NameNotFoundException {
return mPm.getPackageInfo(packageName, i);
@@ -151,6 +151,7 @@
/**
* Retrieves the icon associated with this particular set of ApplicationInfo
+ *
* @param info The ApplicationInfo to retrieve the icon for
* @return The icon as a drawable.
*/
@@ -161,6 +162,7 @@
/**
* Retrieves the label associated with the particular set of ApplicationInfo
+ *
* @param app The ApplicationInfo to retrieve the label for
* @return the label as a CharSequence
*/
@@ -211,4 +213,20 @@
public int getApplicationEnabledSetting(String packageName) {
return mPm.getApplicationEnabledSetting(packageName);
}
+
+ /**
+ * Calls {@code PackageManager.getApplicationInfo}
+ */
+ public ApplicationInfo getApplicationInfo(String packageName, int flags)
+ throws NameNotFoundException {
+ return mPm.getApplicationInfo(packageName, flags);
+ }
+
+ /**
+ * Calls {@code PackageManager.getApplicationLabel}
+ */
+ public CharSequence getApplicationLabel(ApplicationInfo info) {
+ return mPm.getApplicationLabel(info);
+ }
}
+
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
index 1e65a0a..94f80d3 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
@@ -100,4 +100,15 @@
assertThat(twinDrawable.getLayerInsetTop(1)).isEqualTo(
drawable.getLayerInsetTop(1));
}
+
+ @Test
+ public void testCreateLayerDrawable_bluetoothDrawable_hasCorrectFrameColor() {
+ BluetoothDeviceLayerDrawable drawable = BluetoothDeviceLayerDrawable.createLayerDrawable(
+ mContext, RES_ID, BATTERY_LEVEL);
+ BluetoothDeviceLayerDrawable.BatteryMeterDrawable batteryMeterDrawable =
+ (BluetoothDeviceLayerDrawable.BatteryMeterDrawable) drawable.getDrawable(1);
+
+ assertThat(batteryMeterDrawable.mFrameColor).isEqualTo(
+ mContext.getColor(R.color.meter_background_color));
+ }
}
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index 00f0ccb..92c8b9e 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -35,7 +35,7 @@
<string name="keyguard_plugged_in_charging_slowly" msgid="6637043106038550407">"ਹੌਲੀ-ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="keyguard_low_battery" msgid="9218432555787624490">"ਆਪਣਾ ਚਾਰਜਰ ਕਨੈਕਟ ਕਰੋ।"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8566679946700751371">"ਅਣਲਾਕ ਕਰਨ ਲਈ \"ਮੀਨੂ\" ਦਬਾਓ।"</string>
- <string name="keyguard_network_locked_message" msgid="6743537524631420759">"ਨੈੱਟਵਰਕ ਲੌਕ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="keyguard_network_locked_message" msgid="6743537524631420759">"ਨੈੱਟਵਰਕ ਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
<string name="keyguard_missing_sim_message_short" msgid="6327533369959764518">"ਕੋਈ ਸਿਮ ਕਾਰਡ ਨਹੀਂ"</string>
<string name="keyguard_missing_sim_message" product="tablet" msgid="4550152848200783542">"ਟੈਬਲੈੱਟ ਵਿੱਚ ਕੋਈ ਸਿਮ ਕਾਰਡ ਮੌਜੂਦ ਨਹੀਂ।"</string>
<string name="keyguard_missing_sim_message" product="default" msgid="6585414237800161146">"ਫ਼ੋਨ ਵਿੱਚ ਕੋਈ ਸਿਮ ਕਾਰਡ ਮੌਜੂਦ ਨਹੀਂ।"</string>
@@ -43,8 +43,8 @@
<string name="keyguard_missing_sim_instructions_long" msgid="589889372883904477">"SIM ਕਾਰਡ ਮੌਜੂਦ ਨਹੀਂ ਜਾਂ ਪੜ੍ਹਨਯੋਗ ਨਹੀਂ ਹੈ। ਇੱਕ SIM ਕਾਰਡ ਪਾਓ।"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="654102080186420706">"ਨਾ-ਵਰਤਣਯੋਗ SIM ਕਾਰਡ।"</string>
<string name="keyguard_permanent_disabled_sim_instructions" msgid="4683178224791318347">"ਤੁਹਾਡਾ ਸਿਮ ਕਾਰਡ ਸਥਾਈ ਤੌਰ \'ਤੇ ਅਯੋਗ ਬਣਾ ਦਿੱਤਾ ਗਿਆ ਹੈ।\n ਇੱਕ ਹੋਰ ਸਿਮ ਕਾਰਡ ਲਈ ਆਪਣੇ ਵਾਇਰਲੈੱਸ ਸੇਵਾ ਪ੍ਰਦਾਨਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
- <string name="keyguard_sim_locked_message" msgid="953766009432168127">"SIM ਕਾਰਡ ਲੌਕ ਕੀਤਾ ਹੋਇਆ ਹੈ।"</string>
- <string name="keyguard_sim_puk_locked_message" msgid="1772789643694942073">"SIM ਕਾਰਡ PUK-ਲੌਕ ਕੀਤਾ ਹੋਇਆ ਹੈ।"</string>
+ <string name="keyguard_sim_locked_message" msgid="953766009432168127">"SIM ਕਾਰਡ ਲਾਕ ਕੀਤਾ ਹੋਇਆ ਹੈ।"</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="1772789643694942073">"SIM ਕਾਰਡ PUK- ਲਾਕ ਕੀਤਾ ਹੋਇਆ ਹੈ।"</string>
<string name="keyguard_sim_unlock_progress_dialog_message" msgid="3586601150825821675">"SIM ਕਾਰਡ ਨੂੰ ਅਣਲਾਕ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
<string name="keyguard_accessibility_pin_area" msgid="703175752097279029">"ਪਿੰਨ ਖੇਤਰ"</string>
<string name="keyguard_accessibility_sim_pin_area" msgid="912702510825058921">"ਸਿਮ ਪਿੰਨ ਖੇਤਰ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 520df00..116a061 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -659,7 +659,7 @@
<string name="volume_dnd_silent" msgid="4363882330723050727">"اختصار أزرار مستوى الصوت"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"تعطيل \"عدم الإزعاج\" عند رفع مستوى الصوت"</string>
<string name="battery" msgid="7498329822413202973">"البطارية"</string>
- <string name="clock" msgid="7416090374234785905">"ساعة"</string>
+ <string name="clock" msgid="7416090374234785905">"الساعة"</string>
<string name="headset" msgid="4534219457597457353">"سماعة الرأس"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"تم توصيل سماعات رأس"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"تم توصيل سماعات رأس"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 6cab2ec..f43a048 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -336,7 +336,7 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"épinglage d\'écran"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
- <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> est désactivée en mode sécurisé."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> est désactivée en mode sans échec."</string>
<string name="recents_stack_action_button_label" msgid="6593727103310426253">"Effacer tout"</string>
<string name="recents_drag_hint_message" msgid="2649739267073203985">"Glissez l\'élément ici pour utiliser l\'écran partagé"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index fd78108..e30dbcb 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -188,7 +188,7 @@
<string name="accessibility_desc_settings" msgid="3417884241751434521">"ക്രമീകരണം"</string>
<string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"അവലോകനം."</string>
<string name="accessibility_desc_work_lock" msgid="4288774420752813383">"ഔദ്യോഗിക ലോക്ക് സ്ക്രീൻ"</string>
- <string name="accessibility_desc_close" msgid="7479755364962766729">"അടയ്ക്കുക"</string>
+ <string name="accessibility_desc_close" msgid="7479755364962766729">"അവസാനിപ്പിക്കുക"</string>
<string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
<string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"വൈഫൈ ഓഫാക്കി."</string>
<string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"വൈഫൈ ഓണാക്കി."</string>
@@ -724,7 +724,7 @@
<string name="tuner_lock_screen" msgid="5755818559638850294">"ലോക്ക് സ്ക്രീൻ"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"വികസിപ്പിക്കുക"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"ചെറുതാക്കുക"</string>
- <string name="pip_phone_close" msgid="8416647892889710330">"അടയ്ക്കുക"</string>
+ <string name="pip_phone_close" msgid="8416647892889710330">"അവസാനിപ്പിക്കുക"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"തള്ളിക്കളയാൻ താഴേക്ക് വലിച്ചിടുക"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"മെനു"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ചിത്രത്തിനുള്ളിലെ ചിത്രത്തിലാണ്"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index ec9fde8..3b31b2d 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -752,7 +752,7 @@
<string name="tuner_left" msgid="8404287986475034806">"Links"</string>
<string name="tuner_right" msgid="6222734772467850156">"Rechts"</string>
<string name="tuner_menu" msgid="191640047241552081">"Menu"</string>
- <string name="tuner_app" msgid="3507057938640108777">"Apps <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="tuner_app" msgid="3507057938640108777">"<xliff:g id="APP">%1$s</xliff:g>-app"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Meldingen"</string>
<string name="notification_channel_battery" msgid="5786118169182888462">"Batterij"</string>
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
diff --git a/packages/SystemUI/res/values-pa-land/strings.xml b/packages/SystemUI/res/values-pa-land/strings.xml
index fef122a..dfe2a5d 100644
--- a/packages/SystemUI/res/values-pa-land/strings.xml
+++ b/packages/SystemUI/res/values-pa-land/strings.xml
@@ -19,5 +19,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="toast_rotation_locked" msgid="7609673011431556092">"ਸਕ੍ਰੀਨ ਹੁਣ ਲੈਂਡਸਕੇਪ ਅਨੁਕੂਲਨ ਵਿੱਚ ਲੌਕ ਕੀਤੀ ਗਈ ਹੈ।"</string>
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"ਸਕ੍ਰੀਨ ਹੁਣ ਲੈਂਡਸਕੇਪ ਅਨੁਕੂਲਨ ਵਿੱਚ ਲਾਕ ਕੀਤੀ ਗਈ ਹੈ।"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 987ce71..c2089a6 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -184,10 +184,10 @@
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"ਸੂਚਨਾ ਰੱਦ ਕੀਤੀ।"</string>
<string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"ਸੂਚਨਾ ਸ਼ੇਡ।"</string>
<string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ।"</string>
- <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ਲੌਕ ਸਕ੍ਰੀਨ।"</string>
+ <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">" ਲਾਕ ਸਕ੍ਰੀਨ।"</string>
<string name="accessibility_desc_settings" msgid="3417884241751434521">"ਸੈਟਿੰਗਾਂ"</string>
<string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"ਰੂਪ-ਰੇਖਾ।"</string>
- <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"ਕਾਰਜ-ਸਥਾਨ ਲੌਕ ਸਕ੍ਰੀਨ"</string>
+ <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"ਕਾਰਜ-ਸਥਾਨ ਲਾਕ ਸਕ੍ਰੀਨ"</string>
<string name="accessibility_desc_close" msgid="7479755364962766729">"ਬੰਦ ਕਰੋ"</string>
<string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>।"</string>
<string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi ਬੰਦ ਕੀਤਾ।"</string>
@@ -258,11 +258,11 @@
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"ਸੂਚਨਾ ਸੈਟਿੰਗਾਂ"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ਸੈਟਿੰਗਾਂ"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ਸਕ੍ਰੀਨ ਆਟੋਮੈਟਿਕਲੀ ਰੋਟੇਟ ਕਰੇਗੀ।"</string>
- <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"ਸਕ੍ਰੀਨ ਲੈਂਡਸਕੇਪ ਅਨੁਕੂਲਨ ਵਿੱਚ ਲੌਕ ਕੀਤੀ ਹੈ।"</string>
- <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"ਸਕ੍ਰੀਨ ਪੋਰਟਰੇਟ ਅਨੁਕੂਲਨ ਵਿੱਚ ਲੌਕ ਕੀਤੀ ਗਈ ਹੈ।"</string>
+ <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"ਸਕ੍ਰੀਨ ਲੈਂਡਸਕੇਪ ਅਨੁਕੂਲਨ ਵਿੱਚ ਲਾਕ ਕੀਤੀ ਹੈ।"</string>
+ <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"ਸਕ੍ਰੀਨ ਪੋਰਟਰੇਟ ਅਨੁਕੂਲਨ ਵਿੱਚ ਲਾਕ ਕੀਤੀ ਗਈ ਹੈ।"</string>
<string name="accessibility_rotation_lock_off_changed" msgid="8134601071026305153">"ਸਕ੍ਰੀਨ ਹੁਣ ਆਟੋਮੈਟਿਕਲੀ ਰੋਟੇਟ ਕਰੇਗੀ।"</string>
- <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"ਸਕ੍ਰੀਨ ਹੁਣ ਲੈਂਡਸਕੇਪ ਅਨੁਕੂਲਨ ਵਿੱਚ ਲੌਕ ਕੀਤੀ ਗਈ ਹੈ।"</string>
- <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"ਸਕ੍ਰੀਨ ਹੁਣ ਪੋਰਟਰੇਟ ਅਨੁਕੂਲਨ ਵਿੱਚ ਲੌਕ ਕੀਤੀ ਗਈ ਹੈ।"</string>
+ <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"ਸਕ੍ਰੀਨ ਹੁਣ ਲੈਂਡਸਕੇਪ ਅਨੁਕੂਲਨ ਵਿੱਚ ਲਾਕ ਕੀਤੀ ਗਈ ਹੈ।"</string>
+ <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"ਸਕ੍ਰੀਨ ਹੁਣ ਪੋਰਟਰੇਟ ਅਨੁਕੂਲਨ ਵਿੱਚ ਲਾਕ ਕੀਤੀ ਗਈ ਹੈ।"</string>
<string name="dessert_case" msgid="1295161776223959221">"ਡੈਜ਼ਰਟ ਕੇਸ"</string>
<string name="start_dreams" msgid="5640361424498338327">"ਸਕ੍ਰੀਨ ਸੇਵਰ"</string>
<string name="ethernet_label" msgid="7967563676324087464">"ਈਥਰਨੈਟ"</string>
@@ -278,7 +278,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"ਆਟੋ-ਰੋਟੇਟ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"ਸਕ੍ਰੀਨ ਨੂੰ ਆਪਣੇ ਆਪ ਘੁੰਮਾਓ"</string>
<string name="accessibility_quick_settings_rotation_value" msgid="8187398200140760213">"<xliff:g id="ID_1">%s</xliff:g> ਮੋਡ"</string>
- <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"ਰੋਟੇਸ਼ਨ ਲੌਕ ਕੀਤੀ"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"ਰੋਟੇਸ਼ਨ ਲਾਕ ਕੀਤੀ"</string>
<string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"ਪੋਰਟਰੇਟ"</string>
<string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"ਲੈਂਡਸਕੇਪ"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"ਇਨਪੁੱਟ ਵਿਧੀ"</string>
@@ -721,7 +721,7 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ।"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ਸੈਟਿੰਗਾਂ ਦੇ ਕ੍ਰਮ ਦਾ ਸੰਪਾਦਨ ਕਰੋ।"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ਦਾ <xliff:g id="ID_1">%1$d</xliff:g> ਪੰਨਾ"</string>
- <string name="tuner_lock_screen" msgid="5755818559638850294">"ਲੌਕ ਸਕ੍ਰੀਨ"</string>
+ <string name="tuner_lock_screen" msgid="5755818559638850294">" ਲਾਕ ਸਕ੍ਰੀਨ"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"ਵਿਸਤਾਰ ਕਰੋ"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"ਛੋਟਾ ਕਰੋ"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"ਬੰਦ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 7ff9b73..a725e53 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -244,7 +244,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="6801382439018099779">"Mobilna transmisja danych jest wstrzymana"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Transmisja danych została wstrzymana"</string>
- <string name="data_usage_disabled_dialog" msgid="4919541636934603816">"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" msgid="4919541636934603816">"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 użycie 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>
@@ -785,7 +785,7 @@
<string name="qs_dnd_keep" msgid="1825009164681928736">"Zachowaj"</string>
<string name="qs_dnd_replace" msgid="8019520786644276623">"Zastąp"</string>
<string name="running_foreground_services_title" msgid="381024150898615683">"Aplikacje działające w tle"</string>
- <string name="running_foreground_services_msg" msgid="6326247670075574355">"Kliknij, by wyświetlić szczegóły wykorzystania baterii i transmisji danych"</string>
+ <string name="running_foreground_services_msg" msgid="6326247670075574355">"Kliknij, by wyświetlić szczegóły wykorzystania baterii i użycia danych"</string>
<string name="data_usage_disable_mobile" msgid="5116269981510015864">"Wyłączyć mobilną transmisję danych?"</string>
<string name="touch_filtered_warning" msgid="8671693809204767551">"Aplikacja Ustawienia nie może zweryfikować Twojej odpowiedzi, ponieważ inna aplikacja zasłania prośbę o udzielenie uprawnień."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index a4b45e5..db7ea81 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -616,7 +616,7 @@
<string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
<string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Prehrať/pozastaviť"</string>
<string name="keyboard_key_media_stop" msgid="2859963958595908962">"Zastaviť"</string>
- <string name="keyboard_key_media_next" msgid="1894394911630345607">"Nasledujúce"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Ďalej"</string>
<string name="keyboard_key_media_previous" msgid="4256072387192967261">"Predchádzajúce"</string>
<string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Pretočiť späť"</string>
<string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Pretočiť dopredu"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 969a0a2..ad39fea 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -243,7 +243,7 @@
<string name="data_usage_disabled_dialog_mobile_title" msgid="6801382439018099779">"หยุดการใช้อินเทอร์เน็ตมือถือชั่วคราว"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"หยุดการใช้ข้อมูลชั่วคราวแล้ว"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"คุณใช้อินเทอร์เน็ตถึงปริมาณที่กำหนดไว้แล้ว คุณไม่ได้ใช้อินเทอร์เน็ตมือถือแล้วในขณะนี้\n\nหากใช้ต่อ อาจมีการเรียกเก็บค่าบริการอินเทอร์เน็ต"</string>
- <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ทำต่อ"</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>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"กำลังค้นหา GPS"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 9f44d67..aa2eee4 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -155,7 +155,7 @@
<string name="accessibility_cell_data" msgid="5326139158682385073">"موبائل ڈیٹا"</string>
<string name="accessibility_cell_data_on" msgid="5927098403452994422">"موبائل ڈیٹا آن ہے"</string>
<string name="accessibility_cell_data_off" msgid="443267573897409704">"موبائل ڈیٹا آف ہے"</string>
- <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"بلوٹوتھ ٹیتھرنگ۔"</string>
+ <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"بلوٹوتھ ٹیدرنگ۔"</string>
<string name="accessibility_airplane_mode" msgid="834748999790763092">"ہوائی جہاز وضع۔"</string>
<string name="accessibility_vpn_on" msgid="5993385083262856059">"VPN آن ہے۔"</string>
<string name="accessibility_no_sims" msgid="3957997018324995781">"کوئی SIM کارڈ نہیں ہے۔"</string>
@@ -312,7 +312,7 @@
<string name="quick_settings_connected" msgid="1722253542984847487">"مربوط"</string>
<string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"منسلک ہے، بیٹری <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"مربوط ہو رہا ہے…"</string>
- <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ٹیتھرنگ"</string>
+ <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ٹیدرنگ"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ہاٹ اسپاٹ"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"اطلاعات"</string>
<string name="quick_settings_flashlight_label" msgid="2133093497691661546">"فلیش لائٹ"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index d767979..2152ae3 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -73,7 +73,7 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"已拍攝螢幕擷取畫面。"</string>
<string name="screenshot_saved_text" msgid="2685605830386712477">"輕觸即可查看螢幕擷圖。"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"無法拍攝螢幕擷取畫面。"</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"儲存螢幕擷圖時發生問題。"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"儲存螢幕擷取畫面時發生問題。"</string>
<string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"由於儲存空間有限,因此無法儲存螢幕擷取畫面。"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"這個應用程式或貴機構不允許擷取螢幕畫面"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB 檔案傳輸選項"</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index cd23c97..d83a6c6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -16,6 +16,8 @@
package com.android.keyguard;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
import static android.os.BatteryManager.BATTERY_STATUS_FULL;
@@ -452,6 +454,7 @@
*/
public void setKeyguardGoingAway(boolean goingAway) {
mKeyguardGoingAway = goingAway;
+ updateFingerprintListeningState();
}
/**
@@ -1773,7 +1776,7 @@
public void onTaskStackChangedBackground() {
try {
ActivityManager.StackInfo info = ActivityManager.getService().getStackInfo(
- ActivityManager.StackId.ASSISTANT_STACK_ID);
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT);
if (info == null) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 2b31967..2fe66a1 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -15,6 +15,8 @@
*/
package com.android.systemui;
+import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
+import static android.app.StatusBarManager.DISABLE_NONE;
import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
import android.animation.ArgbEvaluator;
@@ -52,6 +54,7 @@
import com.android.systemui.statusbar.policy.IconLogger;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.util.Utils.DisableStateTracker;
import java.text.NumberFormat;
@@ -101,6 +104,9 @@
mSettingObserver = new SettingObserver(new Handler(context.getMainLooper()));
+ addOnAttachStateChangeListener(
+ new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS));
+
mSlotBattery = context.getString(
com.android.internal.R.string.status_bar_battery);
mBatteryIconView = new ImageView(context);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index c5eebcc..8a8bafa 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -61,6 +61,7 @@
private AssistOrbContainer mView;
private final DeviceProvisionedController mDeviceProvisionedController;
protected final AssistUtils mAssistUtils;
+ private final boolean mShouldEnableOrb;
private IVoiceInteractionSessionShowCallback mShowCallback =
new IVoiceInteractionSessionShowCallback.Stub() {
@@ -96,6 +97,7 @@
| ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_UI_MODE
| ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS);
onConfigurationChanged(context.getResources().getConfiguration());
+ mShouldEnableOrb = !ActivityManager.isLowRamDeviceStatic();
}
protected void registerVoiceInteractionSessionListener() {
@@ -179,7 +181,9 @@
private void showOrb(@NonNull ComponentName assistComponent, boolean isService) {
maybeSwapSearchIcon(assistComponent, isService);
- mView.show(true /* show */, true /* animate */);
+ if (mShouldEnableOrb) {
+ mView.show(true /* show */, true /* animate */);
+ }
}
private void startAssistInternal(Bundle args, @NonNull ComponentName assistComponent,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
index 5c99961..debda21 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
@@ -16,8 +16,13 @@
package com.android.systemui.doze;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.UserHandle;
import android.provider.Settings;
import android.text.format.DateUtils;
import android.util.KeyValueListParser;
@@ -34,6 +39,10 @@
public class AlwaysOnDisplayPolicy {
public static final String TAG = "AlwaysOnDisplayPolicy";
+ private static final long DEFAULT_PROX_SCREEN_OFF_DELAY_MS = 10 * DateUtils.SECOND_IN_MILLIS;
+ private static final long DEFAULT_PROX_COOLDOWN_TRIGGER_MS = 2 * DateUtils.SECOND_IN_MILLIS;
+ private static final long DEFAULT_PROX_COOLDOWN_PERIOD_MS = 5 * DateUtils.SECOND_IN_MILLIS;
+
static final String KEY_SCREEN_BRIGHTNESS_ARRAY = "screen_brightness_array";
static final String KEY_DIMMING_SCRIM_ARRAY = "dimming_scrim_array";
static final String KEY_PROX_SCREEN_OFF_DELAY_MS = "prox_screen_off_delay";
@@ -46,7 +55,7 @@
* @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
* @see #KEY_SCREEN_BRIGHTNESS_ARRAY
*/
- public final int[] screenBrightnessArray;
+ public int[] screenBrightnessArray;
/**
* Integer array to map ambient brightness type to dimming scrim.
@@ -54,7 +63,7 @@
* @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
* @see #KEY_DIMMING_SCRIM_ARRAY
*/
- public final int[] dimmingScrimArray;
+ public int[] dimmingScrimArray;
/**
* Delay time(ms) from covering the prox to turning off the screen.
@@ -62,7 +71,7 @@
* @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
* @see #KEY_PROX_SCREEN_OFF_DELAY_MS
*/
- public final long proxScreenOffDelayMs;
+ public long proxScreenOffDelayMs;
/**
* The threshold time(ms) to trigger the cooldown timer, which will
@@ -71,7 +80,7 @@
* @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
* @see #KEY_PROX_COOLDOWN_TRIGGER_MS
*/
- public final long proxCooldownTriggerMs;
+ public long proxCooldownTriggerMs;
/**
* The period(ms) to turning off the prox sensor if
@@ -80,43 +89,78 @@
* @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
* @see #KEY_PROX_COOLDOWN_PERIOD_MS
*/
- public final long proxCooldownPeriodMs;
+ public long proxCooldownPeriodMs;
private final KeyValueListParser mParser;
+ private final Context mContext;
+ private SettingsObserver mSettingsObserver;
public AlwaysOnDisplayPolicy(Context context) {
- final Resources resources = context.getResources();
+ mContext = context;
mParser = new KeyValueListParser(',');
-
- final String value = Settings.Global.getString(context.getContentResolver(),
- Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS);
-
- try {
- mParser.setString(value);
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Bad AOD constants");
- }
-
- proxScreenOffDelayMs = mParser.getLong(KEY_PROX_SCREEN_OFF_DELAY_MS,
- 10 * DateUtils.SECOND_IN_MILLIS);
- proxCooldownTriggerMs = mParser.getLong(KEY_PROX_COOLDOWN_TRIGGER_MS,
- 2 * DateUtils.SECOND_IN_MILLIS);
- proxCooldownPeriodMs = mParser.getLong(KEY_PROX_COOLDOWN_PERIOD_MS,
- 5 * DateUtils.SECOND_IN_MILLIS);
- screenBrightnessArray = parseIntArray(KEY_SCREEN_BRIGHTNESS_ARRAY,
- resources.getIntArray(R.array.config_doze_brightness_sensor_to_brightness));
- dimmingScrimArray = parseIntArray(KEY_DIMMING_SCRIM_ARRAY,
- resources.getIntArray(R.array.config_doze_brightness_sensor_to_scrim_opacity));
+ mSettingsObserver = new SettingsObserver(context.getMainThreadHandler());
+ mSettingsObserver.observe();
}
private int[] parseIntArray(final String key, final int[] defaultArray) {
final String value = mParser.getString(key, null);
if (value != null) {
- return Arrays.stream(value.split(":")).map(String::trim).mapToInt(
- Integer::parseInt).toArray();
+ try {
+ return Arrays.stream(value.split(":")).map(String::trim).mapToInt(
+ Integer::parseInt).toArray();
+ } catch (NumberFormatException e) {
+ return defaultArray;
+ }
} else {
return defaultArray;
}
}
+ private final class SettingsObserver extends ContentObserver {
+ private final Uri ALWAYS_ON_DISPLAY_CONSTANTS_URI
+ = Settings.Global.getUriFor(Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS);
+
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(ALWAYS_ON_DISPLAY_CONSTANTS_URI,
+ false, this, UserHandle.USER_ALL);
+ update(null);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ update(uri);
+ }
+
+ public void update(Uri uri) {
+ if (uri == null || ALWAYS_ON_DISPLAY_CONSTANTS_URI.equals(uri)) {
+ final Resources resources = mContext.getResources();
+ final String value = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS);
+
+ try {
+ mParser.setString(value);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Bad AOD constants");
+ }
+
+ proxScreenOffDelayMs = mParser.getLong(KEY_PROX_SCREEN_OFF_DELAY_MS,
+ DEFAULT_PROX_SCREEN_OFF_DELAY_MS);
+ proxCooldownTriggerMs = mParser.getLong(KEY_PROX_COOLDOWN_TRIGGER_MS,
+ DEFAULT_PROX_COOLDOWN_TRIGGER_MS);
+ proxCooldownPeriodMs = mParser.getLong(KEY_PROX_COOLDOWN_PERIOD_MS,
+ DEFAULT_PROX_COOLDOWN_PERIOD_MS);
+ screenBrightnessArray = parseIntArray(KEY_SCREEN_BRIGHTNESS_ARRAY,
+ resources.getIntArray(
+ R.array.config_doze_brightness_sensor_to_brightness));
+ dimmingScrimArray = parseIntArray(KEY_DIMMING_SCRIM_ARRAY,
+ resources.getIntArray(
+ R.array.config_doze_brightness_sensor_to_scrim_opacity));
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java b/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
index 76a1902..58f1448 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
@@ -28,20 +28,21 @@
public static final String TAG = DozePauser.class.getSimpleName();
private final AlarmTimeout mPauseTimeout;
private final DozeMachine mMachine;
- private final long mTimeoutMs;
+ private final AlwaysOnDisplayPolicy mPolicy;
public DozePauser(Handler handler, DozeMachine machine, AlarmManager alarmManager,
AlwaysOnDisplayPolicy policy) {
mMachine = machine;
mPauseTimeout = new AlarmTimeout(alarmManager, this::onTimeout, TAG, handler);
- mTimeoutMs = policy.proxScreenOffDelayMs;
+ mPolicy = policy;
}
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
switch (newState) {
case DOZE_AOD_PAUSING:
- mPauseTimeout.schedule(mTimeoutMs, AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
+ mPauseTimeout.schedule(mPolicy.proxScreenOffDelayMs,
+ AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
break;
default:
mPauseTimeout.cancel();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 03407e2..4bb4e79 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -22,6 +22,7 @@
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
+import android.os.Trace;
import com.android.internal.annotations.VisibleForTesting;
@@ -94,9 +95,14 @@
@Override
public void onSensorChanged(SensorEvent event) {
- if (mRegistered) {
- mLastSensorValue = (int) event.values[0];
- updateBrightnessAndReady();
+ Trace.beginSection("DozeScreenBrightness.onSensorChanged" + event.values[0]);
+ try {
+ if (mRegistered) {
+ mLastSensorValue = (int) event.values[0];
+ updateBrightnessAndReady();
+ }
+ } finally {
+ Trace.endSection();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 50720e9..b5c0d53 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -29,6 +29,8 @@
import android.os.SystemClock;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
import java.util.LinkedList;
/**
@@ -57,8 +59,12 @@
}
}
- private LinkedList<Command> mCmdQueue = new LinkedList();
+ private final LinkedList<Command> mCmdQueue = new LinkedList<Command>();
+ private final Object mCompletionHandlingLock = new Object();
+ @GuardedBy("mCompletionHandlingLock")
+ private CreationAndCompletionThread mCompletionThread;
+ @GuardedBy("mCompletionHandlingLock")
private Looper mLooper;
/*
@@ -76,7 +82,10 @@
public void run() {
Looper.prepare();
+ // ok to modify mLooper as here we are
+ // synchronized on mCompletionHandlingLock due to the Object.wait() in startSound(cmd)
mLooper = Looper.myLooper();
+ if (DEBUG) Log.d(mTag, "in run: new looper " + mLooper);
synchronized(this) {
AudioManager audioManager =
(AudioManager) mCmd.context.getSystemService(Context.AUDIO_SERVICE);
@@ -97,7 +106,7 @@
if ((mCmd.uri != null) && (mCmd.uri.getEncodedPath() != null)
&& (mCmd.uri.getEncodedPath().length() > 0)) {
if (!audioManager.isMusicActiveRemotely()) {
- synchronized(mQueueAudioFocusLock) {
+ synchronized (mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus == null) {
if (DEBUG) Log.d(mTag, "requesting AudioFocus");
int focusGain = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
@@ -129,7 +138,9 @@
Log.e(mTag, "Exception while sleeping to sync notification playback"
+ " with ducking", e);
}
+ if (DEBUG) { Log.d(mTag, "player.start"); }
if (mPlayer != null) {
+ if (DEBUG) { Log.d(mTag, "mPlayer.release"); }
mPlayer.release();
}
mPlayer = player;
@@ -148,7 +159,7 @@
// is playing, let it continue until we're done, so there
// is less of a glitch.
try {
- if (DEBUG) Log.d(mTag, "Starting playback");
+ if (DEBUG) { Log.d(mTag, "startSound()"); }
//-----------------------------------
// This is were we deviate from the AsyncPlayer implementation and create the
// MediaPlayer in a new thread with which we're synchronized
@@ -158,10 +169,11 @@
// matters
if((mLooper != null)
&& (mLooper.getThread().getState() != Thread.State.TERMINATED)) {
+ if (DEBUG) { Log.d(mTag, "in startSound quitting looper " + mLooper); }
mLooper.quit();
}
mCompletionThread = new CreationAndCompletionThread(cmd);
- synchronized(mCompletionThread) {
+ synchronized (mCompletionThread) {
mCompletionThread.start();
mCompletionThread.wait();
}
@@ -209,13 +221,18 @@
mPlayer = null;
synchronized(mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus != null) {
+ if (DEBUG) { Log.d(mTag, "in STOP: abandonning AudioFocus"); }
mAudioManagerWithAudioFocus.abandonAudioFocus(null);
mAudioManagerWithAudioFocus = null;
}
}
- if((mLooper != null)
- && (mLooper.getThread().getState() != Thread.State.TERMINATED)) {
- mLooper.quit();
+ synchronized (mCompletionHandlingLock) {
+ if ((mLooper != null) &&
+ (mLooper.getThread().getState() != Thread.State.TERMINATED))
+ {
+ if (DEBUG) { Log.d(mTag, "in STOP: quitting looper "+ mLooper); }
+ mLooper.quit();
+ }
}
} else {
Log.w(mTag, "STOP command without a player");
@@ -250,9 +267,11 @@
}
// if there are no more sounds to play, end the Looper to listen for media completion
synchronized (mCmdQueue) {
- if (mCmdQueue.size() == 0) {
- synchronized(mCompletionHandlingLock) {
- if(mLooper != null) {
+ synchronized(mCompletionHandlingLock) {
+ if (DEBUG) { Log.d(mTag, "onCompletion queue size=" + mCmdQueue.size()); }
+ if ((mCmdQueue.size() == 0)) {
+ if (mLooper != null) {
+ if (DEBUG) { Log.d(mTag, "in onCompletion quitting looper " + mLooper); }
mLooper.quit();
}
mCompletionThread = null;
@@ -269,13 +288,20 @@
}
private String mTag;
+
+ @GuardedBy("mCmdQueue")
private CmdThread mThread;
- private CreationAndCompletionThread mCompletionThread;
- private final Object mCompletionHandlingLock = new Object();
+
private MediaPlayer mPlayer;
+
+
+ @GuardedBy("mCmdQueue")
private PowerManager.WakeLock mWakeLock;
+
private final Object mQueueAudioFocusLock = new Object();
- private AudioManager mAudioManagerWithAudioFocus; // synchronized on mQueueAudioFocusLock
+ @GuardedBy("mQueueAudioFocusLock")
+ private AudioManager mAudioManagerWithAudioFocus;
+
private int mNotificationRampTimeMs = 0;
// The current state according to the caller. Reality lags behind
@@ -311,6 +337,7 @@
*/
@Deprecated
public void play(Context context, Uri uri, boolean looping, int stream) {
+ if (DEBUG) { Log.d(mTag, "play uri=" + uri.toString()); }
PlayerBase.deprecateStreamTypeForPlayback(stream, "NotificationPlayer", "play");
Command cmd = new Command();
cmd.requestTime = SystemClock.uptimeMillis();
@@ -339,6 +366,7 @@
* (see {@link MediaPlayer#setAudioAttributes(AudioAttributes)})
*/
public void play(Context context, Uri uri, boolean looping, AudioAttributes attributes) {
+ if (DEBUG) { Log.d(mTag, "play uri=" + uri.toString()); }
Command cmd = new Command();
cmd.requestTime = SystemClock.uptimeMillis();
cmd.code = PLAY;
@@ -357,6 +385,7 @@
* at this point. Calling this multiple times has no ill effects.
*/
public void stop() {
+ if (DEBUG) { Log.d(mTag, "stop"); }
synchronized (mCmdQueue) {
// This check allows stop to be called multiple times without starting
// a thread that ends up doing nothing.
@@ -370,6 +399,7 @@
}
}
+ @GuardedBy("mCmdQueue")
private void enqueueLocked(Command cmd) {
mCmdQueue.add(cmd);
if (mThread == null) {
@@ -393,22 +423,26 @@
* @hide
*/
public void setUsesWakeLock(Context context) {
- if (mWakeLock != null || mThread != null) {
- // if either of these has happened, we've already played something.
- // and our releases will be out of sync.
- throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock
- + " mThread=" + mThread);
+ synchronized (mCmdQueue) {
+ if (mWakeLock != null || mThread != null) {
+ // if either of these has happened, we've already played something.
+ // and our releases will be out of sync.
+ throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock
+ + " mThread=" + mThread);
+ }
+ PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
}
- PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
}
+ @GuardedBy("mCmdQueue")
private void acquireWakeLock() {
if (mWakeLock != null) {
mWakeLock.acquire();
}
}
+ @GuardedBy("mCmdQueue")
private void releaseWakeLock() {
if (mWakeLock != null) {
mWakeLock.release();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index bae9ef8a..58243b4 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -17,6 +17,8 @@
package com.android.systemui.pip.phone;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.Display.DEFAULT_DISPLAY;
import android.app.ActivityManager;
@@ -199,7 +201,8 @@
public final void onBusEvent(ExpandPipEvent event) {
if (event.clearThumbnailWindows) {
try {
- StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ StackInfo stackInfo = mActivityManager.getStackInfo(
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
if (stackInfo != null && stackInfo.taskIds != null) {
SystemServicesProxy ssp = SystemServicesProxy.getInstance(mContext);
for (int taskId : stackInfo.taskIds) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 68743b3..d71d4de 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -17,6 +17,8 @@
package com.android.systemui.pip.phone;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityOptions;
@@ -383,7 +385,8 @@
private void startMenuActivity(int menuState, Rect stackBounds, Rect movementBounds,
boolean allowMenuTimeout, boolean willResizeMenu) {
try {
- StackInfo pinnedStackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ StackInfo pinnedStackInfo = mActivityManager.getStackInfo(
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
pinnedStackInfo.taskIds.length > 0) {
Intent intent = new Intent(mContext, PipMenuActivity.class);
@@ -421,7 +424,8 @@
// Fetch the pinned stack bounds
Rect stackBounds = null;
try {
- StackInfo pinnedStackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ StackInfo pinnedStackInfo = mActivityManager.getStackInfo(
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
if (pinnedStackInfo != null) {
stackBounds = pinnedStackInfo.bounds;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index cebb22f..eef0e7d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -18,6 +18,8 @@
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static com.android.systemui.Interpolators.FAST_OUT_LINEAR_IN;
import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN;
@@ -121,7 +123,8 @@
void synchronizePinnedStackBounds() {
cancelAnimations();
try {
- StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ StackInfo stackInfo =
+ mActivityManager.getStackInfo(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
if (stackInfo != null) {
mBounds.set(stackInfo.bounds);
}
@@ -529,7 +532,8 @@
Rect toBounds = (Rect) args.arg1;
int duration = args.argi1;
try {
- StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ StackInfo stackInfo = mActivityManager.getStackInfo(
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
if (stackInfo == null) {
// In the case where we've already re-expanded or dismissed the PiP, then
// just skip the resize
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
index 56275fd..84410f2 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
@@ -17,6 +17,8 @@
package com.android.systemui.pip.phone;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import android.app.ActivityManager.StackInfo;
import android.app.IActivityManager;
@@ -38,7 +40,8 @@
IActivityManager activityManager) {
try {
final String sysUiPackageName = context.getPackageName();
- final StackInfo pinnedStackInfo = activityManager.getStackInfo(PINNED_STACK_ID);
+ final StackInfo pinnedStackInfo =
+ activityManager.getStackInfo(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
pinnedStackInfo.taskIds.length > 0) {
for (int i = pinnedStackInfo.taskNames.length - 1; i >= 0; i--) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 186de5c4..6e85549 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -54,6 +54,8 @@
import java.util.List;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.Display.DEFAULT_DISPLAY;
/**
@@ -502,7 +504,8 @@
private StackInfo getPinnedStackInfo() {
StackInfo stackInfo = null;
try {
- stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ stackInfo = mActivityManager.getStackInfo(
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
} catch (RemoteException e) {
Log.e(TAG, "getStackInfo failed", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 8d62f2a..81b8622 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -23,6 +23,7 @@
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
+import android.graphics.drawable.Drawable;
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.text.TextUtils;
@@ -34,10 +35,8 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.R.drawable;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
@@ -135,11 +134,7 @@
if (lastDevice != null) {
int batteryLevel = lastDevice.getBatteryLevel();
if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
- BluetoothDeviceLayerDrawable drawable = createLayerDrawable(mContext,
- R.drawable.ic_qs_bluetooth_connected, batteryLevel,
- mContext.getResources().getFraction(
- R.fraction.bt_battery_scale_fraction, 1, 1));
- state.icon = new DrawableIcon(drawable);
+ state.icon = new BluetoothBatteryDrawable(batteryLevel);
}
}
state.contentDescription = mContext.getString(
@@ -215,6 +210,22 @@
return new BluetoothDetailAdapter();
}
+ private class BluetoothBatteryDrawable extends Icon {
+ private int mLevel;
+
+ BluetoothBatteryDrawable(int level) {
+ mLevel = level;
+ }
+
+ @Override
+ public Drawable getDrawable(Context context) {
+ return createLayerDrawable(context,
+ R.drawable.ic_qs_bluetooth_connected, mLevel,
+ context.getResources().getFraction(
+ R.fraction.bt_battery_scale_fraction, 1, 1));
+ }
+ }
+
protected class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
// We probably won't ever have space in the UI for more than 20 devices, so don't
// get info for them.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 2e389ba..0ce3e6a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -266,7 +266,7 @@
}
@Override
- public void setNoSims(boolean show) {
+ public void setNoSims(boolean show, boolean simDetected) {
mInfo.noSim = show;
if (mInfo.noSim) {
// Make sure signal gets cleared out when no sims.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 406bcac..283ac0c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -16,6 +16,9 @@
package com.android.systemui.recents;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
import android.app.ActivityManager;
@@ -437,9 +440,12 @@
int currentUser = sSystemServicesProxy.getCurrentUser();
SystemServicesProxy ssp = Recents.getSystemServices();
ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+ final int activityType = runningTask != null
+ ? runningTask.configuration.windowConfiguration.getActivityType()
+ : ACTIVITY_TYPE_UNDEFINED;
boolean screenPinningActive = ssp.isScreenPinningActive();
- boolean isRunningTaskInHomeOrRecentsStack = runningTask != null &&
- ActivityManager.StackId.isHomeOrRecentsStack(runningTask.stackId);
+ boolean isRunningTaskInHomeOrRecentsStack =
+ activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS;
if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) {
logDockAttempt(mContext, runningTask.topActivity, runningTask.resizeMode);
if (runningTask.supportsSplitScreenMultiWindow) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 43227ab..dc83333 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -17,8 +17,8 @@
package com.android.systemui.recents;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.ActivityManager.StackId.isHomeOrRecentsStack;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.view.View.MeasureSpec;
import android.app.ActivityManager;
@@ -533,7 +533,9 @@
if (runningTask == null) return;
// Find the task in the recents list
- boolean isRunningTaskInHomeStack = SystemServicesProxy.isHomeStack(runningTask.stackId);
+ boolean isRunningTaskInHomeStack =
+ runningTask.configuration.windowConfiguration.getActivityType()
+ == ACTIVITY_TYPE_HOME;
ArrayList<Task> tasks = focusedStack.getStackTasks();
Task toTask = null;
ActivityOptions launchOpts = null;
@@ -583,9 +585,10 @@
// Return early if there is no running task (can't determine affiliated tasks in this case)
ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+ final int activityType = runningTask.configuration.windowConfiguration.getActivityType();
if (runningTask == null) return;
// Return early if the running task is in the home/recents stack (optimization)
- if (isHomeOrRecentsStack(runningTask.stackId)) return;
+ if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) return;
// Find the task in the recents list
ArrayList<Task> tasks = focusedStack.getStackTasks();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideStackActionButtonEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideStackActionButtonEvent.java
index e02fb14..e4a4f59 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideStackActionButtonEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideStackActionButtonEvent.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,5 +22,15 @@
* This is sent when the stack action button should be hidden.
*/
public class HideStackActionButtonEvent extends EventBus.Event {
- // Simple event
+
+ // Whether or not to translate the stack action button when hiding it
+ public final boolean translate;
+
+ public HideStackActionButtonEvent() {
+ this(true);
+ }
+
+ public HideStackActionButtonEvent(boolean translate) {
+ this.translate = translate;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 5a5251e..4580b1f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -18,12 +18,12 @@
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.FULLSCREEN_WORKSPACE_STACK_ID;
-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.app.ActivityManager.StackId.RECENTS_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -38,6 +38,7 @@
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.KeyguardManager;
+import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -486,16 +487,22 @@
public ActivityManager.RunningTaskInfo getRunningTask() {
// Note: The set of running tasks from the system is ordered by recency
List<ActivityManager.RunningTaskInfo> tasks = mAm.getRunningTasks(10);
- if (tasks != null && !tasks.isEmpty()) {
- // Find the first task in a valid stack, we ignore everything from the Recents and PiP
- // stacks
- for (int i = 0; i < tasks.size(); i++) {
- ActivityManager.RunningTaskInfo task = tasks.get(i);
- int stackId = task.stackId;
- if (stackId != RECENTS_STACK_ID && stackId != PINNED_STACK_ID) {
- return task;
- }
+ if (tasks == null || tasks.isEmpty()) {
+ return null;
+ }
+
+ // Find the first task in a valid stack, we ignore everything from the Recents and PiP
+ // stacks
+ for (int i = 0; i < tasks.size(); i++) {
+ final ActivityManager.RunningTaskInfo task = tasks.get(i);
+ final WindowConfiguration winConfig = task.configuration.windowConfiguration;
+ if (winConfig.getActivityType() == ACTIVITY_TYPE_RECENTS) {
+ continue;
}
+ if (winConfig.getWindowingMode() == WINDOWING_MODE_PINNED) {
+ continue;
+ }
+ return task;
}
return null;
}
@@ -522,12 +529,17 @@
ActivityManager.StackInfo fullscreenStackInfo = null;
ActivityManager.StackInfo recentsStackInfo = null;
for (int i = 0; i < stackInfos.size(); i++) {
- StackInfo stackInfo = stackInfos.get(i);
- if (stackInfo.stackId == HOME_STACK_ID) {
+ final StackInfo stackInfo = stackInfos.get(i);
+ final WindowConfiguration winConfig = stackInfo.configuration.windowConfiguration;
+ final int activityType = winConfig.getActivityType();
+ final int windowingMode = winConfig.getWindowingMode();
+ if (activityType == ACTIVITY_TYPE_HOME) {
homeStackInfo = stackInfo;
- } else if (stackInfo.stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+ } else if (activityType == ACTIVITY_TYPE_STANDARD
+ && (windowingMode == WINDOWING_MODE_FULLSCREEN
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)) {
fullscreenStackInfo = stackInfo;
- } else if (stackInfo.stackId == RECENTS_STACK_ID) {
+ } else if (activityType == ACTIVITY_TYPE_RECENTS) {
recentsStackInfo = stackInfo;
}
}
@@ -606,27 +618,6 @@
}
/**
- * Returns whether the given stack id is the home stack id.
- */
- public static boolean isHomeStack(int stackId) {
- return stackId == HOME_STACK_ID;
- }
-
- /**
- * Returns whether the given stack id is the pinned stack id.
- */
- public static boolean isPinnedStack(int stackId){
- return stackId == PINNED_STACK_ID;
- }
-
- /**
- * Returns whether the given stack id is the docked stack id.
- */
- public static boolean isDockedStack(int stackId) {
- return stackId == DOCKED_STACK_ID;
- }
-
- /**
* Returns whether the given stack id is the freeform workspace stack id.
*/
public static boolean isFreeformStack(int stackId) {
@@ -641,7 +632,8 @@
ActivityManager.StackInfo stackInfo = null;
try {
- stackInfo = mIam.getStackInfo(DOCKED_STACK_ID);
+ stackInfo =
+ mIam.getStackInfo(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
} catch (RemoteException e) {
e.printStackTrace();
}
@@ -1106,9 +1098,10 @@
try {
// Use the recents stack bounds, fallback to fullscreen stack if it is null
- ActivityManager.StackInfo stackInfo = mIam.getStackInfo(RECENTS_STACK_ID);
+ ActivityManager.StackInfo stackInfo =
+ mIam.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS);
if (stackInfo == null) {
- stackInfo = mIam.getStackInfo(FULLSCREEN_WORKSPACE_STACK_ID);
+ stackInfo = mIam.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD);
}
if (stackInfo != null) {
windowRect.set(stackInfo.bounds);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 4d33216..ee05d81 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -16,11 +16,6 @@
package com.android.systemui.recents.views;
-import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
-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.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
@@ -32,7 +27,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.annotation.Nullable;
-import android.app.ActivityManager.StackId;
import android.app.ActivityOptions;
import android.app.ActivityOptions.OnAnimationStartedListener;
import android.content.Context;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index fd1b806..16c74e3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -174,8 +174,6 @@
? R.layout.recents_low_ram_stack_action_button
: R.layout.recents_stack_action_button,
this, false);
- mStackActionButton.setOnClickListener(
- v -> EventBus.getDefault().send(new DismissAllTaskViewsEvent()));
mStackButtonShadowRadius = mStackActionButton.getShadowRadius();
mStackButtonShadowDistance = new PointF(mStackActionButton.getShadowDx(),
@@ -553,7 +551,7 @@
event.taskView, event.screenPinningRequested, event.targetWindowingMode,
event.targetActivityType);
if (Recents.getConfiguration().isLowRamDevice) {
- hideStackActionButton(HIDE_STACK_ACTION_BUTTON_DURATION, false /* translate */);
+ EventBus.getDefault().send(new HideStackActionButtonEvent(false /* translate */));
}
}
@@ -561,7 +559,7 @@
int taskViewExitToHomeDuration = TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION;
if (RecentsDebugFlags.Static.EnableStackActionButton) {
// Hide the stack action button
- hideStackActionButton(taskViewExitToHomeDuration, false /* translate */);
+ EventBus.getDefault().send(new HideStackActionButtonEvent());
}
animateBackgroundScrim(0f, taskViewExitToHomeDuration);
@@ -722,13 +720,10 @@
animateBackgroundScrim(getOpaqueScrimAlpha(),
TaskStackAnimationHelper.ENTER_FROM_HOME_TRANSLATION_DURATION);
}
- if (Recents.getConfiguration().isLowRamDevice && mEmptyView.getVisibility() != View.VISIBLE) {
- showStackActionButton(SHOW_STACK_ACTION_BUTTON_DURATION, false /* translate */);
- }
}
public final void onBusEvent(AllTaskViewsDismissedEvent event) {
- hideStackActionButton(HIDE_STACK_ACTION_BUTTON_DURATION, true /* translate */);
+ EventBus.getDefault().send(new HideStackActionButtonEvent());
}
public final void onBusEvent(DismissAllTaskViewsEvent event) {
@@ -776,7 +771,8 @@
mStackActionButton.setVisibility(View.VISIBLE);
mStackActionButton.setAlpha(0f);
if (translate) {
- mStackActionButton.setTranslationY(-mStackActionButton.getMeasuredHeight() * 0.25f);
+ mStackActionButton.setTranslationY(mStackActionButton.getMeasuredHeight() *
+ (Recents.getConfiguration().isLowRamDevice ? 1 : -0.25f));
} else {
mStackActionButton.setTranslationY(0f);
}
@@ -822,8 +818,8 @@
if (mStackActionButton.getVisibility() == View.VISIBLE) {
if (translate) {
- mStackActionButton.animate()
- .translationY(-mStackActionButton.getMeasuredHeight() * 0.25f);
+ mStackActionButton.animate().translationY(mStackActionButton.getMeasuredHeight()
+ * (Recents.getConfiguration().isLowRamDevice ? 1 : -0.25f));
}
mStackActionButton.animate()
.alpha(0f)
@@ -935,7 +931,7 @@
/**
* @return the bounds of the stack action button.
*/
- private Rect getStackActionButtonBoundsFromStackLayout() {
+ Rect getStackActionButtonBoundsFromStackLayout() {
Rect actionButtonRect = new Rect(mTaskStackView.mLayoutAlgorithm.getStackActionButtonRect());
int left, top;
if (Recents.getConfiguration().isLowRamDevice) {
@@ -957,6 +953,16 @@
return actionButtonRect;
}
+ View getStackActionButton() {
+ return mStackActionButton;
+ }
+
+ @Override
+ public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+ super.requestDisallowInterceptTouchEvent(disallowIntercept);
+ mTouchHandler.cancelStackActionButtonClick();
+ }
+
public void dump(String prefix, PrintWriter writer) {
String innerPrefix = prefix + " ";
String id = Integer.toHexString(System.identityHashCode(this));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 46619c2..b6b24bc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -23,6 +23,7 @@
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.PointerIcon;
+import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewDebug;
@@ -31,6 +32,8 @@
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
+import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
+import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
import com.android.systemui.recents.events.ui.HideIncompatibleAppOverlayEvent;
import com.android.systemui.recents.events.ui.ShowIncompatibleAppOverlayEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
@@ -99,8 +102,7 @@
/** Touch preprocessing for handling below */
public boolean onInterceptTouchEvent(MotionEvent ev) {
- handleTouchEvent(ev);
- return mDragRequested;
+ return handleTouchEvent(ev) || mDragRequested;
}
/** Handles touch events once we have intercepted them */
@@ -183,22 +185,47 @@
}
}
+ void cancelStackActionButtonClick() {
+ mRv.getStackActionButton().setPressed(false);
+ }
+
+ private boolean isWithinStackActionButton(float x, float y) {
+ Rect rect = mRv.getStackActionButtonBoundsFromStackLayout();
+ return mRv.getStackActionButton().getVisibility() == View.VISIBLE &&
+ mRv.getStackActionButton().pointInView(x - rect.left, y - rect.top, 0 /* slop */);
+ }
+
+ private void changeStackActionButtonDrawableHotspot(float x, float y) {
+ Rect rect = mRv.getStackActionButtonBoundsFromStackLayout();
+ mRv.getStackActionButton().drawableHotspotChanged(x - rect.left, y - rect.top);
+ }
+
/**
* Handles dragging touch events
*/
- private void handleTouchEvent(MotionEvent ev) {
+ private boolean handleTouchEvent(MotionEvent ev) {
int action = ev.getActionMasked();
+ boolean consumed = false;
+ float evX = ev.getX();
+ float evY = ev.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
- mDownPos.set((int) ev.getX(), (int) ev.getY());
+ mDownPos.set((int) evX, (int) evY);
mDeviceId = ev.getDeviceId();
+
+ if (isWithinStackActionButton(evX, evY)) {
+ changeStackActionButtonDrawableHotspot(evX, evY);
+ mRv.getStackActionButton().setPressed(true);
+ }
break;
case MotionEvent.ACTION_MOVE: {
- float evX = ev.getX();
- float evY = ev.getY();
float x = evX - mTaskViewOffset.x;
float y = evY - mTaskViewOffset.y;
+ if (mRv.getStackActionButton().isPressed() && isWithinStackActionButton(evX, evY)) {
+ changeStackActionButtonDrawableHotspot(evX, evY);
+ }
+
if (mDragRequested) {
if (!mIsDragging) {
mIsDragging = Math.hypot(evX - mDownPos.x, evY - mDownPos.y) > mDragSlop;
@@ -232,9 +259,7 @@
EventBus.getDefault().send(new DragDropTargetChangedEvent(mDragTask,
currentDropTarget));
}
-
}
-
mTaskView.setTranslationX(x);
mTaskView.setTranslationY(y);
}
@@ -242,6 +267,11 @@
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
+ if (mRv.getStackActionButton().isPressed() && isWithinStackActionButton(evX, evY)) {
+ EventBus.getDefault().send(new DismissAllTaskViewsEvent());
+ consumed = true;
+ }
+ cancelStackActionButtonClick();
if (mDragRequested) {
boolean cancelled = action == MotionEvent.ACTION_CANCEL;
if (cancelled) {
@@ -254,5 +284,6 @@
mDeviceId = -1;
}
}
+ return consumed;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 74e9ef2..7ede0c5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -1768,8 +1768,17 @@
}
// In grid layout, the stack action button always remains visible.
- if (mEnterAnimationComplete && !useGridLayout() &&
- !Recents.getConfiguration().isLowRamDevice) {
+ if (mEnterAnimationComplete && !useGridLayout()) {
+ if (Recents.getConfiguration().isLowRamDevice) {
+ // Show stack button when user drags down to show older tasks on low ram devices
+ if (mStack.getTaskCount() > 0 && !mStackActionButtonVisible
+ && mTouchHandler.mIsScrolling && curScroll - prevScroll < 0) {
+ // Going up
+ EventBus.getDefault().send(
+ new ShowStackActionButtonEvent(true /* translate */));
+ }
+ return;
+ }
if (prevScroll > SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
curScroll <= SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
mStack.getTaskCount() > 0) {
@@ -1956,6 +1965,9 @@
// Remove the task from the stack
mStack.removeTask(event.task, event.animation, false /* fromDockGesture */);
EventBus.getDefault().send(new DeleteTaskDataEvent(event.task));
+ if (mStack.getTaskCount() > 0 && Recents.getConfiguration().isLowRamDevice) {
+ EventBus.getDefault().send(new ShowStackActionButtonEvent(false /* translate */));
+ }
MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS,
event.task.key.getComponent().toString());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java
index bcf4f17..2d7cfb1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java
@@ -26,8 +26,8 @@
public class GridTaskViewThumbnail extends TaskViewThumbnail {
- private Path mThumbnailOutline;
- private Path mRestBackgroundOutline;
+ private final Path mThumbnailOutline = new Path();
+ private final Path mRestBackgroundOutline = new Path();
// True if either this view's size or thumbnail scale has changed and mThumbnailOutline should
// be updated.
private boolean mUpdateThumbnailOutline = true;
@@ -77,47 +77,38 @@
(int) (mThumbnailRect.width() * mThumbnailScale));
final int thumbnailHeight = Math.min(viewHeight,
(int) (mThumbnailRect.height() * mThumbnailScale));
- // Draw the thumbnail, we only round the bottom corners:
- //
- // outerLeft outerRight
- // <-----------------------> mRestBackgroundOutline
- // _________________________ (thumbnailWidth < viewWidth)
- // |_______________________| outerTop A ____ B
- // | | ↑ | |
- // | | | | |
- // | | | | |
- // | | | | | C
- // \_______________________/ ↓ |__/
- // mCornerRadius outerBottom E D
- //
- // mRestBackgroundOutline (thumbnailHeight < viewHeight)
- // A _________________________ B
- // | | C
- // F \_______________________/
- // E D
- final int outerLeft = 0;
- final int outerTop = 0;
- final int outerRight = outerLeft + thumbnailWidth;
- final int outerBottom = outerTop + thumbnailHeight;
- mThumbnailOutline = new Path();
- mThumbnailOutline.moveTo(outerLeft, outerTop);
- mThumbnailOutline.lineTo(outerRight, outerTop);
- mThumbnailOutline.lineTo(outerRight, outerBottom - mCornerRadius);
- mThumbnailOutline.arcTo(outerRight - 2 * mCornerRadius, outerBottom - 2 * mCornerRadius,
- outerRight, outerBottom, 0, 90, false);
- mThumbnailOutline.lineTo(outerLeft + mCornerRadius, outerBottom);
- mThumbnailOutline.arcTo(outerLeft, outerBottom - 2 * mCornerRadius,
- outerLeft + 2 * mCornerRadius, outerBottom, 90, 90, false);
- mThumbnailOutline.lineTo(outerLeft, outerTop);
- mThumbnailOutline.close();
if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) {
+ // Draw the thumbnail, we only round the bottom corners:
+ //
+ // outerLeft outerRight
+ // <-----------------------> mRestBackgroundOutline
+ // _________________________ (thumbnailWidth < viewWidth)
+ // |_______________________| outerTop A ____ B
+ // | | ↑ | |
+ // | | | | |
+ // | | | | |
+ // | | | | | C
+ // \_______________________/ ↓ |__/
+ // mCornerRadius outerBottom E D
+ //
+ // mRestBackgroundOutline (thumbnailHeight < viewHeight)
+ // A _________________________ B
+ // | | C
+ // F \_______________________/
+ // E D
+ final int outerLeft = 0;
+ final int outerTop = 0;
+ final int outerRight = outerLeft + thumbnailWidth;
+ final int outerBottom = outerTop + thumbnailHeight;
+ createThumbnailPath(outerLeft, outerTop, outerRight, outerBottom, mThumbnailOutline);
+
if (thumbnailWidth < viewWidth) {
final int l = Math.max(0, outerRight - mCornerRadius);
final int r = outerRight;
final int t = outerTop;
final int b = outerBottom;
- mRestBackgroundOutline = new Path();
+ mRestBackgroundOutline.reset();
mRestBackgroundOutline.moveTo(l, t); // A
mRestBackgroundOutline.lineTo(r, t); // B
mRestBackgroundOutline.lineTo(r, b - mCornerRadius); // C
@@ -133,7 +124,7 @@
final int r = outerRight;
final int t = Math.max(0, thumbnailHeight - mCornerRadius);
final int b = outerBottom;
- mRestBackgroundOutline = new Path();
+ mRestBackgroundOutline.reset();
mRestBackgroundOutline.moveTo(l, t); // A
mRestBackgroundOutline.lineTo(r, t); // B
mRestBackgroundOutline.lineTo(r, b - mCornerRadius); // C
@@ -145,9 +136,26 @@
mRestBackgroundOutline.lineTo(l, t); // A
mRestBackgroundOutline.close();
}
+ } else {
+ createThumbnailPath(0, 0, viewWidth, viewHeight, mThumbnailOutline);
}
}
+ private void createThumbnailPath(int outerLeft, int outerTop, int outerRight, int outerBottom,
+ Path outPath) {
+ outPath.reset();
+ outPath.moveTo(outerLeft, outerTop);
+ outPath.lineTo(outerRight, outerTop);
+ outPath.lineTo(outerRight, outerBottom - mCornerRadius);
+ outPath.arcTo(outerRight - 2 * mCornerRadius, outerBottom - 2 * mCornerRadius, outerRight,
+ outerBottom, 0, 90, false);
+ outPath.lineTo(outerLeft + mCornerRadius, outerBottom);
+ outPath.arcTo(outerLeft, outerBottom - 2 * mCornerRadius, outerLeft + 2 * mCornerRadius,
+ outerBottom, 90, 90, false);
+ outPath.lineTo(outerLeft, outerTop);
+ outPath.close();
+ }
+
@Override
protected void onDraw(Canvas canvas) {
final int titleHeight = getResources().getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 44e60ee..7bcef57 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -16,6 +16,9 @@
package com.android.systemui.stackdivider;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
@@ -23,7 +26,6 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
-import android.app.ActivityManager.StackId;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -36,8 +38,6 @@
import android.view.Choreographer;
import android.view.Display;
import android.view.DisplayInfo;
-import android.view.GestureDetector;
-import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.VelocityTracker;
@@ -62,8 +62,8 @@
import com.android.internal.view.SurfaceFlingerVsyncChoreographer;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.activity.UndockingTaskEvent;
@@ -661,7 +661,7 @@
} else {
mWindowManagerProxy.maximizeDockedStack();
}
- mWindowManagerProxy.setResizeDimLayer(false, -1, 0f);
+ mWindowManagerProxy.setResizeDimLayer(false, WINDOWING_MODE_UNDEFINED, 0f);
}
private void liftBackground() {
@@ -997,8 +997,7 @@
SnapTarget closestDismissTarget = getSnapAlgorithm().getClosestDismissTarget(position);
float dimFraction = getDimFraction(position, closestDismissTarget);
mWindowManagerProxy.setResizeDimLayer(dimFraction != 0f,
- getStackIdForDismissTarget(closestDismissTarget),
- dimFraction);
+ getWindowingModeForDismissTarget(closestDismissTarget), dimFraction);
}
private void applyExitAnimationParallax(Rect taskRect, int position) {
@@ -1132,13 +1131,13 @@
}
}
- private int getStackIdForDismissTarget(SnapTarget dismissTarget) {
+ private int getWindowingModeForDismissTarget(SnapTarget dismissTarget) {
if ((dismissTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(mDockSide))
|| (dismissTarget.flag == SnapTarget.FLAG_DISMISS_END
&& dockSideBottomRight(mDockSide))) {
- return StackId.DOCKED_STACK_ID;
+ return WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
} else {
- return StackId.RECENTS_STACK_ID;
+ return WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
}
}
@@ -1192,6 +1191,10 @@
}
}
+ public final void onBusEvent(DockedFirstAnimationFrameEvent event) {
+ saveSnapTargetBeforeMinimized(mSnapAlgorithm.getMiddleTarget());
+ }
+
public final void onBusEvent(DockedTopTaskEvent event) {
if (event.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) {
mState.growAfterRecentsDrawn = false;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 185f6e3..f7c0411 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -56,7 +56,7 @@
private final Rect mTouchableRegion = new Rect();
private boolean mDimLayerVisible;
- private int mDimLayerTargetStack;
+ private int mDimLayerTargetWindowingMode;
private float mDimLayerAlpha;
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
@@ -113,7 +113,7 @@
public void run() {
try {
WindowManagerGlobal.getWindowManagerService().setResizeDimLayer(mDimLayerVisible,
- mDimLayerTargetStack, mDimLayerAlpha);
+ mDimLayerTargetWindowingMode, mDimLayerAlpha);
} catch (RemoteException e) {
Log.w(TAG, "Failed to resize stack: " + e);
}
@@ -200,9 +200,9 @@
return DOCKED_INVALID;
}
- public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+ public void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) {
mDimLayerVisible = visible;
- mDimLayerTargetStack = targetStackId;
+ mDimLayerTargetWindowingMode = targetWindowingMode;
mDimLayerAlpha = alpha;
mExecutor.execute(mDimLayerRunnable);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 759d2cf..a7fb61a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -16,14 +16,15 @@
package com.android.systemui.statusbar;
+import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
+import static android.app.StatusBarManager.DISABLE_NONE;
+
import android.annotation.DrawableRes;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
-import android.graphics.drawable.Animatable;
-import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.telephony.SubscriptionInfo;
import android.util.ArraySet;
@@ -50,14 +51,15 @@
import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.util.Utils.DisableStateTracker;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
// Intimately tied to the design of res/layout/signal_cluster_view.xml
public class SignalClusterView extends LinearLayout implements NetworkControllerImpl.SignalCallback,
- SecurityController.SecurityControllerCallback, Tunable,
- DarkReceiver {
+ SecurityController.SecurityControllerCallback, Tunable, DarkReceiver {
static final String TAG = "SignalClusterView";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -73,6 +75,7 @@
private boolean mNoSimsVisible = false;
private boolean mVpnVisible = false;
+ private boolean mSimDetected;
private int mVpnIconId = 0;
private int mLastVpnIconId = -1;
private boolean mEthernetVisible = false;
@@ -148,6 +151,8 @@
mIconScaleFactor = typedValue.getFloat();
mNetworkController = Dependency.get(NetworkController.class);
mSecurityController = Dependency.get(SecurityController.class);
+ addOnAttachStateChangeListener(
+ new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS));
updateActivityEnabled();
}
@@ -327,8 +332,9 @@
}
@Override
- public void setNoSims(boolean show) {
+ public void setNoSims(boolean show, boolean simDetected) {
mNoSimsVisible = show && !mBlockMobile;
+ mSimDetected = simDetected;
apply();
}
@@ -548,6 +554,23 @@
if (mNoSimsVisible) {
mIconLogger.onIconShown(SLOT_MOBILE);
mNoSimsCombo.setVisibility(View.VISIBLE);
+ if (!Objects.equals(mSimDetected, mNoSimsCombo.getTag())) {
+ mNoSimsCombo.setTag(mSimDetected);
+ if (mSimDetected) {
+ SignalDrawable d = new SignalDrawable(mNoSims.getContext());
+ d.setDarkIntensity(0);
+ mNoSims.setImageDrawable(d);
+ mNoSims.setImageLevel(SignalDrawable.getEmptyState(4));
+
+ SignalDrawable dark = new SignalDrawable(mNoSims.getContext());
+ dark.setDarkIntensity(1);
+ mNoSimsDark.setImageDrawable(dark);
+ mNoSimsDark.setImageLevel(SignalDrawable.getEmptyState(4));
+ } else {
+ mNoSims.setImageResource(R.drawable.stat_sys_no_sims);
+ mNoSimsDark.setImageResource(R.drawable.stat_sys_no_sims);
+ }
+ }
} else {
mIconLogger.onIconHidden(SLOT_MOBILE);
mNoSimsCombo.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index 9d2d71e..f5c77f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -21,7 +21,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import android.app.ActivityManager.StackId;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -107,7 +107,7 @@
}
}
- public void taskChanged(String packageName, int stackId) {
+ public void taskChanged(String packageName, ActivityManager.RunningTaskInfo taskInfo) {
// If the package name belongs to a filter, then highlight appropriate button in
// the navigation bar.
if (mFacetPackageMap.containsKey(packageName)) {
@@ -121,8 +121,9 @@
}
// Set up the persistent docked task if needed.
- if (mPersistentTaskIntent != null && !mStatusBar.hasDockedTask()
- && stackId != StackId.HOME_STACK_ID) {
+ boolean isHomeTask =
+ taskInfo.configuration.windowConfiguration.getActivityType() == ACTIVITY_TYPE_HOME;
+ if (mPersistentTaskIntent != null && !mStatusBar.hasDockedTask() && !isHomeTask) {
mStatusBar.startActivityOnStack(mPersistentTaskIntent,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 10fc496..59d3e0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -314,7 +314,7 @@
ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
if (runningTaskInfo != null && runningTaskInfo.baseActivity != null) {
mController.taskChanged(runningTaskInfo.baseActivity.getPackageName(),
- runningTaskInfo.stackId);
+ runningTaskInfo);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index 533771a..d226fed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -264,8 +264,10 @@
pw.println(" StatusBarTransitionsController:");
mStatusBarIconController.getTransitionsController().dump(fd, pw, args);
pw.println();
- pw.println(" NavigationBarTransitionsController:");
- mNavigationBarController.dump(fd, pw, args);
- pw.println();
+ if (mNavigationBarController != null) {
+ pw.println(" NavigationBarTransitionsController:");
+ mNavigationBarController.dump(fd, pw, args);
+ pw.println();
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index cfe0a4a..6d3bc1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -437,7 +437,7 @@
}
private boolean onNavigationTouch(View v, MotionEvent event) {
- mStatusBar.checkUserAutohide(v, event);
+ mStatusBar.checkUserAutohide(event);
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 4ae1393..9c837ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -16,8 +16,12 @@
package com.android.systemui.statusbar.phone;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+
import android.app.ActivityManager;
-import android.app.ActivityManager.StackId;
import android.app.ActivityManager.StackInfo;
import android.app.AlarmManager;
import android.app.AlarmManager.AlarmClockInfo;
@@ -523,12 +527,18 @@
mCurrentNotifs.clear();
mUiOffloadThread.submit(() -> {
try {
- int focusedId = ActivityManager.getService().getFocusedStackId();
- if (focusedId == StackId.FULLSCREEN_WORKSPACE_STACK_ID) {
- checkStack(StackId.FULLSCREEN_WORKSPACE_STACK_ID, notifs, noMan, pm);
+ final StackInfo focusedStack = ActivityManager.getService().getFocusedStackInfo();
+ if (focusedStack != null) {
+ final int windowingMode =
+ focusedStack.configuration.windowConfiguration.getWindowingMode();
+ if (windowingMode == WINDOWING_MODE_FULLSCREEN
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
+ checkStack(focusedStack, notifs, noMan, pm);
+ }
}
if (mDockedStackExists) {
- checkStack(StackId.DOCKED_STACK_ID, notifs, noMan, pm);
+ checkStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED,
+ notifs, noMan, pm);
}
} catch (RemoteException e) {
e.rethrowFromSystemServer();
@@ -539,10 +549,19 @@
});
}
- private void checkStack(int stackId, ArraySet<Pair<String, Integer>> notifs,
+ private void checkStack(int windowingMode, int activityType,
+ ArraySet<Pair<String, Integer>> notifs, NotificationManager noMan, IPackageManager pm) {
+ try {
+ final StackInfo info =
+ ActivityManager.getService().getStackInfo(windowingMode, activityType);
+ checkStack(info, notifs, noMan, pm);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+ private void checkStack(StackInfo info, ArraySet<Pair<String, Integer>> notifs,
NotificationManager noMan, IPackageManager pm) {
try {
- StackInfo info = ActivityManager.getService().getStackInfo(stackId);
if (info == null || info.topActivity == null) return;
String pkg = info.topActivity.getPackageName();
if (!hasNotif(notifs, pkg, info.userId)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 4739a2e..a2e5a3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -69,9 +69,6 @@
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.PorterDuff;
@@ -108,7 +105,6 @@
import android.service.notification.StatusBarNotification;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
-import android.text.TextUtils;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.EventLog;
@@ -127,13 +123,11 @@
import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.view.ViewParent;
-import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.AccelerateInterpolator;
-import android.view.animation.Interpolator;
import android.widget.DateTimeView;
import android.widget.ImageView;
import android.widget.RemoteViews;
@@ -259,7 +253,6 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
@@ -279,11 +272,9 @@
= SystemProperties.getBoolean("debug.child_notifs", true);
public static final boolean FORCE_REMOTE_INPUT_HISTORY =
SystemProperties.getBoolean("debug.force_remoteinput_history", false);
- private static boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
+ private static final boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
- protected static final int MSG_SHOW_RECENT_APPS = 1019;
protected static final int MSG_HIDE_RECENT_APPS = 1020;
- protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
@@ -365,10 +356,6 @@
/** If true, the lockscreen will show a distinct wallpaper */
private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
- /* If true, the device supports freeform window management.
- * This affects the status bar UI. */
- private static final boolean FREEFORM_WINDOW_MANAGEMENT;
-
/**
* How long to wait before auto-dismissing a notification that was kept for remote input, and
* has now sent a remote input. We auto-dismiss, because the app may not see a reason to cancel
@@ -387,19 +374,14 @@
static {
boolean onlyCoreApps;
- boolean freeformWindowManagement;
try {
IPackageManager packageManager =
IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
onlyCoreApps = packageManager.isOnlyCoreApps();
- freeformWindowManagement = packageManager.hasSystemFeature(
- PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT, 0);
} catch (RemoteException e) {
onlyCoreApps = false;
- freeformWindowManagement = false;
}
ONLY_CORE_APPS = onlyCoreApps;
- FREEFORM_WINDOW_MANAGEMENT = freeformWindowManagement;
}
/**
@@ -410,17 +392,17 @@
protected boolean mShowLockscreenNotifications;
protected boolean mAllowLockscreenRemoteInput;
- PhoneStatusBarPolicy mIconPolicy;
+ private PhoneStatusBarPolicy mIconPolicy;
- VolumeComponent mVolumeComponent;
- BrightnessMirrorController mBrightnessMirrorController;
+ private VolumeComponent mVolumeComponent;
+ private BrightnessMirrorController mBrightnessMirrorController;
protected FingerprintUnlockController mFingerprintUnlockController;
- LightBarController mLightBarController;
+ private LightBarController mLightBarController;
protected LockscreenWallpaper mLockscreenWallpaper;
- int mNaturalBarHeight = -1;
+ private int mNaturalBarHeight = -1;
- Point mCurrentDisplaySize = new Point();
+ private final Point mCurrentDisplaySize = new Point();
protected StatusBarWindowView mStatusBarWindow;
protected PhoneStatusBarView mStatusBarView;
@@ -431,15 +413,13 @@
private boolean mWakeUpComingFromTouch;
private PointF mWakeUpTouchLocation;
- int mPixelFormat;
- Object mQueueLock = new Object();
+ private final Object mQueueLock = new Object();
protected StatusBarIconController mIconController;
// expanded notifications
protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
- View mExpandedContents;
- TextView mNotificationPanelDebugText;
+ private TextView mNotificationPanelDebugText;
/**
* {@code true} if notifications not part of a group should by default be rendered in their
@@ -452,12 +432,10 @@
private QSPanel mQSPanel;
// top bar
- protected KeyguardStatusBarView mKeyguardStatusBar;
- boolean mLeaveOpenOnKeyguardHide;
+ private KeyguardStatusBarView mKeyguardStatusBar;
+ private boolean mLeaveOpenOnKeyguardHide;
KeyguardIndicationController mKeyguardIndicationController;
- // Keyguard is going away soon.
- private boolean mKeyguardGoingAway;
// Keyguard is actually fading away now.
protected boolean mKeyguardFadingAway;
protected long mKeyguardFadingAwayDelay;
@@ -469,25 +447,19 @@
private View mReportRejectedTouch;
- int mMaxAllowedKeyguardNotifications;
+ private int mMaxAllowedKeyguardNotifications;
- boolean mExpandedVisible;
+ private boolean mExpandedVisible;
- // the tracker view
- int mTrackingPosition; // the position of the top of the tracking view.
-
- // Tracking finger for opening/closing.
- boolean mTracking;
-
- int[] mAbsPos = new int[2];
- ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
+ private final int[] mAbsPos = new int[2];
+ private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
// for disabling the status bar
- int mDisabled1 = 0;
- int mDisabled2 = 0;
+ private int mDisabled1 = 0;
+ private int mDisabled2 = 0;
// tracking calls to View.setSystemUiVisibility()
- int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
+ private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
private final Rect mLastFullscreenStackBounds = new Rect();
private final Rect mLastDockedStackBounds = new Rect();
private final Rect mTmpRect = new Rect();
@@ -495,7 +467,7 @@
// last value sent to window manager
private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
- DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+ private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
// XXX: gesture research
private final GestureRecorder mGestureRec = DEBUG_GESTURES
@@ -508,13 +480,15 @@
// ensure quick settings is disabled until the current user makes it through the setup wizard
private boolean mUserSetup = false;
- private DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() {
+ private final DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() {
@Override
public void onUserSetupChanged() {
final boolean userSetup = mDeviceProvisionedController.isUserSetup(
mDeviceProvisionedController.getCurrentUser());
- if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
- "userSetup=%s mUserSetup=%s", userSetup, mUserSetup));
+ if (MULTIUSER_DEBUG) {
+ Log.d(TAG, String.format("User setup changed: userSetup=%s mUserSetup=%s",
+ userSetup, mUserSetup));
+ }
if (userSetup != mUserSetup) {
mUserSetup = userSetup;
@@ -528,7 +502,7 @@
}
};
- protected H mHandler = createHandler();
+ protected final H mHandler = createHandler();
final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -537,8 +511,6 @@
&& Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
mContext.getContentResolver(), Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
Settings.Global.HEADS_UP_OFF);
- mHeadsUpTicker = mUseHeadsUp && 0 != Settings.Global.getInt(
- mContext.getContentResolver(), SETTING_HEADS_UP_TICKER, 0);
Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
if (wasUsing != mUseHeadsUp) {
if (!mUseHeadsUp) {
@@ -566,26 +538,21 @@
}
};
- private boolean mWaitingForKeyguardExit;
protected boolean mDozing;
private boolean mDozingRequested;
protected boolean mScrimSrcModeEnabled;
- public static final Interpolator ALPHA_IN = Interpolators.ALPHA_IN;
- public static final Interpolator ALPHA_OUT = Interpolators.ALPHA_OUT;
-
protected BackDropView mBackdrop;
protected ImageView mBackdropFront, mBackdropBack;
- protected PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
- protected PorterDuffXfermode mSrcOverXferMode =
+ protected final PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
+ protected final PorterDuffXfermode mSrcOverXferMode =
new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
private MediaSessionManager mMediaSessionManager;
private MediaController mMediaController;
private String mMediaNotificationKey;
private MediaMetadata mMediaMetadata;
- private MediaController.Callback mMediaListener
- = new MediaController.Callback() {
+ private final MediaController.Callback mMediaListener = new MediaController.Callback() {
@Override
public void onPlaybackStateChanged(PlaybackState state) {
super.onPlaybackStateChanged(state);
@@ -607,17 +574,6 @@
}
};
- private final OnChildLocationsChangedListener mOnChildLocationsChangedListener =
- new OnChildLocationsChangedListener() {
- @Override
- public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout) {
- userActivity();
- }
- };
-
- private int mDisabledUnmodified1;
- private int mDisabledUnmodified2;
-
/** Keys of notifications currently visible to the user. */
private final ArraySet<NotificationVisibility> mCurrentlyVisibleNotifications =
new ArraySet<>();
@@ -644,15 +600,6 @@
private boolean mWereIconsJustHidden;
private boolean mBouncerWasShowingWhenHidden;
- public boolean isStartedGoingToSleep() {
- return mStartedGoingToSleep;
- }
-
- /**
- * If set, the device has started going to sleep but isn't fully non-interactive yet.
- */
- protected boolean mStartedGoingToSleep;
-
private final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
new OnChildLocationsChangedListener() {
@Override
@@ -686,7 +633,6 @@
@Override
public void run() {
mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis();
- final String mediaKey = getCurrentMediaNotificationKey();
// 1. Loop over mNotificationData entries:
// A. Keep list of visible notifications.
@@ -743,10 +689,10 @@
private boolean mKeyguardRequested;
private boolean mIsKeyguard;
private LogMaker mStatusBarStateLog;
- private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
+ private final LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
protected NotificationIconAreaController mNotificationIconAreaController;
private boolean mReinflateNotificationsOnUserSwitched;
- private HashMap<String, Entry> mPendingNotifications = new HashMap<>();
+ private final HashMap<String, Entry> mPendingNotifications = new HashMap<>();
private boolean mClearAllEnabled;
@Nullable private View mAmbientIndicationContainer;
private String mKeyToRemoveOnGutsClosed;
@@ -769,20 +715,21 @@
goToLockedShade(null);
}
};
- private HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> mTmpChildOrderMap
- = new HashMap<>();
+ private final HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>>
+ mTmpChildOrderMap = new HashMap<>();
private RankingMap mLatestRankingMap;
private boolean mNoAnimationOnNextBarModeChange;
private FalsingManager mFalsingManager;
- private KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
- @Override
- public void onDreamingStateChanged(boolean dreaming) {
- if (dreaming) {
- maybeEscalateHeadsUp();
- }
- }
- };
+ private final KeyguardUpdateMonitorCallback mUpdateCallback =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onDreamingStateChanged(boolean dreaming) {
+ if (dreaming) {
+ maybeEscalateHeadsUp();
+ }
+ }
+ };
private NavigationBarFragment mNavigationBar;
private View mNavigationBarView;
@@ -861,10 +808,6 @@
mRecents = getComponent(Recents.class);
- final Configuration currentConfig = res.getConfiguration();
- mLocale = currentConfig.locale;
- mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
-
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
mLockPatternUtils = new LockPatternUtils(mContext);
@@ -994,9 +937,6 @@
Dependency.get(ConfigurationController.class).addCallback(this);
}
- protected void createIconController() {
- }
-
// ================================================================================
// Constructing the view
// ================================================================================
@@ -1012,16 +952,14 @@
// TODO: Deal with the ugliness that comes from having some of the statusbar broken out
// into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
- mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
- R.id.notification_panel);
- mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
- R.id.notification_stack_scroller);
+ mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
+ mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
mNotificationPanel.setStatusBar(this);
mNotificationPanel.setGroupManager(mGroupManager);
mAboveShelfObserver = new AboveShelfObserver(mStackScroller);
mAboveShelfObserver.setListener(mStatusBarWindow.findViewById(
R.id.notification_container_parent));
- mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
+ mKeyguardStatusBar = mStatusBarWindow.findViewById(R.id.keyguard_header);
mNotificationIconAreaController = SystemUIFactory.getInstance()
.createNotificationIconAreaController(context, this);
@@ -1060,8 +998,7 @@
putComponent(HeadsUpManager.class, mHeadsUpManager);
if (MULTIUSER_DEBUG) {
- mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
- R.id.header_debug_info);
+ mNotificationPanelDebugText = mNotificationPanel.findViewById(R.id.header_debug_info);
mNotificationPanelDebugText.setVisibility(View.VISIBLE);
}
@@ -1075,9 +1012,6 @@
// no window manager? good luck with that
}
- // figure out which pixel-format to use for the status bar.
- mPixelFormat = PixelFormat.OPAQUE;
-
mStackScroller.setLongPressListener(getNotificationLongClicker());
mStackScroller.setStatusBar(this);
mStackScroller.setGroupManager(mGroupManager);
@@ -1087,11 +1021,10 @@
inflateEmptyShadeView();
inflateDismissView();
- mExpandedContents = mStackScroller;
- mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
- mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
- mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);
+ mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);
+ mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front);
+ mBackdropBack = mBackdrop.findViewById(R.id.backdrop_back);
if (ENABLE_LOCKSCREEN_WALLPAPER) {
mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
@@ -1099,8 +1032,8 @@
mKeyguardIndicationController =
SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
- (ViewGroup) mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
- mNotificationPanel.getLockIcon());
+ mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
+ mNotificationPanel.getLockIcon());
mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);
@@ -1131,8 +1064,8 @@
mNavigationBar.setLightBarController(mLightBarController);
}
- ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
- ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
+ ScrimView scrimBehind = mStatusBarWindow.findViewById(R.id.scrim_behind);
+ ScrimView scrimInFront = mStatusBarWindow.findViewById(R.id.scrim_in_front);
View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
mScrimController = SystemUIFactory.getInstance().createScrimController(mLightBarController,
scrimBehind, scrimInFront, headsUpScrim, mLockscreenWallpaper,
@@ -1142,13 +1075,10 @@
}
});
if (mScrimSrcModeEnabled) {
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
- mScrimController.setDrawBehindAsSrc(asSrc);
- mStackScroller.setDrawBackgroundAsSrc(asSrc);
- }
+ Runnable runnable = () -> {
+ boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
+ mScrimController.setDrawBehindAsSrc(asSrc);
+ mStackScroller.setDrawBackgroundAsSrc(asSrc);
};
mBackdrop.setOnVisibilityChangedRunnable(runnable);
runnable.run();
@@ -1170,11 +1100,11 @@
if (container != null) {
FragmentHostManager fragmentHostManager = FragmentHostManager.get(container);
ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame,
- Dependency.get(ExtensionController.class).newExtension(QS.class)
+ Dependency.get(ExtensionController.class)
+ .newExtension(QS.class)
.withPlugin(QS.class)
- .withFeature(
- PackageManager.FEATURE_AUTOMOTIVE, () -> new CarQSFragment())
- .withDefault(() -> new QSFragment())
+ .withFeature(PackageManager.FEATURE_AUTOMOTIVE, CarQSFragment::new)
+ .withDefault(QSFragment::new)
.build());
final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
mIconController);
@@ -1276,7 +1206,7 @@
*/
protected View.OnTouchListener getStatusBarWindowTouchListener() {
return (v, event) -> {
- checkUserAutohide(v, event);
+ checkUserAutohide(event);
checkRemoteInputOutside(event);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mExpandedVisible) {
@@ -1380,8 +1310,7 @@
public static SignalClusterView reinflateSignalCluster(View view) {
Context context = view.getContext();
- SignalClusterView signalCluster =
- (SignalClusterView) view.findViewById(R.id.signal_cluster);
+ SignalClusterView signalCluster = view.findViewById(R.id.signal_cluster);
if (signalCluster != null) {
ViewParent parent = signalCluster.getParent();
if (parent instanceof ViewGroup) {
@@ -1421,20 +1350,17 @@
mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
- mDismissView.setOnButtonClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES);
- clearAllNotifications();
- }
+ mDismissView.setOnButtonClickListener(v -> {
+ mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES);
+ clearAllNotifications();
});
mStackScroller.setDismissView(mDismissView);
}
protected void createUserSwitcher() {
mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
- (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
- mKeyguardStatusBar, mNotificationPanel);
+ mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mKeyguardStatusBar,
+ mNotificationPanel);
}
protected void inflateStatusBarWindow(Context context) {
@@ -1447,7 +1373,7 @@
// animate-swipe all dismissable notifications, then animate the shade closed
int numChildren = mStackScroller.getChildCount();
- final ArrayList<View> viewsToHide = new ArrayList<View>(numChildren);
+ final ArrayList<View> viewsToHide = new ArrayList<>(numChildren);
final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren);
for (int i = 0; i < numChildren; i++) {
final View child = mStackScroller.getChildAt(i);
@@ -1487,20 +1413,18 @@
return;
}
- addPostCollapseAction(new Runnable() {
- @Override
- public void run() {
- mStackScroller.setDismissAllInProgress(false);
- for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
- if (mStackScroller.canChildBeDismissed(rowToRemove)) {
- removeNotification(rowToRemove.getEntry().key, null);
- } else {
- rowToRemove.resetTranslation();
- }
+ addPostCollapseAction(() -> {
+ mStackScroller.setDismissAllInProgress(false);
+ for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
+ if (mStackScroller.canChildBeDismissed(rowToRemove)) {
+ removeNotification(rowToRemove.getEntry().key, null);
+ } else {
+ rowToRemove.resetTranslation();
}
- try {
- mBarService.onClearAllNotifications(mCurrentUserId);
- } catch (Exception ex) { }
+ }
+ try {
+ mBarService.onClearAllNotifications(mCurrentUserId);
+ } catch (Exception ex) {
}
});
@@ -1509,11 +1433,8 @@
}
private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
- Runnable animationFinishAction = new Runnable() {
- @Override
- public void run() {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
- }
+ Runnable animationFinishAction = () -> {
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
};
// let's disable our normal animations
@@ -1632,10 +1553,6 @@
SystemServicesProxy.getInstance(mContext).awakenDreamsAsync();
}
- public UserHandle getCurrentUserHandle() {
- return new UserHandle(mCurrentUserId);
- }
-
public void addNotification(StatusBarNotification notification, RankingMap ranking)
throws InflationException {
String key = notification.getKey();
@@ -1746,7 +1663,7 @@
boolean deferRemoval = false;
abortExistingInflation(key);
if (mHeadsUpManager.isHeadsUp(key)) {
- // A cancel() in repsonse to a remote input shouldn't be delayed, as it makes the
+ // A cancel() in response to a remote input shouldn't be delayed, as it makes the
// sending look longer than it takes.
// Also we should not defer the removal if reordering isn't allowed since otherwise
// some notifications can't disappear before the panel is closed.
@@ -1772,9 +1689,7 @@
newHistory = new CharSequence[1];
} else {
newHistory = new CharSequence[oldHistory.length + 1];
- for (int i = 0; i < oldHistory.length; i++) {
- newHistory[i + 1] = oldHistory[i];
- }
+ System.arraycopy(oldHistory, 0, newHistory, 1, oldHistory.length);
}
newHistory[0] = String.valueOf(entry.remoteInputText);
b.setRemoteInputHistory(newHistory);
@@ -1833,7 +1748,7 @@
mStackScroller.cleanUpViewState(entry.row);
}
// Let's remove the children if this was a summary
- handleGroupSummaryRemoved(key, ranking);
+ handleGroupSummaryRemoved(key);
StatusBarNotification old = removeNotificationViews(key, ranking);
if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
@@ -1857,12 +1772,10 @@
*
* This also ensures that the animation looks nice and only consists of a single disappear
* animation instead of multiple.
+ * @param key the key of the notification was removed
*
- * @param key the key of the notification was removed
- * @param ranking the current ranking
*/
- private void handleGroupSummaryRemoved(String key,
- RankingMap ranking) {
+ private void handleGroupSummaryRemoved(String key) {
Entry entry = mNotificationData.get(key);
if (entry != null && entry.row != null
&& entry.row.isSummaryWithChildren()) {
@@ -1873,15 +1786,13 @@
}
List<ExpandableNotificationRow> notificationChildren =
entry.row.getNotificationChildren();
- ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
for (int i = 0; i < notificationChildren.size(); i++) {
ExpandableNotificationRow row = notificationChildren.get(i);
if ((row.getStatusBarNotification().getNotification().flags
& Notification.FLAG_FOREGROUND_SERVICE) != 0) {
- // the child is a forground service notification which we can't remove!
+ // the child is a foreground service notification which we can't remove!
continue;
}
- toRemove.add(row);
row.setKeepInParent(true);
// we need to set this state earlier as otherwise we might generate some weird
// animations
@@ -1924,19 +1835,14 @@
// Do not modify the notifications during collapse.
if (isCollapsing()) {
- addPostCollapseAction(new Runnable() {
- @Override
- public void run() {
- updateNotificationShade();
- }
- });
+ addPostCollapseAction(this::updateNotificationShade);
return;
}
ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
final int N = activeNotifications.size();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
Entry ent = activeNotifications.get(i);
if (ent.row.isDismissed() || ent.row.isRemoved()) {
// we don't want to update removed notifications because they could
@@ -1980,7 +1886,8 @@
for (ExpandableNotificationRow remove : toRemove) {
if (mGroupManager.isChildInGroupWithSummary(remove.getStatusBarNotification())) {
- // we are only transfering this notification to its parent, don't generate an animation
+ // we are only transferring this notification to its parent, don't generate an
+ // animation
mStackScroller.setChildTransferInProgress(true);
}
if (remove.isSummaryWithChildren()) {
@@ -1992,7 +1899,7 @@
removeNotificationChildren();
- for (int i=0; i<toShow.size(); i++) {
+ for (int i = 0; i < toShow.size(); i++) {
View v = toShow.get(i);
if (v.getParent() == null) {
mVisualStabilityManager.notifyViewAddition(v);
@@ -2102,7 +2009,7 @@
}
}
- // Finally after removing and adding has been beformed we can apply the order.
+ // Finally after removing and adding has been performed we can apply the order.
orderChanged |= parent.applyChildOrder(orderedChildren, mVisualStabilityManager, this);
}
if (orderChanged) {
@@ -2275,10 +2182,11 @@
MediaController controller = null;
for (int i = 0; i < N; i++) {
final Entry entry = activeNotifications.get(i);
+
if (isMediaNotification(entry)) {
final MediaSession.Token token =
- entry.notification.getNotification().extras
- .getParcelable(Notification.EXTRA_MEDIA_SESSION);
+ entry.notification.getNotification().extras.getParcelable(
+ Notification.EXTRA_MEDIA_SESSION);
if (token != null) {
MediaController aController = new MediaController(mContext, token);
if (PlaybackState.STATE_PLAYING ==
@@ -2316,7 +2224,7 @@
if (entry.notification.getPackageName().equals(pkg)) {
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: found controller matching "
- + entry.notification.getKey());
+ + entry.notification.getKey());
}
controller = aController;
mediaNotification = entry;
@@ -2367,12 +2275,8 @@
}
private boolean isPlaybackActive(int state) {
- if (state != PlaybackState.STATE_STOPPED
- && state != PlaybackState.STATE_ERROR
- && state != PlaybackState.STATE_NONE) {
- return true;
- }
- return false;
+ return state != PlaybackState.STATE_STOPPED && state != PlaybackState.STATE_ERROR
+ && state != PlaybackState.STATE_NONE;
}
private void clearCurrentMediaNotification() {
@@ -2397,7 +2301,7 @@
/**
* Hide the album artwork that is fading out and release its bitmap.
*/
- protected Runnable mHideBackdropFront = new Runnable() {
+ protected final Runnable mHideBackdropFront = new Runnable() {
@Override
public void run() {
if (DEBUG_MEDIA) {
@@ -2549,14 +2453,11 @@
.setInterpolator(Interpolators.ACCELERATE_DECELERATE)
.setDuration(300)
.setStartDelay(0)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- mBackdrop.setVisibility(View.GONE);
- mBackdropFront.animate().cancel();
- mBackdropBack.setImageDrawable(null);
- mHandler.post(mHideBackdropFront);
- }
+ .withEndAction(() -> {
+ mBackdrop.setVisibility(View.GONE);
+ mBackdropFront.animate().cancel();
+ mBackdropBack.setImageDrawable(null);
+ mHandler.post(mHideBackdropFront);
});
if (mKeyguardFadingAway) {
mBackdrop.animate()
@@ -2587,8 +2488,6 @@
@Override
public void disable(int state1, int state2, boolean animate) {
animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
- mDisabledUnmodified1 = state1;
- mDisabledUnmodified2 = state2;
final int old1 = mDisabled1;
final int diff1 = state1 ^ old1;
mDisabled1 = state1;
@@ -2624,8 +2523,11 @@
flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_CLOCK)) ? '!' : ' ');
flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SEARCH)) ? 'S' : 's');
flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SEARCH)) ? '!' : ' ');
+ flagdbg.append("> disable2<");
flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? 'Q' : 'q');
flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? '!' : ' ');
+ flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? 'I' : 'i');
+ flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? '!' : ' ');
flagdbg.append('>');
Log.d(TAG, flagdbg.toString());
@@ -2739,11 +2641,8 @@
// make sure that the window stays small for one frame until the touchableRegion is set.
mNotificationPanel.requestLayout();
mStatusBarWindowManager.setForceWindowCollapsed(true);
- mNotificationPanel.post(new Runnable() {
- @Override
- public void run() {
- mStatusBarWindowManager.setForceWindowCollapsed(false);
- }
+ mNotificationPanel.post(() -> {
+ mStatusBarWindowManager.setForceWindowCollapsed(false);
});
}
} else {
@@ -2755,15 +2654,12 @@
// we need to keep the panel open artificially, let's wait until the animation
// is finished.
mHeadsUpManager.setHeadsUpGoingAway(true);
- mStackScroller.runAfterAnimationFinished(new Runnable() {
- @Override
- public void run() {
- if (!mHeadsUpManager.hasPinnedHeadsUp()) {
- mStatusBarWindowManager.setHeadsUpShowing(false);
- mHeadsUpManager.setHeadsUpGoingAway(false);
- }
- removeRemoteInputEntriesKeptUntilCollapsed();
+ mStackScroller.runAfterAnimationFinished(() -> {
+ if (!mHeadsUpManager.hasPinnedHeadsUp()) {
+ mStatusBarWindowManager.setHeadsUpShowing(false);
+ mHeadsUpManager.setHeadsUpGoingAway(false);
}
+ removeRemoteInputEntriesKeptUntilCollapsed();
});
}
}
@@ -3030,7 +2926,6 @@
mStatusBarWindowManager.setPanelVisible(true);
visibilityChanged(true);
- mWaitingForKeyguardExit = false;
recomputeDisableFlags(!force /* animate */);
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
}
@@ -3039,23 +2934,15 @@
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
}
- private final Runnable mAnimateCollapsePanels = new Runnable() {
- @Override
- public void run() {
- animateCollapsePanels();
- }
- };
+ private final Runnable mAnimateCollapsePanels = this::animateCollapsePanels;
public void postAnimateCollapsePanels() {
mHandler.post(mAnimateCollapsePanels);
}
public void postAnimateForceCollapsePanels() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
- }
+ mHandler.post(() -> {
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
});
}
@@ -3105,6 +2992,9 @@
}
}
+ // TODO(b/62444020): remove when this bug is fixed
+ Log.v(TAG, "mStatusBarWindow: " + mStatusBarWindow + " canPanelBeCollapsed(): "
+ + mNotificationPanel.canPanelBeCollapsed());
if (mStatusBarWindow != null && mNotificationPanel.canPanelBeCollapsed()) {
// release focus immediately to kick off focus change transition
mStatusBarWindowManager.setStatusBarFocusable(false);
@@ -3210,7 +3100,7 @@
if (SPEW) {
Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled1="
- + mDisabled1 + " mDisabled2=" + mDisabled2 + " mTracking=" + mTracking);
+ + mDisabled1 + " mDisabled2=" + mDisabled2);
} else if (CHATTY) {
if (event.getAction() != MotionEvent.ACTION_MOVE) {
Log.d(TAG, String.format(
@@ -3295,10 +3185,8 @@
sbModeChanged = sbMode != -1;
if (sbModeChanged && sbMode != mStatusBarMode) {
- if (sbMode != mStatusBarMode) {
- mStatusBarMode = sbMode;
- checkBarModes();
- }
+ mStatusBarMode = sbMode;
+ checkBarModes();
touchAutoHide();
}
@@ -3385,12 +3273,7 @@
}
}
- private final Runnable mCheckBarModes = new Runnable() {
- @Override
- public void run() {
- checkBarModes();
- }
- };
+ private final Runnable mCheckBarModes = this::checkBarModes;
public void setInteracting(int barWindow, boolean interacting) {
final boolean changing = ((mInteractingWindows & barWindow) != 0) != interacting;
@@ -3449,7 +3332,7 @@
}
}
- void checkUserAutohide(View v, MotionEvent event) {
+ void checkUserAutohide(MotionEvent event) {
if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed
&& event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
&& event.getX() == 0 && event.getY() == 0 // a touch outside both bars
@@ -3516,9 +3399,7 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mQueueLock) {
pw.println("Current Status Bar state:");
- pw.println(" mExpandedVisible=" + mExpandedVisible
- + ", mTrackingPosition=" + mTrackingPosition);
- pw.println(" mTracking=" + mTracking);
+ pw.println(" mExpandedVisible=" + mExpandedVisible);
pw.println(" mDisplayMetrics=" + mDisplayMetrics);
pw.println(" mStackScroller: " + viewInfo(mStackScroller));
pw.println(" mStackScroller: " + viewInfo(mStackScroller)
@@ -3606,16 +3487,12 @@
if (false) {
pw.println("see the logcat for a dump of the views we have created.");
// must happen on ui thread
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mStatusBarView.getLocationOnScreen(mAbsPos);
- Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
- + ") " + mStatusBarView.getWidth() + "x"
- + getStatusBarHeight());
- mStatusBarView.debug();
- }
- });
+ mHandler.post(() -> {
+ mStatusBarView.getLocationOnScreen(mAbsPos);
+ Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] +
+ ") " + mStatusBarView.getWidth() + "x" + getStatusBarHeight());
+ mStatusBarView.debug();
+ });
}
}
@@ -3695,49 +3572,43 @@
final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
mContext, intent, mCurrentUserId);
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- mAssistManager.hideAssist();
- intent.setFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- int result = ActivityManager.START_CANCELED;
- ActivityOptions options = new ActivityOptions(getActivityOptions());
- options.setDisallowEnterPictureInPictureWhileLaunching(
- disallowEnterPictureInPictureWhileLaunching);
- if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) {
- // Normally an activity will set it's requested rotation
- // animation on its window. However when launching an activity
- // causes the orientation to change this is too late. In these cases
- // the default animation is used. This doesn't look good for
- // the camera (as it rotates the camera contents out of sync
- // with physical reality). So, we ask the WindowManager to
- // force the crossfade animation if an orientation change
- // happens to occur during the launch.
- options.setRotationAnimationHint(
- WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
- }
- try {
- result = ActivityManager.getService().startActivityAsUser(
- null, mContext.getBasePackageName(),
- intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
- options.toBundle(), UserHandle.CURRENT.getIdentifier());
- } catch (RemoteException e) {
- Log.w(TAG, "Unable to start activity", e);
- }
- if (callback != null) {
- callback.onActivityStarted(result);
- }
+ Runnable runnable = () -> {
+ mAssistManager.hideAssist();
+ intent.setFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ int result = ActivityManager.START_CANCELED;
+ ActivityOptions options = new ActivityOptions(getActivityOptions());
+ options.setDisallowEnterPictureInPictureWhileLaunching(
+ disallowEnterPictureInPictureWhileLaunching);
+ if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) {
+ // Normally an activity will set it's requested rotation
+ // animation on its window. However when launching an activity
+ // causes the orientation to change this is too late. In these cases
+ // the default animation is used. This doesn't look good for
+ // the camera (as it rotates the camera contents out of sync
+ // with physical reality). So, we ask the WindowManager to
+ // force the crossfade animation if an orientation change
+ // happens to occur during the launch.
+ options.setRotationAnimationHint(
+ WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
+ }
+ try {
+ result = ActivityManager.getService().startActivityAsUser(
+ null, mContext.getBasePackageName(),
+ intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
+ options.toBundle(), UserHandle.CURRENT.getIdentifier());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to start activity", e);
+ }
+ if (callback != null) {
+ callback.onActivityStarted(result);
}
};
- Runnable cancelRunnable = new Runnable() {
- @Override
- public void run() {
- if (callback != null) {
- callback.onActivityStarted(ActivityManager.START_CANCELED);
- }
+ Runnable cancelRunnable = () -> {
+ if (callback != null) {
+ callback.onActivityStarted(ActivityManager.START_CANCELED);
}
};
executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade,
@@ -3782,7 +3653,7 @@
}, cancelAction, afterKeyguardGone);
}
- private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Log.v(TAG, "onReceive: " + intent);
@@ -3811,7 +3682,7 @@
}
};
- private BroadcastReceiver mDemoReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mDemoReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Log.v(TAG, "onReceive: " + intent);
@@ -3972,7 +3843,6 @@
* The LEDs are turned off when the notification panel is shown, even just a little bit.
* See also StatusBar.setPanelExpanded for another place where we attempt to do this.
*/
- // Old BaseStatusBar.handleVisibileToUserChanged
private void handleVisibleToUserChangedImpl(boolean visibleToUser) {
try {
if (visibleToUser) {
@@ -3997,8 +3867,8 @@
// Report all notifications as invisible and turn down the
// reporter.
if (!mCurrentlyVisibleNotifications.isEmpty()) {
- logNotificationVisibilityChanges(Collections.<NotificationVisibility>emptyList(),
- mCurrentlyVisibleNotifications);
+ logNotificationVisibilityChanges(
+ Collections.emptyList(), mCurrentlyVisibleNotifications);
recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
}
mHandler.removeCallbacks(mVisibilityReporter);
@@ -4105,7 +3975,7 @@
vib.vibrate(250, VIBRATION_ATTRIBUTES);
}
- Runnable mStartTracing = new Runnable() {
+ final Runnable mStartTracing = new Runnable() {
@Override
public void run() {
vibrate();
@@ -4116,13 +3986,10 @@
}
};
- Runnable mStopTracing = new Runnable() {
- @Override
- public void run() {
- android.os.Debug.stopMethodTracing();
- Log.d(TAG, "stopTracing");
- vibrate();
- }
+ final Runnable mStopTracing = () -> {
+ android.os.Debug.stopMethodTracing();
+ Log.d(TAG, "stopTracing");
+ vibrate();
};
@Override
@@ -4149,40 +4016,6 @@
startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */);
}
- private static class FastColorDrawable extends Drawable {
- private final int mColor;
-
- public FastColorDrawable(int color) {
- mColor = 0xff000000 | color;
- }
-
- @Override
- public void draw(Canvas canvas) {
- canvas.drawColor(mColor, PorterDuff.Mode.SRC);
- }
-
- @Override
- public void setAlpha(int alpha) {
- }
-
- @Override
- public void setColorFilter(ColorFilter colorFilter) {
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.OPAQUE;
- }
-
- @Override
- public void setBounds(int left, int top, int right, int bottom) {
- }
-
- @Override
- public void setBounds(Rect bounds) {
- }
- }
-
public void destroy() {
// Begin old BaseStatusBar.destroy().
mContext.unregisterReceiver(mBaseBroadcastReceiver);
@@ -4400,31 +4233,23 @@
Runnable endRunnable) {
mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
mLaunchTransitionEndRunnable = endRunnable;
- Runnable hideRunnable = new Runnable() {
- @Override
- public void run() {
- mLaunchTransitionFadingAway = true;
- if (beforeFading != null) {
- beforeFading.run();
- }
- mScrimController.forceHideScrims(true /* hide */, false /* animated */);
- updateMediaMetaData(false, true);
- mNotificationPanel.setAlpha(1);
- mStackScroller.setParentNotFullyVisible(true);
- mNotificationPanel.animate()
- .alpha(0)
- .setStartDelay(FADE_KEYGUARD_START_DELAY)
- .setDuration(FADE_KEYGUARD_DURATION)
- .withLayer()
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- onLaunchTransitionFadingEnded();
- }
- });
- mCommandQueue.appTransitionStarting(SystemClock.uptimeMillis(),
- LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
+ Runnable hideRunnable = () -> {
+ mLaunchTransitionFadingAway = true;
+ if (beforeFading != null) {
+ beforeFading.run();
}
+ mScrimController.forceHideScrims(true /* hide */, false /* animated */);
+ updateMediaMetaData(false, true);
+ mNotificationPanel.setAlpha(1);
+ mStackScroller.setParentNotFullyVisible(true);
+ mNotificationPanel.animate()
+ .alpha(0)
+ .setStartDelay(FADE_KEYGUARD_START_DELAY)
+ .setDuration(FADE_KEYGUARD_DURATION)
+ .withLayer()
+ .withEndAction(this::onLaunchTransitionFadingEnded);
+ mCommandQueue.appTransitionStarting(SystemClock.uptimeMillis(),
+ LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
};
if (mNotificationPanel.isLaunchTransitionRunning()) {
mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable);
@@ -4553,7 +4378,6 @@
// Treat Keyguard exit animation as an app transition to achieve nice transition for status
// bar.
- mKeyguardGoingAway = true;
mKeyguardMonitor.notifyKeyguardGoingAway(true);
mCommandQueue.appTransitionPending(true);
}
@@ -4562,14 +4386,13 @@
* Notifies the status bar the Keyguard is fading away with the specified timings.
*
* @param startTime the start time of the animations in uptime millis
- * @param delay the precalculated animation delay in miliseconds
+ * @param delay the precalculated animation delay in milliseconds
* @param fadeoutDuration the duration of the exit animation, in milliseconds
*/
public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
mKeyguardFadingAway = true;
mKeyguardFadingAwayDelay = delay;
mKeyguardFadingAwayDuration = fadeoutDuration;
- mWaitingForKeyguardExit = false;
mCommandQueue.appTransitionStarting(startTime + fadeoutDuration
- LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
@@ -4589,14 +4412,9 @@
*/
public void finishKeyguardFadingAway() {
mKeyguardFadingAway = false;
- mKeyguardGoingAway = false;
mKeyguardMonitor.notifyKeyguardDoneFading();
}
- public void stopWaitingForKeyguardExit() {
- mWaitingForKeyguardExit = false;
- }
-
private void updatePublicMode() {
final boolean showingKeyguard = mStatusBarKeyguardViewManager.isShowing();
final boolean devicePublic = showingKeyguard
@@ -4810,7 +4628,6 @@
}
protected void showBouncer() {
- mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing();
mStatusBarKeyguardViewManager.dismiss();
}
@@ -4827,7 +4644,7 @@
@Override
public void onActivated(ActivatableNotificationView view) {
- onActivated((View)view);
+ onActivated((View) view);
mStackScroller.setActivatedChild(view);
}
@@ -5129,51 +4946,41 @@
updateNotifications();
if (mPendingWorkRemoteInputView != null && !isAnyProfilePublicMode()) {
// Expand notification panel and the notification row, then click on remote input view
- final Runnable clickPendingViewRunnable = new Runnable() {
- @Override
- public void run() {
- final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
- if (pendingWorkRemoteInputView == null) {
+ final Runnable clickPendingViewRunnable = () -> {
+ final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
+ if (pendingWorkRemoteInputView == null) {
+ return;
+ }
+
+ // Climb up the hierarchy until we get to the container for this row.
+ ViewParent p = pendingWorkRemoteInputView.getParent();
+ while (!(p instanceof ExpandableNotificationRow)) {
+ if (p == null) {
return;
}
+ p = p.getParent();
+ }
- // Climb up the hierarchy until we get to the container for this row.
- ViewParent p = pendingWorkRemoteInputView.getParent();
- while (!(p instanceof ExpandableNotificationRow)) {
- if (p == null) {
- return;
+ final ExpandableNotificationRow row = (ExpandableNotificationRow) p;
+ ViewParent viewParent = row.getParent();
+ if (viewParent instanceof NotificationStackScrollLayout) {
+ final NotificationStackScrollLayout scrollLayout =
+ (NotificationStackScrollLayout) viewParent;
+ row.makeActionsVisibile();
+ row.post(() -> {
+ final Runnable finishScrollingCallback = () -> {
+ mPendingWorkRemoteInputView.callOnClick();
+ mPendingWorkRemoteInputView = null;
+ scrollLayout.setFinishScrollingCallback(null);
+ };
+ if (scrollLayout.scrollTo(row)) {
+ // It scrolls! So call it when it's finished.
+ scrollLayout.setFinishScrollingCallback(finishScrollingCallback);
+ } else {
+ // It does not scroll, so call it now!
+ finishScrollingCallback.run();
}
- p = p.getParent();
- }
-
- final ExpandableNotificationRow row = (ExpandableNotificationRow) p;
- ViewParent viewParent = row.getParent();
- if (viewParent instanceof NotificationStackScrollLayout) {
- final NotificationStackScrollLayout scrollLayout =
- (NotificationStackScrollLayout) viewParent;
- row.makeActionsVisibile();
- row.post(new Runnable() {
- @Override
- public void run() {
- final Runnable finishScrollingCallback = new Runnable() {
- @Override
- public void run() {
- mPendingWorkRemoteInputView.callOnClick();
- mPendingWorkRemoteInputView = null;
- scrollLayout.setFinishScrollingCallback(null);
- }
- };
- if (scrollLayout.scrollTo(row)) {
- // It scrolls! So call it when it's finished.
- scrollLayout.setFinishScrollingCallback(
- finishScrollingCallback);
- } else {
- // It does not scroll, so call it now!
- finishScrollingCallback.run();
- }
- }
- });
- }
+ });
}
};
mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
@@ -5236,7 +5043,7 @@
}
}
- WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
+ final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
@Override
public void onFinishedGoingToSleep() {
mNotificationPanel.onAffordanceLaunchEnded();
@@ -5259,12 +5066,7 @@
// This gets executed before we will show Keyguard, so post it in order that the state
// is correct.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- onCameraLaunchGestureDetected(mLastCameraLaunchSource);
- }
- });
+ mHandler.post(() -> onCameraLaunchGestureDetected(mLastCameraLaunchSource));
}
updateIsKeyguard();
}
@@ -5290,7 +5092,7 @@
}
};
- ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
+ final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
@Override
public void onScreenTurningOn() {
mFalsingManager.onScreenTurningOn();
@@ -5487,7 +5289,7 @@
}
private final class DozeServiceHost implements DozeHost {
- private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+ private final ArrayList<Callback> mCallbacks = new ArrayList<>();
private boolean mAnimateWakeup;
private boolean mIgnoreTouchWhilePulsing;
@@ -5700,7 +5502,7 @@
protected NotificationData mNotificationData;
protected NotificationStackScrollLayout mStackScroller;
- protected NotificationGroupManager mGroupManager = new NotificationGroupManager();
+ protected final NotificationGroupManager mGroupManager = new NotificationGroupManager();
protected RemoteInputController mRemoteInputController;
@@ -5710,34 +5512,30 @@
private AboveShelfObserver mAboveShelfObserver;
// handling reordering
- protected VisualStabilityManager mVisualStabilityManager = new VisualStabilityManager();
+ protected final VisualStabilityManager mVisualStabilityManager = new VisualStabilityManager();
protected int mCurrentUserId = 0;
- final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
+ final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
- protected int mLayoutDirection = -1; // invalid
protected AccessibilityManager mAccessibilityManager;
protected boolean mDeviceInteractive;
protected boolean mVisible;
- protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
- protected ArraySet<Entry> mRemoteInputEntriesToRemoveOnCollapse = new ArraySet<>();
+ protected final ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
+ protected final ArraySet<Entry> mRemoteInputEntriesToRemoveOnCollapse = new ArraySet<>();
/**
* Notifications with keys in this set are not actually around anymore. We kept them around
* when they were canceled in response to a remote input interaction. This allows us to show
* what you replied and allows you to continue typing into it.
*/
- protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
+ protected final ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
// mScreenOnFromKeyguard && mVisible.
private boolean mVisibleToUser;
- private Locale mLocale;
-
protected boolean mUseHeadsUp = false;
- protected boolean mHeadsUpTicker = false;
protected boolean mDisableNotificationAlerts = false;
protected DevicePolicyManager mDevicePolicyManager;
@@ -5772,13 +5570,11 @@
private NotificationGuts mNotificationGutsExposed;
private MenuItem mGutsMenuItem;
- private KeyboardShortcuts mKeyboardShortcuts;
-
protected NotificationShelf mNotificationShelf;
protected DismissView mDismissView;
protected EmptyShadeView mEmptyShadeView;
- private NotificationClicker mNotificationClicker = new NotificationClicker();
+ private final NotificationClicker mNotificationClicker = new NotificationClicker();
protected AssistManager mAssistManager;
@@ -5838,15 +5634,14 @@
}
};
- private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
+ private final RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
@Override
public boolean onClickHandler(
final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
wakeUpIfDozing(SystemClock.uptimeMillis(), view);
-
- if (handleRemoteInput(view, pendingIntent, fillInIntent)) {
+ if (handleRemoteInput(view, pendingIntent)) {
return true;
}
@@ -5864,33 +5659,29 @@
}
final boolean isActivity = pendingIntent.isActivity();
if (isActivity) {
- final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
mContext, pendingIntent.getIntent(), mCurrentUserId);
- dismissKeyguardThenExecute(new OnDismissAction() {
- @Override
- public boolean onDismiss() {
- try {
- ActivityManager.getService().resumeAppSwitches();
- } catch (RemoteException e) {
- }
-
- boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
-
- // close the shade if it was open
- if (handled && !mNotificationPanel.isFullyCollapsed()) {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
- true /* force */);
- visibilityChanged(false);
- mAssistManager.hideAssist();
-
- // Wait for activity start.
- return true;
- } else {
- return false;
- }
-
+ dismissKeyguardThenExecute(() -> {
+ try {
+ ActivityManager.getService().resumeAppSwitches();
+ } catch (RemoteException e) {
}
+
+ boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
+
+ // close the shade if it was open
+ if (handled && !mNotificationPanel.isFullyCollapsed()) {
+ animateCollapsePanels(
+ CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
+ visibilityChanged(false);
+ mAssistManager.hideAssist();
+
+ // Wait for activity start.
+ return true;
+ } else {
+ return false;
+ }
+
}, afterKeyguardGone);
return true;
} else {
@@ -5935,7 +5726,7 @@
WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
}
- private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
+ private boolean handleRemoteInput(View view, PendingIntent pendingIntent) {
Object tag = view.getTag(com.android.internal.R.id.remote_input_tag);
RemoteInput[] inputs = null;
if (tag instanceof RemoteInput[]) {
@@ -6050,7 +5841,7 @@
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
updateCurrentProfilesCache();
- if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
+ Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
updateLockscreenNotificationSetting();
@@ -6073,8 +5864,7 @@
Toast toast = Toast.makeText(mContext,
R.string.managed_profile_foreground_toast,
Toast.LENGTH_SHORT);
- TextView text = (TextView) toast.getView().findViewById(
- android.R.id.message);
+ TextView text = toast.getView().findViewById(android.R.id.message);
text.setCompoundDrawablesRelativeWithIntrinsicBounds(
R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
int paddingPx = mContext.getResources().getDimensionPixelSize(
@@ -6150,15 +5940,12 @@
return;
}
final RankingMap currentRanking = getCurrentRanking();
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- for (StatusBarNotification sbn : notifications) {
- try {
- addNotification(sbn, currentRanking);
- } catch (InflationException e) {
- handleInflationException(sbn, e);
- }
+ mHandler.post(() -> {
+ for (StatusBarNotification sbn : notifications) {
+ try {
+ addNotification(sbn, currentRanking);
+ } catch (InflationException e) {
+ handleInflationException(sbn, e);
}
}
});
@@ -6169,40 +5956,37 @@
final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- processForRemoteInput(sbn.getNotification());
- String key = sbn.getKey();
- mKeysKeptForRemoteInput.remove(key);
- boolean isUpdate = mNotificationData.get(key) != null;
- // In case we don't allow child notifications, we ignore children of
- // notifications that have a summary, since we're not going to show them
- // anyway. This is true also when the summary is canceled,
- // because children are automatically canceled by NoMan in that case.
- if (!ENABLE_CHILD_NOTIFICATIONS
+ mHandler.post(() -> {
+ processForRemoteInput(sbn.getNotification());
+ String key = sbn.getKey();
+ mKeysKeptForRemoteInput.remove(key);
+ boolean isUpdate = mNotificationData.get(key) != null;
+ // In case we don't allow child notifications, we ignore children of
+ // notifications that have a summary, since we're not going to show them
+ // anyway. This is true also when the summary is canceled,
+ // because children are automatically canceled by NoMan in that case.
+ if (!ENABLE_CHILD_NOTIFICATIONS
&& mGroupManager.isChildInGroupWithSummary(sbn)) {
- if (DEBUG) {
- Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
- }
+ if (DEBUG) {
+ Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
+ }
- // Remove existing notification to avoid stale data.
- if (isUpdate) {
- removeNotification(key, rankingMap);
- } else {
- mNotificationData.updateRanking(rankingMap);
- }
- return;
+ // Remove existing notification to avoid stale data.
+ if (isUpdate) {
+ removeNotification(key, rankingMap);
+ } else {
+ mNotificationData.updateRanking(rankingMap);
}
- try {
- if (isUpdate) {
- updateNotification(sbn, rankingMap);
- } else {
- addNotification(sbn, rankingMap);
- }
- } catch (InflationException e) {
- handleInflationException(sbn, e);
+ return;
+ }
+ try {
+ if (isUpdate) {
+ updateNotification(sbn, rankingMap);
+ } else {
+ addNotification(sbn, rankingMap);
}
+ } catch (InflationException e) {
+ handleInflationException(sbn, e);
}
});
}
@@ -6250,7 +6034,7 @@
Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
return;
}
- Log.d(TAG, "disabling lockecreen notifications and alerting the user");
+ Log.d(TAG, "disabling lockscreen notifications and alerting the user");
// disable lockscreen notifications until user acts on the banner.
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
@@ -6291,11 +6075,10 @@
@Override // NotificationData.Environment
public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
- final int thisUserId = mCurrentUserId;
final int notificationUserId = n.getUserId();
if (DEBUG && MULTIUSER_DEBUG) {
- Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
- n, thisUserId, notificationUserId));
+ Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", n,
+ mCurrentUserId, notificationUserId));
}
return isCurrentProfile(notificationUserId);
}
@@ -6343,21 +6126,15 @@
}
private void startNotificationGutsIntent(final Intent intent, final int appUid) {
- dismissKeyguardThenExecute(new OnDismissAction() {
- @Override
- public boolean onDismiss() {
- AsyncTask.execute(new Runnable() {
- @Override
- public void run() {
- TaskStackBuilder.create(mContext)
- .addNextIntentWithParentStack(intent)
- .startActivities(getActivityOptions(),
- new UserHandle(UserHandle.getUserId(appUid)));
- }
- });
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
- return true;
- }
+ dismissKeyguardThenExecute(() -> {
+ AsyncTask.execute(() -> {
+ TaskStackBuilder.create(mContext)
+ .addNextIntentWithParentStack(intent)
+ .startActivities(getActivityOptions(),
+ new UserHandle(UserHandle.getUserId(appUid)));
+ });
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
+ return true;
}, false /* afterKeyguardGone */);
}
@@ -6428,7 +6205,7 @@
startNotificationGutsIntent(intent, sbn.getUid());
};
final View.OnClickListener onDoneClick = (View v) -> {
- saveAndCloseNotificationMenu(info, row, guts, v);
+ saveAndCloseNotificationMenu(row, guts, v);
};
final NotificationInfo.CheckSaveListener checkSaveListener =
(Runnable saveImportance) -> {
@@ -6445,7 +6222,7 @@
}
};
- ArraySet<NotificationChannel> channels = new ArraySet<NotificationChannel>();
+ ArraySet<NotificationChannel> channels = new ArraySet<>();
channels.add(row.getEntry().channel);
if (row.isSummaryWithChildren()) {
// If this is a summary, then add in the children notification channels for the
@@ -6473,7 +6250,7 @@
}
}
- private void saveAndCloseNotificationMenu(NotificationInfo info,
+ private void saveAndCloseNotificationMenu(
ExpandableNotificationRow row, NotificationGuts guts, View done) {
guts.resetFalsingCheck();
int[] rowLocation = new int[2];
@@ -6642,13 +6419,6 @@
updateHideIconsForBouncer(true /* animate */);
}
- protected void sendCloseSystemWindows(String reason) {
- try {
- ActivityManager.getService().closeSystemDialogs(reason);
- } catch (RemoteException e) {
- }
- }
-
protected void toggleKeyboardShortcuts(int deviceId) {
KeyboardShortcuts.toggle(mContext, deviceId);
}
@@ -6750,18 +6520,6 @@
return isLockscreenPublicMode(userId);
}
- public void onNotificationClear(StatusBarNotification notification) {
- try {
- mBarService.onNotificationClear(
- notification.getPackageName(),
- notification.getTag(),
- notification.getId(),
- notification.getUserId());
- } catch (android.os.RemoteException ex) {
- // oh well
- }
- }
-
/**
* Called when the notification panel layouts
*/
@@ -6919,49 +6677,42 @@
public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
if (!isDeviceProvisioned()) return;
- final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
final boolean afterKeyguardGone = intent.isActivity()
&& PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
mCurrentUserId);
- dismissKeyguardThenExecute(new OnDismissAction() {
- @Override
- public boolean onDismiss() {
- new Thread() {
- @Override
- public void run() {
- try {
- // The intent we are sending is for the application, which
- // won't have permission to immediately start an activity after
- // the user switches to home. We know it is safe to do at this
- // point, so make sure new activity switches are now allowed.
- ActivityManager.getService().resumeAppSwitches();
- } catch (RemoteException e) {
- }
- try {
- intent.send(null, 0, null, null, null, null, getActivityOptions());
- } catch (PendingIntent.CanceledException e) {
- // the stack trace isn't very helpful here.
- // Just log the exception message.
- Log.w(TAG, "Sending intent failed: " + e);
-
- // TODO: Dismiss Keyguard.
- }
- if (intent.isActivity()) {
- mAssistManager.hideAssist();
- }
- }
- }.start();
-
- if (!mNotificationPanel.isFullyCollapsed()) {
- // close the shade if it was open
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
- true /* force */, true /* delayed */);
- visibilityChanged(false);
-
- return true;
- } else {
- return false;
+ dismissKeyguardThenExecute(() -> {
+ new Thread(() -> {
+ try {
+ // The intent we are sending is for the application, which
+ // won't have permission to immediately start an activity after
+ // the user switches to home. We know it is safe to do at this
+ // point, so make sure new activity switches are now allowed.
+ ActivityManager.getService().resumeAppSwitches();
+ } catch (RemoteException e) {
}
+ try {
+ intent.send(null, 0, null, null, null, null, getActivityOptions());
+ } catch (PendingIntent.CanceledException e) {
+ // the stack trace isn't very helpful here.
+ // Just log the exception message.
+ Log.w(TAG, "Sending intent failed: " + e);
+
+ // TODO: Dismiss Keyguard.
+ }
+ if (intent.isActivity()) {
+ mAssistManager.hideAssist();
+ }
+ }).start();
+
+ if (!mNotificationPanel.isFullyCollapsed()) {
+ // close the shade if it was open
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
+ true /* delayed */);
+ visibilityChanged(false);
+
+ return true;
+ } else {
+ return false;
}
}, afterKeyguardGone);
}
@@ -6999,130 +6750,110 @@
// Mark notification for one frame.
row.setJustClicked(true);
- DejankUtils.postAfterTraversal(new Runnable() {
- @Override
- public void run() {
- row.setJustClicked(false);
- }
- });
+ DejankUtils.postAfterTraversal(() -> row.setJustClicked(false));
final boolean afterKeyguardGone = intent.isActivity()
&& PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
mCurrentUserId);
- dismissKeyguardThenExecute(new OnDismissAction() {
- @Override
- public boolean onDismiss() {
- if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
- // Release the HUN notification to the shade.
+ dismissKeyguardThenExecute(() -> {
+ if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
+ // Release the HUN notification to the shade.
- if (isPanelFullyCollapsed()) {
- HeadsUpManager.setIsClickedNotification(row, true);
- }
- //
- // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
- // become canceled shortly by NoMan, but we can't assume that.
- mHeadsUpManager.releaseImmediately(notificationKey);
+ if (isPanelFullyCollapsed()) {
+ HeadsUpManager.setIsClickedNotification(row, true);
}
- StatusBarNotification parentToCancel = null;
- if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
- StatusBarNotification summarySbn = mGroupManager.getLogicalGroupSummary(sbn)
- .getStatusBarNotification();
- if (shouldAutoCancel(summarySbn)) {
- parentToCancel = summarySbn;
- }
+ //
+ // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
+ // become canceled shortly by NoMan, but we can't assume that.
+ mHeadsUpManager.releaseImmediately(notificationKey);
+ }
+ StatusBarNotification parentToCancel = null;
+ if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
+ StatusBarNotification summarySbn =
+ mGroupManager.getLogicalGroupSummary(sbn).getStatusBarNotification();
+ if (shouldAutoCancel(summarySbn)) {
+ parentToCancel = summarySbn;
}
- final StatusBarNotification parentToCancelFinal = parentToCancel;
- final Runnable runnable = new Runnable() {
- @Override
- public void run() {
- try {
- // The intent we are sending is for the application, which
- // won't have permission to immediately start an activity after
- // the user switches to home. We know it is safe to do at this
- // point, so make sure new activity switches are now allowed.
- ActivityManager.getService().resumeAppSwitches();
- } catch (RemoteException e) {
- }
- if (intent != null) {
- // If we are launching a work activity and require to launch
- // separate work challenge, we defer the activity action and cancel
- // notification until work challenge is unlocked.
- if (intent.isActivity()) {
- final int userId = intent.getCreatorUserHandle()
- .getIdentifier();
- if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
- && mKeyguardManager.isDeviceLocked(userId)) {
- // TODO(b/28935539): should allow certain activities to
- // bypass work challenge
- if (startWorkChallengeIfNecessary(userId,
- intent.getIntentSender(), notificationKey)) {
- // Show work challenge, do not run PendingIntent and
- // remove notification
- return;
- }
- }
- }
- try {
- intent.send(null, 0, null, null, null, null,
- getActivityOptions());
- } catch (PendingIntent.CanceledException e) {
- // the stack trace isn't very helpful here.
- // Just log the exception message.
- Log.w(TAG, "Sending contentIntent failed: " + e);
-
- // TODO: Dismiss Keyguard.
- }
- if (intent.isActivity()) {
- mAssistManager.hideAssist();
+ }
+ final StatusBarNotification parentToCancelFinal = parentToCancel;
+ final Runnable runnable = () -> {
+ try {
+ // The intent we are sending is for the application, which
+ // won't have permission to immediately start an activity after
+ // the user switches to home. We know it is safe to do at this
+ // point, so make sure new activity switches are now allowed.
+ ActivityManager.getService().resumeAppSwitches();
+ } catch (RemoteException e) {
+ }
+ if (intent != null) {
+ // If we are launching a work activity and require to launch
+ // separate work challenge, we defer the activity action and cancel
+ // notification until work challenge is unlocked.
+ if (intent.isActivity()) {
+ final int userId = intent.getCreatorUserHandle().getIdentifier();
+ if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
+ && mKeyguardManager.isDeviceLocked(userId)) {
+ // TODO(b/28935539): should allow certain activities to
+ // bypass work challenge
+ if (startWorkChallengeIfNecessary(userId, intent.getIntentSender(),
+ notificationKey)) {
+ // Show work challenge, do not run PendingIntent and
+ // remove notification
+ return;
}
}
-
- try {
- mBarService.onNotificationClick(notificationKey);
- } catch (RemoteException ex) {
- // system process is dead if we're here.
- }
- if (parentToCancelFinal != null) {
- // We have to post it to the UI thread for synchronization
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- Runnable removeRunnable = new Runnable() {
- @Override
- public void run() {
- performRemoveNotification(parentToCancelFinal);
- }
- };
- if (isCollapsing()) {
- // To avoid lags we're only performing the remove
- // after the shade was collapsed
- addPostCollapseAction(removeRunnable);
- } else {
- removeRunnable.run();
- }
- }
- });
- }
}
- };
+ try {
+ intent.send(null, 0, null, null, null, null, getActivityOptions());
+ } catch (PendingIntent.CanceledException e) {
+ // the stack trace isn't very helpful here.
+ // Just log the exception message.
+ Log.w(TAG, "Sending contentIntent failed: " + e);
- if (mStatusBarKeyguardViewManager.isShowing()
- && mStatusBarKeyguardViewManager.isOccluded()) {
- mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
- } else {
- new Thread(runnable).start();
+ // TODO: Dismiss Keyguard.
+ }
+ if (intent.isActivity()) {
+ mAssistManager.hideAssist();
+ }
}
- if (!mNotificationPanel.isFullyCollapsed()) {
- // close the shade if it was open
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
- true /* force */, true /* delayed */);
- visibilityChanged(false);
-
- return true;
- } else {
- return false;
+ try {
+ mBarService.onNotificationClick(notificationKey);
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
}
+ if (parentToCancelFinal != null) {
+ // We have to post it to the UI thread for synchronization
+ mHandler.post(() -> {
+ Runnable removeRunnable =
+ () -> performRemoveNotification(parentToCancelFinal);
+ if (isCollapsing()) {
+ // To avoid lags we're only performing the remove
+ // after the shade was collapsed
+ addPostCollapseAction(removeRunnable);
+ } else {
+ removeRunnable.run();
+ }
+ });
+ }
+ };
+
+ if (mStatusBarKeyguardViewManager.isShowing()
+ && mStatusBarKeyguardViewManager.isOccluded()) {
+ mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
+ } else {
+ new Thread(runnable).start();
+ }
+
+ if (!mNotificationPanel.isFullyCollapsed()) {
+ // close the shade if it was open
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
+ true /* delayed */);
+ visibilityChanged(false);
+
+ return true;
+ } else {
+ return false;
}
}, afterKeyguardGone);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index c240765..bcda60e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -14,10 +14,10 @@
package com.android.systemui.statusbar.phone;
-import android.annotation.ColorInt;
+import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
+import static android.app.StatusBarManager.DISABLE_NONE;
+
import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Color;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -29,11 +29,11 @@
import android.widget.LinearLayout.LayoutParams;
import com.android.internal.statusbar.StatusBarIcon;
-import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.util.Utils.DisableStateTracker;
public interface StatusBarIconController {
@@ -149,6 +149,14 @@
mContext = group.getContext();
mIconSize = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_icon_size);
+
+ DisableStateTracker tracker =
+ new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS);
+ mGroup.addOnAttachStateChangeListener(tracker);
+ if (mGroup.isAttachedToWindow()) {
+ // In case we miss the first onAttachedToWindow event
+ tracker.onViewAttachedToWindow(mGroup);
+ }
}
protected void onIconAdded(int index, String slot, boolean blocked,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 68f8e06..1c3ee75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -33,7 +33,6 @@
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.IconLogger;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -50,21 +49,17 @@
public class StatusBarIconControllerImpl extends StatusBarIconList implements Tunable,
ConfigurationListener, Dumpable, CommandQueue.Callbacks, StatusBarIconController {
- private final DarkIconDispatcher mDarkIconDispatcher;
+ private final ArrayList<IconManager> mIconGroups = new ArrayList<>();
+ private final ArraySet<String> mIconBlacklist = new ArraySet<>();
+ private final IconLogger mIconLogger = Dependency.get(IconLogger.class);
private Context mContext;
private DemoStatusIcons mDemoStatusIcons;
- private final ArrayList<IconManager> mIconGroups = new ArrayList<>();
-
- private final ArraySet<String> mIconBlacklist = new ArraySet<>();
- private final IconLogger mIconLogger = Dependency.get(IconLogger.class);
-
public StatusBarIconControllerImpl(Context context) {
super(context.getResources().getStringArray(
com.android.internal.R.array.config_statusBarIcons));
Dependency.get(ConfigurationController.class).addCallback(this);
- mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
mContext = context;
loadDimens();
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 bbce751..09828dcd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -225,7 +225,6 @@
if (mShowing) {
if (mOccluded && !mDozing) {
mStatusBar.hideKeyguard();
- mStatusBar.stopWaitingForKeyguardExit();
if (hideBouncerWhenShowing || mBouncer.needsFullscreenBouncer()) {
hideBouncer(false /* destroyView */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
index a456786..5159e8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -71,7 +71,7 @@
break;
case MSG_NO_SIM_VISIBLE_CHANGED:
for (SignalCallback signalCluster : mSignalCallbacks) {
- signalCluster.setNoSims(msg.arg1 != 0);
+ signalCluster.setNoSims(msg.arg1 != 0, msg.arg2 != 0);
}
break;
case MSG_ETHERNET_CHANGED:
@@ -144,8 +144,8 @@
}
@Override
- public void setNoSims(boolean show) {
- obtainMessage(MSG_NO_SIM_VISIBLE_CHANGED, show ? 1 : 0, 0).sendToTarget();
+ public void setNoSims(boolean show, boolean simDetected) {
+ obtainMessage(MSG_NO_SIM_VISIBLE_CHANGED, show ? 1 : 0, simDetected ? 1 : 0).sendToTarget();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 2771011..9eee906 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -52,7 +52,7 @@
int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
String description, boolean isWide, int subId, boolean roaming) {}
default void setSubs(List<SubscriptionInfo> subs) {}
- default void setNoSims(boolean show) {}
+ default void setNoSims(boolean show, boolean simDetected) {}
default void setEthernetIndicators(IconState icon) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index c217bda..3e9d000 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -58,10 +58,8 @@
import java.util.BitSet;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashMap;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
@@ -116,7 +114,7 @@
// States that don't belong to a subcontroller.
private boolean mAirplaneMode = false;
- private boolean mHasNoSims;
+ private boolean mHasNoSubs;
private Locale mLocale = null;
// This list holds our ordering.
private List<SubscriptionInfo> mCurrentSubscriptions = new ArrayList<>();
@@ -140,6 +138,7 @@
@VisibleForTesting
ServiceState mLastServiceState;
private boolean mUserSetup;
+ private boolean mSimDetected;
/**
* Construct this controller object and register for updates.
@@ -363,7 +362,7 @@
cb.setSubs(mCurrentSubscriptions);
cb.setIsAirplaneMode(new IconState(mAirplaneMode,
TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
- cb.setNoSims(mHasNoSims);
+ cb.setNoSims(mHasNoSubs, mSimDetected);
mWifiSignalController.notifyListeners(cb);
mEthernetSignalController.notifyListeners(cb);
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
@@ -498,13 +497,27 @@
@VisibleForTesting
protected void updateNoSims() {
- boolean hasNoSims = mHasMobileDataFeature && mMobileSignalControllers.size() == 0;
- if (hasNoSims != mHasNoSims) {
- mHasNoSims = hasNoSims;
- mCallbackHandler.setNoSims(mHasNoSims);
+ boolean hasNoSubs = mHasMobileDataFeature && mMobileSignalControllers.size() == 0;
+ boolean simDetected = hasAnySim();
+ if (hasNoSubs != mHasNoSubs || simDetected != mSimDetected) {
+ mHasNoSubs = hasNoSubs;
+ mSimDetected = simDetected;
+ mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected);
}
}
+ private boolean hasAnySim() {
+ int simCount = mPhone.getSimCount();
+ for (int i = 0; i < simCount; i++) {
+ int state = mPhone.getSimState(i);
+ if (state != TelephonyManager.SIM_STATE_ABSENT
+ && state != TelephonyManager.SIM_STATE_UNKNOWN) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@VisibleForTesting
void setCurrentSubscriptions(List<SubscriptionInfo> subscriptions) {
Collections.sort(subscriptions, new Comparator<SubscriptionInfo>() {
@@ -631,7 +644,7 @@
private void notifyListeners() {
mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode,
TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
- mCallbackHandler.setNoSims(mHasNoSims);
+ mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected);
}
/**
@@ -804,6 +817,10 @@
} else {
mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_NONE);
}
+ String ssid = args.getString("ssid");
+ if (ssid != null) {
+ mDemoWifiState.ssid = ssid;
+ }
mDemoWifiState.enabled = show;
mWifiSignalController.notifyListeners();
}
@@ -822,8 +839,8 @@
}
String nosim = args.getString("nosim");
if (nosim != null) {
- mHasNoSims = nosim.equals("show");
- mCallbackHandler.setNoSims(mHasNoSims);
+ mHasNoSubs = nosim.equals("show");
+ mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected);
}
String mobile = args.getString("mobile");
if (mobile != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index f4aebae..eca6127 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -14,6 +14,11 @@
package com.android.systemui.util;
+import android.view.View;
+
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.CommandQueue;
+
import java.util.List;
import java.util.function.Consumer;
@@ -28,4 +33,52 @@
c.accept(list.get(i));
}
}
+
+ /**
+ * Sets the visibility of an UI element according to the DISABLE_* flags in
+ * {@link android.app.StatusBarManager}.
+ */
+ public static class DisableStateTracker implements CommandQueue.Callbacks,
+ View.OnAttachStateChangeListener {
+ private final int mMask1;
+ private final int mMask2;
+ private View mView;
+ private boolean mDisabled;
+
+ public DisableStateTracker(int disableMask, int disable2Mask) {
+ mMask1 = disableMask;
+ mMask2 = disable2Mask;
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ mView = v;
+ SysUiServiceProvider.getComponent(v.getContext(), CommandQueue.class)
+ .addCallbacks(this);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ SysUiServiceProvider.getComponent(mView.getContext(), CommandQueue.class)
+ .removeCallbacks(this);
+ mView = null;
+ }
+
+ /**
+ * Sets visibility of this {@link View} given the states passed from
+ * {@link com.android.systemui.statusbar.CommandQueue.Callbacks#disable(int, int)}.
+ */
+ @Override
+ public void disable(int state1, int state2, boolean animate) {
+ final boolean disabled = ((state1 & mMask1) != 0) || ((state2 & mMask2) != 0);
+ if (disabled == mDisabled) return;
+ mDisabled = disabled;
+ mView.setVisibility(disabled ? View.GONE : View.VISIBLE);
+ }
+
+ /** @return {@code true} if and only if this {@link View} is currently disabled */
+ public boolean isDisabled() {
+ return mDisabled;
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java
index 4f87b02..e023e87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java
@@ -14,6 +14,7 @@
package com.android.systemui.qs.car;
import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
import android.content.Context;
import android.support.test.filters.SmallTest;
@@ -27,6 +28,7 @@
import com.android.keyguard.CarrierText;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.Clock;
import org.junit.Before;
@@ -54,7 +56,7 @@
.replace(CarrierText.class, View.class)
.replace(Clock.class, View.class)
.build());
-
+ mSysuiContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
mDependency.injectTestDependency(Dependency.BG_LOOPER,
TestableLooper.get(this).getLooper());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
index 51bd7bc..e3558d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
@@ -161,12 +161,11 @@
@Test
public void testSignalCallback_setNoSims() {
boolean noSims = true;
- mHandler.setNoSims(noSims);
+ boolean simDetected = false;
+ mHandler.setNoSims(noSims, simDetected);
waitForCallbacks();
- ArgumentCaptor<Boolean> noSimsArg = ArgumentCaptor.forClass(Boolean.class);
- Mockito.verify(mSignalCallback).setNoSims(noSimsArg.capture());
- assertEquals(noSims, (boolean) noSimsArg.getValue());
+ Mockito.verify(mSignalCallback).setNoSims(eq(noSims), eq(simDetected));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index b7e6a40..f685b1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -292,10 +292,8 @@
}
protected void verifyHasNoSims(boolean hasNoSimsVisible) {
- ArgumentCaptor<Boolean> hasNoSimsArg = ArgumentCaptor.forClass(Boolean.class);
-
- Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setNoSims(hasNoSimsArg.capture());
- assertEquals("No sims", hasNoSimsVisible, (boolean) hasNoSimsArg.getValue());
+ Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setNoSims(
+ eq(hasNoSimsVisible), eq(false));
}
protected void verifyLastQsMobileDataIndicators(boolean visible, int icon, int typeIcon,
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 84c67a1..787d363 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4626,6 +4626,16 @@
// OS: P
DIALOG_ENABLE_OEM_UNLOCKING = 1159;
+ // OPEN: Settings > Security > Nexus Imprint > [Fingerprint]
+ // CATEGORY: SETTINGS
+ // OS: P
+ FINGERPRINT_AUTHENTICATE_SIDECAR = 1160;
+
+ // OPEN: Settings > Developer options > USB debugging > Info dialog
+ // CATEGORY: SETTINGS
+ // OS: P
+ DIALOG_ENABLE_ADB = 1161;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 28bf856..54eba2b 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -315,6 +315,27 @@
// Pno scan metrics
optional PnoScanMetrics pno_scan_metrics = 76;
+
+ // Histogram of "Connect to Network" notifications.
+ // The notification Action should be unset.
+ repeated ConnectToNetworkNotificationAndActionCount connect_to_network_notification_count = 77;
+
+ // Histogram of "Connect to Network" notification user actions.
+ repeated ConnectToNetworkNotificationAndActionCount connect_to_network_notification_action_count = 78;
+
+ // The number of SSIDs blacklisted from recommendation by the open network
+ // notification recommender
+ optional int32 open_network_recommender_blacklist_size = 79;
+
+ // Is the available network notification feature turned on
+ optional bool is_wifi_networks_available_notification_on = 80;
+
+ // Count of recommendation updates made by the open network notification
+ // recommender
+ optional int32 num_open_network_recommendation_updates = 81;
+
+ // Count of connection attempts that were initiated unsuccessfully
+ optional int32 num_open_network_connect_message_failed_to_send = 82;
}
// Information that gets logged for every WiFi connection.
@@ -950,3 +971,68 @@
// Total number of pno scans that found any network
optional int32 num_pno_found_network_events = 5;
}
+
+// Number of occurrences for a particular "Connect to Network" Notification or
+// notification Action.
+message ConnectToNetworkNotificationAndActionCount {
+
+ // "Connect to Network" notifications
+ enum Notification {
+
+ // Default
+ NOTIFICATION_UNKNOWN = 0;
+
+ // Initial notification with a recommended network.
+ NOTIFICATION_RECOMMEND_NETWORK = 1;
+
+ // Notification when connecting to the recommended network.
+ NOTIFICATION_CONNECTING_TO_NETWORK = 2;
+
+ // Notification when successfully connected to the network.
+ NOTIFICATION_CONNECTED_TO_NETWORK = 3;
+
+ // Notification when failed to connect to network.
+ NOTIFICATION_FAILED_TO_CONNECT = 4;
+ }
+
+ // "Connect to Network" notification actions
+ enum Action {
+
+ // Default
+ ACTION_UNKNOWN = 0;
+
+ // User dismissed the "Connect to Network" notification.
+ ACTION_USER_DISMISSED_NOTIFICATION = 1;
+
+ // User tapped action button to connect to recommended network.
+ ACTION_CONNECT_TO_NETWORK = 2;
+
+ // User tapped action button to open Wi-Fi Settings.
+ ACTION_PICK_WIFI_NETWORK = 3;
+
+ // User tapped "Failed to connect" notification to open Wi-Fi Settings.
+ ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE = 4;
+ }
+
+ // Recommenders of the "Connect to Network" notification
+ enum Recommender {
+
+ // Default.
+ RECOMMENDER_UNKNOWN = 0;
+
+ // Open Network Available recommender.
+ RECOMMENDER_OPEN = 1;
+ }
+
+ // Notification Type.
+ optional Notification notification = 1;
+
+ // Action Type.
+ optional Action action = 2;
+
+ // Recommender Type.
+ optional Recommender recommender = 3;
+
+ // Occurrences of this action.
+ optional int32 count = 4;
+}
diff --git a/services/art-profile b/services/art-profile
index ae5c909..ac5ecaf 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -2134,23 +2134,15 @@
HPLcom/android/server/autofill/ui/AutoFillUI$AutoFillUiCallback;->requestShowFillUi(Landroid/view/autofill/AutofillId;IILandroid/view/autofill/IAutofillWindowPresenter;)V
HPLcom/android/server/autofill/ui/AutoFillUI$AutoFillUiCallback;->save()V
HPLcom/android/server/autofill/ui/AutoFillUI$AutoFillUiCallback;->startIntentSender(Landroid/content/IntentSender;)V
-HPLcom/android/server/backup/BackupManagerService$1;->run()V
-HPLcom/android/server/backup/BackupManagerService$3;->onReceive(Landroid/content/Context;Landroid/content/Intent;)V
-HPLcom/android/server/backup/BackupManagerService$7;-><init>(Lcom/android/server/backup/BackupManagerService;Ljava/lang/String;Ljava/util/HashSet;)V
-HPLcom/android/server/backup/BackupManagerService$7;->run()V
-HPLcom/android/server/backup/BackupManagerService$BackupRequest;-><init>(Lcom/android/server/backup/BackupManagerService;Ljava/lang/String;)V
-HPLcom/android/server/backup/BackupManagerService;->-wrap18(Lcom/android/server/backup/BackupManagerService;Ljava/lang/String;Ljava/util/HashSet;)V
-HPLcom/android/server/backup/BackupManagerService;->addPackageParticipantsLockedInner(Ljava/lang/String;Ljava/util/List;)V
-HPLcom/android/server/backup/BackupManagerService;->allAgentPackages()Ljava/util/List;
-HPLcom/android/server/backup/BackupManagerService;->appIsDisabled(Landroid/content/pm/ApplicationInfo;Landroid/content/pm/PackageManager;)Z
-HPLcom/android/server/backup/BackupManagerService;->appIsEligibleForBackup(Landroid/content/pm/ApplicationInfo;Landroid/content/pm/PackageManager;)Z
-HPLcom/android/server/backup/BackupManagerService;->dataChanged(Ljava/lang/String;)V
-HPLcom/android/server/backup/BackupManagerService;->dataChangedImpl(Ljava/lang/String;)V
-HPLcom/android/server/backup/BackupManagerService;->dataChangedImpl(Ljava/lang/String;Ljava/util/HashSet;)V
-HPLcom/android/server/backup/BackupManagerService;->dataChangedTargets(Ljava/lang/String;)Ljava/util/HashSet;
-HPLcom/android/server/backup/BackupManagerService;->dequeueFullBackupLocked(Ljava/lang/String;)V
-HPLcom/android/server/backup/BackupManagerService;->readFullBackupSchedule()Ljava/util/ArrayList;
-HPLcom/android/server/backup/BackupManagerService;->writeToJournalLocked(Ljava/lang/String;)V
+HPLcom/android/server/backup/RefactoredBackupManagerService;->addPackageParticipantsLockedInner(Ljava/lang/String;Ljava/util/List;)V
+HPLcom/android/server/backup/RefactoredBackupManagerService;->allAgentPackages()Ljava/util/List;
+HPLcom/android/server/backup/RefactoredBackupManagerService;->dataChanged(Ljava/lang/String;)V
+HPLcom/android/server/backup/RefactoredBackupManagerService;->dataChangedImpl(Ljava/lang/String;)V
+HPLcom/android/server/backup/RefactoredBackupManagerService;->dataChangedImpl(Ljava/lang/String;Ljava/util/HashSet;)V
+HPLcom/android/server/backup/RefactoredBackupManagerService;->dataChangedTargets(Ljava/lang/String;)Ljava/util/HashSet;
+HPLcom/android/server/backup/RefactoredBackupManagerService;->dequeueFullBackupLocked(Ljava/lang/String;)V
+HPLcom/android/server/backup/RefactoredBackupManagerService;->readFullBackupSchedule()Ljava/util/ArrayList;
+HPLcom/android/server/backup/RefactoredBackupManagerService;->writeToJournalLocked(Ljava/lang/String;)V
HPLcom/android/server/backup/BackupManagerServiceInterface;->acknowledgeAdbBackupOrRestore(IZLjava/lang/String;Ljava/lang/String;Landroid/app/backup/IFullBackupRestoreObserver;)V
HPLcom/android/server/backup/BackupManagerServiceInterface;->adbBackup(Landroid/os/ParcelFileDescriptor;ZZZZZZZZ[Ljava/lang/String;)V
HPLcom/android/server/backup/BackupManagerServiceInterface;->adbRestore(Landroid/os/ParcelFileDescriptor;)V
@@ -2200,6 +2192,8 @@
HPLcom/android/server/backup/Trampoline;->dataChanged(Ljava/lang/String;)V
HPLcom/android/server/backup/TransportManager$TransportBoundListener;->onTransportBound(Lcom/android/internal/backup/IBackupTransport;)Z
HPLcom/android/server/backup/TransportManager;->onPackageRemoved(Ljava/lang/String;)V
+HPLcom/android/server/backup/utils/AppBackupUtils;->appIsDisabled(Landroid/content/pm/ApplicationInfo;Landroid/content/pm/PackageManager;)Z
+HPLcom/android/server/backup/utils/AppBackupUtils;->appIsEligibleForBackup(Landroid/content/pm/ApplicationInfo;Landroid/content/pm/PackageManager;)Z
HPLcom/android/server/clipboard/ClipboardService$ClipboardImpl;->hasPrimaryClip(Ljava/lang/String;)Z
HPLcom/android/server/clipboard/ClipboardService;->clipboardAccessAllowed(ILjava/lang/String;I)Z
HPLcom/android/server/companion/CompanionDeviceManagerService$CompanionDeviceManagerImpl;->checkCallerIsSystemOr(Ljava/lang/String;I)V
@@ -9364,61 +9358,30 @@
PLcom/android/server/autofill/ui/AutoFillUI;->lambda$-com_android_server_autofill_ui_AutoFillUI_4826(Lcom/android/server/autofill/ui/AutoFillUI$AutoFillUiCallback;Ljava/lang/String;)V
PLcom/android/server/autofill/ui/AutoFillUI;->setCallback(Lcom/android/server/autofill/ui/AutoFillUI$AutoFillUiCallback;)V
PLcom/android/server/autofill/ui/OverlayControl;-><init>(Landroid/content/Context;)V
-PLcom/android/server/backup/-$Lambda$UGPbw6RN8_4TeqlxQ94PEo_ieak;->$m$0()V
-PLcom/android/server/backup/-$Lambda$UGPbw6RN8_4TeqlxQ94PEo_ieak;-><init>(BLjava/lang/Object;)V
-PLcom/android/server/backup/-$Lambda$UGPbw6RN8_4TeqlxQ94PEo_ieak;->run()V
-PLcom/android/server/backup/BackupManagerService$1;-><init>(Lcom/android/server/backup/BackupManagerService;)V
-PLcom/android/server/backup/BackupManagerService$2;-><init>(Lcom/android/server/backup/BackupManagerService;)V
-PLcom/android/server/backup/BackupManagerService$2;->onTransportBound(Lcom/android/internal/backup/IBackupTransport;)Z
-PLcom/android/server/backup/BackupManagerService$3;-><init>(Lcom/android/server/backup/BackupManagerService;)V
-PLcom/android/server/backup/BackupManagerService$4;-><init>(Lcom/android/server/backup/BackupManagerService;J)V
-PLcom/android/server/backup/BackupManagerService$4;->run()V
-PLcom/android/server/backup/BackupManagerService$8;-><init>(Lcom/android/server/backup/BackupManagerService;Landroid/content/ComponentName;Landroid/app/backup/ISelectBackupTransportCallback;)V
-PLcom/android/server/backup/BackupManagerService$8;->onSuccess(Ljava/lang/String;)V
-PLcom/android/server/backup/BackupManagerService$BackupHandler;-><init>(Lcom/android/server/backup/BackupManagerService;Landroid/os/Looper;)V
-PLcom/android/server/backup/BackupManagerService$BackupHandler;->handleMessage(Landroid/os/Message;)V
-PLcom/android/server/backup/BackupManagerService$FullBackupEntry;-><init>(Lcom/android/server/backup/BackupManagerService;Ljava/lang/String;J)V
-PLcom/android/server/backup/BackupManagerService$FullBackupEntry;->compareTo(Lcom/android/server/backup/BackupManagerService$FullBackupEntry;)I
-PLcom/android/server/backup/BackupManagerService$FullBackupEntry;->compareTo(Ljava/lang/Object;)I
-PLcom/android/server/backup/BackupManagerService$Lifecycle;-><init>(Landroid/content/Context;)V
-PLcom/android/server/backup/BackupManagerService$Lifecycle;->onStart()V
-PLcom/android/server/backup/BackupManagerService$Lifecycle;->onUnlockUser(I)V
-PLcom/android/server/backup/BackupManagerService$ProvisionedObserver;-><init>(Lcom/android/server/backup/BackupManagerService;Landroid/os/Handler;)V
-PLcom/android/server/backup/BackupManagerService$RunBackupReceiver;-><init>(Lcom/android/server/backup/BackupManagerService;)V
-PLcom/android/server/backup/BackupManagerService$RunBackupReceiver;-><init>(Lcom/android/server/backup/BackupManagerService;Lcom/android/server/backup/BackupManagerService$RunBackupReceiver;)V
-PLcom/android/server/backup/BackupManagerService$RunInitializeReceiver;-><init>(Lcom/android/server/backup/BackupManagerService;)V
-PLcom/android/server/backup/BackupManagerService$RunInitializeReceiver;-><init>(Lcom/android/server/backup/BackupManagerService;Lcom/android/server/backup/BackupManagerService$RunInitializeReceiver;)V
-PLcom/android/server/backup/BackupManagerService;->-get3(Lcom/android/server/backup/BackupManagerService;)Landroid/content/pm/PackageManager;
-PLcom/android/server/backup/BackupManagerService;->-get6(Lcom/android/server/backup/BackupManagerService;)Lcom/android/server/backup/TransportManager;
-PLcom/android/server/backup/BackupManagerService;->-wrap11(I)Z
-PLcom/android/server/backup/BackupManagerService;->-wrap17(Lcom/android/server/backup/BackupManagerService;Ljava/lang/String;)V
-PLcom/android/server/backup/BackupManagerService;->-wrap23(Lcom/android/server/backup/BackupManagerService;Ljava/lang/String;)V
-PLcom/android/server/backup/BackupManagerService;->-wrap25(Lcom/android/server/backup/BackupManagerService;)V
-PLcom/android/server/backup/BackupManagerService;->-wrap5(Landroid/content/pm/PackageInfo;)Z
-PLcom/android/server/backup/BackupManagerService;->-wrap9(I)Z
-PLcom/android/server/backup/BackupManagerService;-><init>(Landroid/content/Context;Lcom/android/server/backup/Trampoline;)V
-PLcom/android/server/backup/BackupManagerService;->addPackageParticipantsLocked([Ljava/lang/String;)V
-PLcom/android/server/backup/BackupManagerService;->appGetsFullBackup(Landroid/content/pm/PackageInfo;)Z
-PLcom/android/server/backup/BackupManagerService;->backupSettingMigrated(I)Z
-PLcom/android/server/backup/BackupManagerService;->enqueueFullBackup(Ljava/lang/String;J)V
-PLcom/android/server/backup/BackupManagerService;->getCurrentTransport()Ljava/lang/String;
-PLcom/android/server/backup/BackupManagerService;->initPackageTracking()V
-PLcom/android/server/backup/BackupManagerService;->isBackupEnabled()Z
-PLcom/android/server/backup/BackupManagerService;->lambda$-com_android_server_backup_BackupManagerService_56585()V
-PLcom/android/server/backup/BackupManagerService;->parseLeftoverJournals()V
-PLcom/android/server/backup/BackupManagerService;->readBackupEnableState(I)Z
-PLcom/android/server/backup/BackupManagerService;->removePackageFromSetLocked(Ljava/util/HashSet;Ljava/lang/String;)V
-PLcom/android/server/backup/BackupManagerService;->removePackageParticipantsLocked([Ljava/lang/String;I)V
-PLcom/android/server/backup/BackupManagerService;->scheduleNextFullBackupJob(J)V
-PLcom/android/server/backup/BackupManagerService;->selectBackupTransportAsync(Landroid/content/ComponentName;Landroid/app/backup/ISelectBackupTransportCallback;)V
-PLcom/android/server/backup/BackupManagerService;->setBackupEnabled(Z)V
-PLcom/android/server/backup/BackupManagerService;->updateStateForTransport(Ljava/lang/String;)V
-PLcom/android/server/backup/BackupManagerService;->writeBackupEnableState(ZI)V
-PLcom/android/server/backup/BackupManagerService;->writeFullBackupScheduleAsync()V
+PLcom/android/server/backup/RefactoredBackupManagerService$Lifecycle;-><init>(Landroid/content/Context;)V
+PLcom/android/server/backup/RefactoredBackupManagerService$Lifecycle;->onStart()V
+PLcom/android/server/backup/RefactoredBackupManagerService$Lifecycle;->onUnlockUser(I)V
+PLcom/android/server/backup/RefactoredBackupManagerService;-><init>(Landroid/content/Context;Lcom/android/server/backup/Trampoline;)V
+PLcom/android/server/backup/RefactoredBackupManagerService;->addPackageParticipantsLocked([Ljava/lang/String;)V
+PLcom/android/server/backup/RefactoredBackupManagerService;->backupSettingMigrated(I)Z
+PLcom/android/server/backup/RefactoredBackupManagerService;->enqueueFullBackup(Ljava/lang/String;J)V
+PLcom/android/server/backup/RefactoredBackupManagerService;->getCurrentTransport()Ljava/lang/String;
+PLcom/android/server/backup/RefactoredBackupManagerService;->initPackageTracking()V
+PLcom/android/server/backup/RefactoredBackupManagerService;->isBackupEnabled()Z
+PLcom/android/server/backup/RefactoredBackupManagerService;->parseLeftoverJournals()V
+PLcom/android/server/backup/RefactoredBackupManagerService;->readBackupEnableState(I)Z
+PLcom/android/server/backup/RefactoredBackupManagerService;->removePackageFromSetLocked(Ljava/util/HashSet;Ljava/lang/String;)V
+PLcom/android/server/backup/RefactoredBackupManagerService;->removePackageParticipantsLocked([Ljava/lang/String;I)V
+PLcom/android/server/backup/RefactoredBackupManagerService;->scheduleNextFullBackupJob(J)V
+PLcom/android/server/backup/RefactoredBackupManagerService;->selectBackupTransportAsync(Landroid/content/ComponentName;Landroid/app/backup/ISelectBackupTransportCallback;)V
+PLcom/android/server/backup/RefactoredBackupManagerService;->setBackupEnabled(Z)V
+PLcom/android/server/backup/RefactoredBackupManagerService;->updateStateForTransport(Ljava/lang/String;)V
+PLcom/android/server/backup/RefactoredBackupManagerService;->writeBackupEnableState(ZI)V
+PLcom/android/server/backup/RefactoredBackupManagerService;->writeFullBackupScheduleAsync()V
PLcom/android/server/backup/FullBackupJob;->schedule(Landroid/content/Context;J)V
PLcom/android/server/backup/KeyValueBackupJob;->cancel(Landroid/content/Context;)V
PLcom/android/server/backup/Trampoline;-><init>(Landroid/content/Context;)V
-PLcom/android/server/backup/Trampoline;->createBackupManagerService()Lcom/android/server/backup/BackupManagerServiceInterface;
+PLcom/android/server/backup/Trampoline;->createRefactoredBackupManagerService()Lcom/android/server/backup/BackupManagerServiceInterface;
PLcom/android/server/backup/Trampoline;->createService()Lcom/android/server/backup/BackupManagerServiceInterface;
PLcom/android/server/backup/Trampoline;->getCurrentTransport()Ljava/lang/String;
PLcom/android/server/backup/Trampoline;->getSuppressFile()Ljava/io/File;
@@ -9459,6 +9422,14 @@
PLcom/android/server/backup/TransportManager;->registerAllTransports()V
PLcom/android/server/backup/TransportManager;->selectTransport(Ljava/lang/String;)Ljava/lang/String;
PLcom/android/server/backup/TransportManager;->tryBindTransport(Landroid/content/ComponentName;)V
+PLcom/android/server/backup/internal/BackupHandler;-><init>(Lcom/android/server/backup/RefactoredBackupManagerService;Landroid/os/Looper;)V
+PLcom/android/server/backup/fullbackup/FullBackupEntry;->compareTo(Lcom/android/server/backup/fullbackup/FullBackupEntry;)I
+PLcom/android/server/backup/fullbackup/FullBackupEntry;->compareTo(Ljava/lang/Object;)I
+PLcom/android/server/backup/internal/BackupHandler;->handleMessage(Landroid/os/Message;)V
+PLcom/android/server/backup/internal/ProvisionedObserver;-><init>(Lcom/android/server/backup/RefactoredBackupManagerService;Landroid/os/Handler;)V
+PLcom/android/server/backup/internal/RunBackupReceiver;-><init>(Lcom/android/server/backup/RefactoredBackupManagerService;)V
+PLcom/android/server/backup/internal/RunInitializeReceiver;-><init>(Lcom/android/server/backup/RefactoredBackupManagerService;)V
+PLcom/android/server/backup/utils/AppBackupUtils;->appGetsFullBackup(Landroid/content/pm/PackageInfo;)Z
PLcom/android/server/camera/CameraServiceProxy$1;-><init>(Lcom/android/server/camera/CameraServiceProxy;)V
PLcom/android/server/camera/CameraServiceProxy$2;-><init>(Lcom/android/server/camera/CameraServiceProxy;)V
PLcom/android/server/camera/CameraServiceProxy$2;->notifyCameraState(Ljava/lang/String;IILjava/lang/String;)V
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index cd9bdb7..d48f23c 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -271,6 +271,10 @@
mDialog = new Dialog(context, R.style.Theme_DeviceDefault_Light_Panel);
mDialog.setContentView(view);
+ // Dialog can be dismissed when touched outside, but the negative listener should not be
+ // notified (hence the null argument).
+ mDialog.setOnDismissListener((d) -> mListener.onCancel(null));
+
final Window window = mDialog.getWindow();
window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
diff --git a/services/backup/java/com/android/server/backup/BackupManagerConstants.java b/services/backup/java/com/android/server/backup/BackupManagerConstants.java
index cd60182..245241c 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerConstants.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerConstants.java
@@ -123,7 +123,7 @@
// group the calls of these methods in a block syncrhonized on
// a reference of this object.
public synchronized long getKeyValueBackupIntervalMilliseconds() {
- if (BackupManagerService.DEBUG_SCHEDULING) {
+ if (RefactoredBackupManagerService.DEBUG_SCHEDULING) {
Slog.v(TAG, "getKeyValueBackupIntervalMilliseconds(...) returns "
+ mKeyValueBackupIntervalMilliseconds);
}
@@ -131,7 +131,7 @@
}
public synchronized long getKeyValueBackupFuzzMilliseconds() {
- if (BackupManagerService.DEBUG_SCHEDULING) {
+ if (RefactoredBackupManagerService.DEBUG_SCHEDULING) {
Slog.v(TAG, "getKeyValueBackupFuzzMilliseconds(...) returns "
+ mKeyValueBackupFuzzMilliseconds);
}
@@ -139,7 +139,7 @@
}
public synchronized boolean getKeyValueBackupRequireCharging() {
- if (BackupManagerService.DEBUG_SCHEDULING) {
+ if (RefactoredBackupManagerService.DEBUG_SCHEDULING) {
Slog.v(TAG, "getKeyValueBackupRequireCharging(...) returns "
+ mKeyValueBackupRequireCharging);
}
@@ -147,7 +147,7 @@
}
public synchronized int getKeyValueBackupRequiredNetworkType() {
- if (BackupManagerService.DEBUG_SCHEDULING) {
+ if (RefactoredBackupManagerService.DEBUG_SCHEDULING) {
Slog.v(TAG, "getKeyValueBackupRequiredNetworkType(...) returns "
+ mKeyValueBackupRequiredNetworkType);
}
@@ -155,7 +155,7 @@
}
public synchronized long getFullBackupIntervalMilliseconds() {
- if (BackupManagerService.DEBUG_SCHEDULING) {
+ if (RefactoredBackupManagerService.DEBUG_SCHEDULING) {
Slog.v(TAG, "getFullBackupIntervalMilliseconds(...) returns "
+ mFullBackupIntervalMilliseconds);
}
@@ -163,7 +163,7 @@
}
public synchronized boolean getFullBackupRequireCharging() {
- if (BackupManagerService.DEBUG_SCHEDULING) {
+ if (RefactoredBackupManagerService.DEBUG_SCHEDULING) {
Slog.v(TAG, "getFullBackupRequireCharging(...) returns " + mFullBackupRequireCharging);
}
return mFullBackupRequireCharging;
@@ -171,7 +171,7 @@
}
public synchronized int getFullBackupRequiredNetworkType() {
- if (BackupManagerService.DEBUG_SCHEDULING) {
+ if (RefactoredBackupManagerService.DEBUG_SCHEDULING) {
Slog.v(TAG, "getFullBackupRequiredNetworkType(...) returns "
+ mFullBackupRequiredNetworkType);
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index f525797..2f31fc3 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -192,6 +192,10 @@
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
+/**
+ * @Deprecated Use RefactoredBackupManagerService instead. This class is only
+ * kept for fallback and archeology reasons and will be removed soon.
+ */
public class BackupManagerService implements BackupManagerServiceInterface {
private static final String TAG = "BackupManagerService";
diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java
index 82638b4..b81a54d 100644
--- a/services/backup/java/com/android/server/backup/FullBackupJob.java
+++ b/services/backup/java/com/android/server/backup/FullBackupJob.java
@@ -61,7 +61,7 @@
@Override
public boolean onStartJob(JobParameters params) {
mParams = params;
- Trampoline service = BackupManagerService.getInstance();
+ Trampoline service = RefactoredBackupManagerService.getInstance();
return service.beginFullBackup(this);
}
@@ -69,7 +69,7 @@
public boolean onStopJob(JobParameters params) {
if (mParams != null) {
mParams = null;
- Trampoline service = BackupManagerService.getInstance();
+ Trampoline service = RefactoredBackupManagerService.getInstance();
service.endFullBackup();
}
return false;
diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
index 279c828..b38b25a 100644
--- a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
@@ -4,8 +4,8 @@
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
-import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT;
-import static com.android.server.backup.BackupManagerService.TIMEOUT_BACKUP_INTERVAL;
+import static com.android.server.backup.RefactoredBackupManagerService.OP_TYPE_BACKUP_WAIT;
+import static com.android.server.backup.RefactoredBackupManagerService.TIMEOUT_BACKUP_INTERVAL;
import android.app.ApplicationThreadConstants;
import android.app.IBackupAgent;
@@ -19,6 +19,8 @@
import android.os.SELinux;
import android.util.Slog;
+import com.android.server.backup.utils.FullBackupUtils;
+
import libcore.io.IoUtils;
import java.io.File;
@@ -78,7 +80,7 @@
mNewStateName = new File(mStateDir,
pkg + BACKUP_KEY_VALUE_NEW_STATE_FILENAME_SUFFIX);
- mManifestFile = new File(mDataDir, BackupManagerService.BACKUP_MANIFEST_FILENAME);
+ mManifestFile = new File(mDataDir, RefactoredBackupManagerService.BACKUP_MANIFEST_FILENAME);
}
public void backupOnePackage() throws IOException {
@@ -188,7 +190,7 @@
if (DEBUG) {
Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
}
- BackupManagerService.writeAppManifest(
+ FullBackupUtils.writeAppManifest(
mPackage, mPackageManager, mManifestFile, false, false);
FullBackup.backupToTar(mPackage.packageName, FullBackup.KEY_VALUE_DATA_TOKEN, null,
mDataDir.getAbsolutePath(),
@@ -251,7 +253,7 @@
t.start();
// Now pull data from the app and stuff it into the output
- BackupManagerService.routeSocketDataToOutput(pipes[0], mOutput);
+ FullBackupUtils.routeSocketDataToOutput(pipes[0], mOutput);
if (!mBackupManagerService.waitUntilOperationComplete(token)) {
Slog.e(TAG, "Full backup failed on package " + mCurrentPackage.packageName);
diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java
index b62bb5c..a2de8e7 100644
--- a/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java
@@ -13,6 +13,8 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.backup.restore.PerformAdbRestoreTask;
+
import libcore.io.IoUtils;
import java.io.File;
@@ -41,7 +43,7 @@
private final File mDataDir;
FileMetadata mInfo;
- BackupManagerService.PerformAdbRestoreTask mRestoreTask;
+ PerformAdbRestoreTask mRestoreTask;
ParcelFileDescriptor mInFD;
IBackupAgent mAgent;
int mToken;
diff --git a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
index d8411e2..5dfb0bc 100644
--- a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
+++ b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
@@ -71,7 +71,7 @@
if (delay <= 0) {
delay = interval + new Random().nextInt((int) fuzz);
}
- if (BackupManagerService.DEBUG_SCHEDULING) {
+ if (RefactoredBackupManagerService.DEBUG_SCHEDULING) {
Slog.v(TAG, "Scheduling k/v pass in " + (delay / 1000 / 60) + " minutes");
}
JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sKeyValueJobService)
@@ -110,7 +110,7 @@
}
// Time to run a key/value backup!
- Trampoline service = BackupManagerService.getInstance();
+ Trampoline service = RefactoredBackupManagerService.getInstance();
try {
service.backupNow();
} catch (RemoteException e) {}
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index 8d91e0d..f658f22 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -30,6 +30,8 @@
import android.os.ParcelFileDescriptor;
import android.util.Slog;
+import com.android.server.backup.utils.AppBackupUtils;
+
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
@@ -140,7 +142,7 @@
int N = pkgs.size();
for (int a = N-1; a >= 0; a--) {
PackageInfo pkg = pkgs.get(a);
- if (!BackupManagerService.appIsEligibleForBackup(pkg.applicationInfo, pm)) {
+ if (!AppBackupUtils.appIsEligibleForBackup(pkg.applicationInfo, pm)) {
pkgs.remove(a);
}
}
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index fcd929a..245bc1d 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -98,7 +98,7 @@
protected boolean isRefactoredServiceEnabled() {
return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.BACKUP_REFACTORED_SERVICE_DISABLED, 1) == 0;
+ Settings.Global.BACKUP_REFACTORED_SERVICE_DISABLED, 0) == 0;
}
protected int binderGetCallingUid() {
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 83bd9eb..5106c8d 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -20,6 +20,7 @@
import android.database.ContentObserver;
import android.os.BatteryStats;
+import android.os.PowerManager;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.ShellCommand;
@@ -291,6 +292,8 @@
if (mActivityManagerInternal.isSystemReady()) {
Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ intent.putExtra(Intent.EXTRA_REASON,
+ PowerManager.SHUTDOWN_LOW_BATTERY);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
}
@@ -310,6 +313,8 @@
if (mActivityManagerInternal.isSystemReady()) {
Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ intent.putExtra(Intent.EXTRA_REASON,
+ PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3ac6f2e..348c799 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.NETID_UNSET;
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.getNetworkTypeName;
@@ -90,6 +91,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -780,6 +782,13 @@
mNetworksDefined++; // used only in the log() statement below.
}
+ // Do the same for Ethernet, since it's often not specified in the configs, although many
+ // devices can use it via USB host adapters.
+ if (mNetConfigs[TYPE_ETHERNET] == null && hasService(Context.ETHERNET_SERVICE)) {
+ mLegacyTypeTracker.addSupportedType(TYPE_ETHERNET);
+ mNetworksDefined++;
+ }
+
if (VDBG) log("mNetworksDefined=" + mNetworksDefined);
mProtectedNetworks = new ArrayList<Integer>();
@@ -5540,6 +5549,11 @@
return new WakeupMessage(c, h, s, cmd, 0, 0, obj);
}
+ @VisibleForTesting
+ public boolean hasService(String name) {
+ return ServiceManager.checkService(name) != null;
+ }
+
private void logDefaultNetworkEvent(NetworkAgentInfo newNai, NetworkAgentInfo prevNai) {
int newNetid = NETID_UNSET;
int prevNetid = NETID_UNSET;
diff --git a/services/core/java/com/android/server/DiskStatsService.java b/services/core/java/com/android/server/DiskStatsService.java
index 800081e..2d2c6b0 100644
--- a/services/core/java/com/android/server/DiskStatsService.java
+++ b/services/core/java/com/android/server/DiskStatsService.java
@@ -202,6 +202,8 @@
JSONObject json = new JSONObject(jsonString);
pw.print("App Size: ");
pw.println(json.getLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY));
+ pw.print("App Data Size: ");
+ pw.println(json.getLong(DiskStatsFileLogger.APP_DATA_SIZE_AGG_KEY));
pw.print("App Cache Size: ");
pw.println(json.getLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY));
pw.print("Photos Size: ");
@@ -220,6 +222,8 @@
pw.println(json.getJSONArray(DiskStatsFileLogger.PACKAGE_NAMES_KEY));
pw.print("App Sizes: ");
pw.println(json.getJSONArray(DiskStatsFileLogger.APP_SIZES_KEY));
+ pw.print("App Data Sizes: ");
+ pw.println(json.getJSONArray(DiskStatsFileLogger.APP_DATA_KEY));
pw.print("Cache Sizes: ");
pw.println(json.getJSONArray(DiskStatsFileLogger.APP_CACHES_KEY));
} catch (IOException | JSONException e) {
@@ -235,6 +239,8 @@
proto.write(DiskStatsCachedValuesProto.AGG_APPS_SIZE,
json.getLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY));
+ proto.write(DiskStatsCachedValuesProto.AGG_APPS_DATA_SIZE,
+ json.getLong(DiskStatsFileLogger.APP_DATA_SIZE_AGG_KEY));
proto.write(DiskStatsCachedValuesProto.AGG_APPS_CACHE_SIZE,
json.getLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY));
proto.write(DiskStatsCachedValuesProto.PHOTOS_SIZE,
@@ -252,22 +258,26 @@
JSONArray packageNamesArray = json.getJSONArray(DiskStatsFileLogger.PACKAGE_NAMES_KEY);
JSONArray appSizesArray = json.getJSONArray(DiskStatsFileLogger.APP_SIZES_KEY);
+ JSONArray appDataSizesArray = json.getJSONArray(DiskStatsFileLogger.APP_DATA_KEY);
JSONArray cacheSizesArray = json.getJSONArray(DiskStatsFileLogger.APP_CACHES_KEY);
final int len = packageNamesArray.length();
- if (len == appSizesArray.length() && len == cacheSizesArray.length()) {
+ if (len == appSizesArray.length()
+ && len == appDataSizesArray.length()
+ && len == cacheSizesArray.length()) {
for (int i = 0; i < len; i++) {
long packageToken = proto.start(DiskStatsCachedValuesProto.APP_SIZES);
proto.write(DiskStatsAppSizesProto.PACKAGE_NAME,
packageNamesArray.getString(i));
proto.write(DiskStatsAppSizesProto.APP_SIZE, appSizesArray.getLong(i));
+ proto.write(DiskStatsAppSizesProto.APP_DATA_SIZE, appDataSizesArray.getLong(i));
proto.write(DiskStatsAppSizesProto.CACHE_SIZE, cacheSizesArray.getLong(i));
proto.end(packageToken);
}
} else {
- Slog.wtf(TAG, "Sizes of packageNamesArray, appSizesArray and cacheSizesArray "
- + "are not the same");
+ Slog.wtf(TAG, "Sizes of packageNamesArray, appSizesArray, appDataSizesArray "
+ + " and cacheSizesArray are not the same");
}
proto.end(cachedValuesToken);
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 2f95aa2..8adc259 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1140,17 +1140,6 @@
}
@Override
- public void setInterfaceIpv6NdOffload(String iface, boolean enable) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- try {
- mConnector.execute(
- "interface", "ipv6ndoffload", iface, (enable ? "enable" : "disable"));
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- }
-
- @Override
public void addRoute(int netId, RouteInfo route) {
modifyRoute("add", "" + netId, route);
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index c7e22be..55391b3 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -386,17 +386,6 @@
}
}
- private static String escapeNull(String arg) {
- if (TextUtils.isEmpty(arg)) {
- return "!";
- } else {
- if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
- throw new IllegalArgumentException(arg);
- }
- return arg;
- }
- }
-
/** List of crypto types.
* These must match CRYPT_TYPE_XXX in cryptfs.h AND their
* corresponding commands in CommandListener.cpp */
@@ -416,10 +405,6 @@
private final Callbacks mCallbacks;
private final LockPatternUtils mLockPatternUtils;
- private final Object mUnmountLock = new Object();
- @GuardedBy("mUnmountLock")
- private CountDownLatch mUnmountSignal;
-
/**
* The size of the crypto algorithm key in bits for OBB files. Currently
* Twofish is used which takes 128-bit keys.
@@ -699,18 +684,6 @@
}
};
- @Override
- public void waitForAsecScan() {
- throw new UnsupportedOperationException();
- }
-
- private void waitForLatch(CountDownLatch latch, String condition) {
- try {
- waitForLatch(latch, condition, -1);
- } catch (TimeoutException ignored) {
- }
- }
-
private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
throws TimeoutException {
final long startMillis = SystemClock.elapsedRealtime();
@@ -1533,48 +1506,6 @@
}
@Override
- public boolean isUsbMassStorageConnected() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setUsbMassStorageEnabled(boolean enable) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isUsbMassStorageEnabled() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getVolumeState(String mountPoint) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isExternalStorageEmulated() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int mountVolume(String path) {
- mount(findVolumeIdForPathOrThrow(path));
- return 0;
- }
-
- @Override
- public void unmountVolume(String path, boolean force, boolean removeEncryption) {
- unmount(findVolumeIdForPathOrThrow(path));
- }
-
- @Override
- public int formatVolume(String path) {
- format(findVolumeIdForPathOrThrow(path));
- return 0;
- }
-
- @Override
public void mount(String volId) {
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
@@ -1594,22 +1525,6 @@
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
final VolumeInfo vol = findVolumeByIdOrThrow(volId);
-
- // TODO: expand PMS to know about multiple volumes
- if (vol.isPrimaryPhysical()) {
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mUnmountLock) {
- mUnmountSignal = new CountDownLatch(1);
- mPms.updateExternalMediaStatus(false, true);
- waitForLatch(mUnmountSignal, "mUnmountSignal");
- mUnmountSignal = null;
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
try {
mVold.unmount(vol.id);
} catch (Exception e) {
@@ -2004,11 +1919,6 @@
}
}
- @Override
- public int[] getStorageUsers(String path) {
- throw new UnsupportedOperationException();
- }
-
private void warnOnNotMounted() {
synchronized (mLock) {
for (int i = 0; i < mVolumes.size(); i++) {
@@ -2023,79 +1933,6 @@
Slog.w(TAG, "No primary storage mounted!");
}
- @Override
- public String[] getSecureContainerList() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int createSecureContainer(String id, int sizeMb, String fstype, String key,
- int ownerUid, boolean external) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int resizeSecureContainer(String id, int sizeMb, String key) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int finalizeSecureContainer(String id) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int fixPermissionsSecureContainer(String id, int gid, String filename) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int destroySecureContainer(String id, boolean force) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int unmountSecureContainer(String id, boolean force) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isSecureContainerMounted(String id) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int renameSecureContainer(String oldId, String newId) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getSecureContainerPath(String id) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getSecureContainerFilesystemPath(String id) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void finishMediaUpdate() {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("no permission to call finishMediaUpdate()");
- }
- if (mUnmountSignal != null) {
- mUnmountSignal.countDown();
- } else {
- Slog.w(TAG, "Odd, nobody asked to unmount?");
- }
- }
-
private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
if (callerUid == android.os.Process.SYSTEM_UID) {
return true;
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 98e08e0..4e15e5d 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2969,9 +2969,13 @@
* have users launching arbitrary activities by tricking users to
* interact with malicious notifications.
*/
- checkKeyIntent(
+ if (!checkKeyIntent(
Binder.getCallingUid(),
- intent);
+ intent)) {
+ onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ "invalid intent in bundle returned");
+ return;
+ }
doNotification(
mAccounts,
account,
@@ -3366,9 +3370,13 @@
Intent intent = null;
if (result != null
&& (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
- checkKeyIntent(
+ if (!checkKeyIntent(
Binder.getCallingUid(),
- intent);
+ intent)) {
+ onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ "invalid intent in bundle returned");
+ return;
+ }
}
IAccountManagerResponse response;
if (mExpectActivityLaunch && result != null
@@ -4716,9 +4724,7 @@
* into launching arbitrary intents on the device via by tricking to click authenticator
* supplied entries in the system Settings app.
*/
- protected void checkKeyIntent(
- int authUid,
- Intent intent) throws SecurityException {
+ protected boolean checkKeyIntent(int authUid, Intent intent) {
intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
@@ -4727,6 +4733,9 @@
try {
PackageManager pm = mContext.getPackageManager();
ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
+ if (resolveInfo == null) {
+ return false;
+ }
ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
int targetUid = targetActivityInfo.applicationInfo.uid;
if (!isExportedSystemActivity(targetActivityInfo)
@@ -4736,9 +4745,10 @@
String activityName = targetActivityInfo.name;
String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
+ "does not share a signature with the supplying authenticator (%s).";
- throw new SecurityException(
- String.format(tmpl, activityName, pkgName, mAccountType));
+ Log.e(TAG, String.format(tmpl, activityName, pkgName, mAccountType));
+ return false;
}
+ return true;
} finally {
Binder.restoreCallingIdentity(bid);
}
@@ -4888,9 +4898,13 @@
}
if (result != null
&& (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
- checkKeyIntent(
+ if (!checkKeyIntent(
Binder.getCallingUid(),
- intent);
+ intent)) {
+ onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ "invalid intent in bundle returned");
+ return;
+ }
}
if (result != null
&& !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 90ad8a5..2131731 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3150,7 +3150,7 @@
sr.userId, sr.crashCount, sr.shortName, app.pid);
bringDownServiceLocked(sr);
} else if (!allowRestart
- || !mAm.mUserController.isUserRunningLocked(sr.userId, 0)) {
+ || !mAm.mUserController.isUserRunning(sr.userId, 0)) {
bringDownServiceLocked(sr);
} else {
boolean canceled = scheduleServiceRestartLocked(sr, true);
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 5da9fb2..8bcbfbe 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -16,6 +16,19 @@
package com.android.server.am;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.getStackIdForWindowingMode;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE;
import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
@@ -27,10 +40,12 @@
import static com.android.server.am.proto.ActivityDisplayProto.ID;
import android.app.ActivityManagerInternal;
+import android.app.WindowConfiguration;
import android.util.IntArray;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wm.ConfigurationContainer;
import java.util.ArrayList;
@@ -129,6 +144,204 @@
return null;
}
+ /**
+ * @return the topmost stack on the display that is compatible with the input windowing mode and
+ * activity type. {@code null} means no compatible stack on the display.
+ * @see ConfigurationContainer#isCompatible(int, int)
+ */
+ <T extends ActivityStack> T getStack(int windowingMode, int activityType) {
+ for (int i = mStacks.size() - 1; i >= 0; --i) {
+ final ActivityStack stack = mStacks.get(i);
+ // TODO: Should undefined windowing and activity type be compatible with standard type?
+ if (stack.isCompatible(windowingMode, activityType)) {
+ return (T) stack;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @see #getStack(int, int)
+ * @see #createStack(int, int, boolean)
+ */
+ <T extends ActivityStack> T getOrCreateStack(int windowingMode, int activityType,
+ boolean onTop) {
+ T stack = getStack(windowingMode, activityType);
+ if (stack != null) {
+ return stack;
+ }
+ return createStack(windowingMode, activityType, onTop);
+ }
+
+ /**
+ * Creates a stack matching the input windowing mode and activity type on this display.
+ * @param windowingMode The windowing mode the stack should be created in. If
+ * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
+ * be created in {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}.
+ * @param activityType The activityType the stack should be created in. If
+ * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
+ * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
+ * @param onTop If true the stack will be created at the top of the display, else at the bottom.
+ * @return The newly created stack.
+ */
+ <T extends ActivityStack> T createStack(int windowingMode, int activityType, boolean onTop) {
+
+ if (activityType == ACTIVITY_TYPE_UNDEFINED) {
+ // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
+ // anything else should be passing it in anyways...
+ activityType = ACTIVITY_TYPE_STANDARD;
+ }
+
+ if (activityType != ACTIVITY_TYPE_STANDARD) {
+ // For now there can be only one stack of a particular non-standard activity type on a
+ // display. So, get that ignoring whatever windowing mode it is currently in.
+ T stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
+ if (stack != null) {
+ throw new IllegalArgumentException("Stack=" + stack + " of activityType="
+ + activityType + " already on display=" + this + ". Can't have multiple.");
+ }
+ }
+
+ final ActivityManagerService service = mSupervisor.mService;
+ if (!mSupervisor.isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow,
+ service.mSupportsSplitScreenMultiWindow, service.mSupportsFreeformWindowManagement,
+ service.mSupportsPictureInPicture, activityType)) {
+ throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
+ + windowingMode);
+ }
+
+ if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+ // TODO: Should be okay to have stacks with with undefined windowing mode long term, but
+ // have to set them to something for now due to logic that depending on them.
+ windowingMode = WINDOWING_MODE_FULLSCREEN;
+ }
+
+ final boolean inSplitScreenMode = hasSplitScreenStack();
+ if (!inSplitScreenMode
+ && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
+ // Switch to fullscreen windowing mode if we are not in split-screen mode and we are
+ // trying to launch in split-screen secondary.
+ windowingMode = WINDOWING_MODE_FULLSCREEN;
+ } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
+ && WindowConfiguration.supportSplitScreenWindowingMode(
+ windowingMode, activityType)) {
+ windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+ }
+
+ int stackId = INVALID_STACK_ID;
+ if (mDisplayId == DEFAULT_DISPLAY && (activityType == ACTIVITY_TYPE_STANDARD
+ || activityType == ACTIVITY_TYPE_UNDEFINED)) {
+ // TODO: Will be removed once we are no longer using static stack ids.
+ stackId = getStackIdForWindowingMode(windowingMode);
+ if (stackId == INVALID_STACK_ID) {
+ // Whatever...put in fullscreen stack for now.
+ stackId = FULLSCREEN_WORKSPACE_STACK_ID;
+ }
+ final T stack = getStack(stackId);
+ if (stack != null) {
+ return stack;
+ }
+ }
+
+ if (stackId == INVALID_STACK_ID) {
+ stackId = mSupervisor.getNextStackId();
+ }
+
+ final T stack = createStackUnchecked(windowingMode, activityType, stackId, onTop);
+
+ if (mDisplayId == DEFAULT_DISPLAY && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ // Make sure recents stack exist when creating a dock stack as it normally need to be on
+ // the other side of the docked stack and we make visibility decisions based on that.
+ // TODO: Not sure if this is needed after we change to calculate visibility based on
+ // stack z-order vs. id.
+ getOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS, onTop);
+ }
+
+ return stack;
+ }
+
+ @VisibleForTesting
+ <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
+ int stackId, boolean onTop) {
+ switch (windowingMode) {
+ case WINDOWING_MODE_PINNED:
+ return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop);
+ default:
+ return (T) new ActivityStack(
+ this, stackId, mSupervisor, windowingMode, activityType, onTop);
+ }
+ }
+
+ /**
+ * Removes stacks in the input windowing modes from the system if they are of activity type
+ * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
+ */
+ void removeStacksInWindowingModes(int... windowingModes) {
+ if (windowingModes == null || windowingModes.length == 0) {
+ return;
+ }
+
+ for (int j = windowingModes.length - 1 ; j >= 0; --j) {
+ final int windowingMode = windowingModes[j];
+ for (int i = mStacks.size() - 1; i >= 0; --i) {
+ final ActivityStack stack = mStacks.get(i);
+ if (!stack.isActivityTypeStandardOrUndefined()) {
+ continue;
+ }
+ if (stack.getWindowingMode() != windowingMode) {
+ continue;
+ }
+ mSupervisor.removeStackLocked(stack.mStackId);
+ }
+ }
+ }
+
+ void removeStacksWithActivityTypes(int... activityTypes) {
+ if (activityTypes == null || activityTypes.length == 0) {
+ return;
+ }
+
+ for (int j = activityTypes.length - 1 ; j >= 0; --j) {
+ final int activityType = activityTypes[j];
+ for (int i = mStacks.size() - 1; i >= 0; --i) {
+ final ActivityStack stack = mStacks.get(i);
+ if (stack.getActivityType() == activityType) {
+ mSupervisor.removeStackLocked(stack.mStackId);
+ }
+ }
+ }
+ }
+
+ /** Returns the top visible stack activity type that isn't in the exclude windowing mode. */
+ int getTopVisibleStackActivityType(int excludeWindowingMode) {
+ for (int i = mStacks.size() - 1; i >= 0; --i) {
+ final ActivityStack stack = mStacks.get(i);
+ if (stack.getWindowingMode() == excludeWindowingMode) {
+ continue;
+ }
+ if (stack.shouldBeVisible(null /* starting */)) {
+ return stack.getActivityType();
+ }
+ }
+ return ACTIVITY_TYPE_UNDEFINED;
+ }
+
+ ActivityStack getSplitScreenStack() {
+ return getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
+ }
+
+ boolean hasSplitScreenStack() {
+ return getSplitScreenStack() != null;
+ }
+
+ PinnedActivityStack getPinnedStack() {
+ return getStack(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+ }
+
+ boolean hasPinnedStack() {
+ return getPinnedStack() != null;
+ }
+
@Override
public String toString() {
return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6df5fb7..cf564e4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -33,6 +33,13 @@
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.ActivityManager.StackId.getWindowingModeForStackId;
+import static android.app.ActivityManager.StackId.isStaticStack;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY;
@@ -164,7 +171,6 @@
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.ActivityStackSupervisor.CREATE_IF_NEEDED;
import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_ONLY;
import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
@@ -177,7 +183,6 @@
import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
import static com.android.server.am.proto.ActivityManagerServiceProto.ACTIVITIES;
import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
-import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH;
import static com.android.server.wm.AppTransition.TRANSIT_NONE;
import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE;
import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN;
@@ -1711,6 +1716,7 @@
static final int PUSH_TEMP_WHITELIST_UI_MSG = 68;
static final int SERVICE_FOREGROUND_CRASH_MSG = 69;
static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
+ static final int TOP_APP_KILLED_BY_LMK_MSG = 73;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1938,6 +1944,17 @@
dispatchProcessDied(pid, uid);
break;
}
+ case TOP_APP_KILLED_BY_LMK_MSG: {
+ final String appName = (String) msg.obj;
+ final AlertDialog d = new BaseErrorDialog(mUiContext);
+ d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+ d.setTitle(mUiContext.getText(R.string.top_app_killed_title));
+ d.setMessage(mUiContext.getString(R.string.top_app_killed_message, appName));
+ d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.close),
+ obtainMessage(DISMISS_DIALOG_UI_MSG, d));
+ d.show();
+ break;
+ }
case DISPATCH_UIDS_CHANGED_UI_MSG: {
dispatchUidsChanged();
} break;
@@ -2360,11 +2377,7 @@
if (disableNonVrUi) {
// If we are in a VR mode where Picture-in-Picture mode is unsupported,
// then remove the pinned stack.
- final PinnedActivityStack pinnedStack = mStackSupervisor.getStack(
- PINNED_STACK_ID);
- if (pinnedStack != null) {
- mStackSupervisor.removeStackLocked(PINNED_STACK_ID);
- }
+ mStackSupervisor.removeStacksInWindowingModes(WINDOWING_MODE_PINNED);
}
}
} break;
@@ -2519,10 +2532,12 @@
}
public void setWindowManager(WindowManagerService wm) {
- mWindowManager = wm;
- mStackSupervisor.setWindowManager(wm);
- mActivityStarter.setWindowManager(wm);
- mLockTaskController.setWindowManager(wm);
+ synchronized (this) {
+ mWindowManager = wm;
+ mStackSupervisor.setWindowManager(wm);
+ mActivityStarter.setWindowManager(wm);
+ mLockTaskController.setWindowManager(wm);
+ }
}
public void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {
@@ -5394,6 +5409,7 @@
boolean doLowMem = app.instr == null;
boolean doOomAdj = doLowMem;
if (!app.killedByAm) {
+ maybeNotifyTopAppKilled(app);
Slog.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died: "
+ ProcessList.makeOomAdjString(app.setAdj)
+ ProcessList.makeProcStateString(app.setProcState));
@@ -5427,6 +5443,23 @@
}
}
+ /** Show system error dialog when a top app is killed by LMK */
+ void maybeNotifyTopAppKilled(ProcessRecord app) {
+ if (!shouldNotifyTopAppKilled(app)) {
+ return;
+ }
+
+ Message msg = mHandler.obtainMessage(TOP_APP_KILLED_BY_LMK_MSG);
+ msg.obj = mContext.getPackageManager().getApplicationLabel(app.info);
+ mUiHandler.sendMessage(msg);
+ }
+
+ /** Only show notification when the top app is killed on low ram devices */
+ private boolean shouldNotifyTopAppKilled(ProcessRecord app) {
+ return app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
+ ActivityManager.isLowRamDeviceStatic();
+ }
+
/**
* If a stack trace dump file is configured, dump process stack traces.
* @param clearTraces causes the dump file to be erased prior to the new
@@ -6150,7 +6183,7 @@
Slog.w(TAG, "Failed trying to unstop package "
+ packageName + ": " + e);
}
- if (mUserController.isUserRunningLocked(user, 0)) {
+ if (mUserController.isUserRunning(user, 0)) {
forceStopPackageLocked(packageName, pkgUid, "from pid " + callingPid);
finishForceStopPackageLocked(packageName, pkgUid);
}
@@ -7308,33 +7341,32 @@
startProcessLocked(procs.get(ip), "on-hold", null);
}
}
-
- if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
- // Start looking for apps that are abusing wake locks.
- Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_POWER_USE_MSG);
- mHandler.sendMessageDelayed(nmsg, mConstants.POWER_CHECK_INTERVAL);
- // Tell anyone interested that we are done booting!
- SystemProperties.set("sys.boot_completed", "1");
-
- // And trigger dev.bootcomplete if we are not showing encryption progress
- if (!"trigger_restart_min_framework".equals(SystemProperties.get("vold.decrypt"))
- || "".equals(SystemProperties.get("vold.encrypt_progress"))) {
- SystemProperties.set("dev.bootcomplete", "1");
- }
- mUserController.sendBootCompletedLocked(
- new IIntentReceiver.Stub() {
- @Override
- public void performReceive(Intent intent, int resultCode,
- String data, Bundle extras, boolean ordered,
- boolean sticky, int sendingUser) {
- synchronized (ActivityManagerService.this) {
- requestPssAllProcsLocked(SystemClock.uptimeMillis(),
- true, false);
- }
- }
- });
- mUserController.scheduleStartProfilesLocked();
+ if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
+ return;
}
+ // Start looking for apps that are abusing wake locks.
+ Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_POWER_USE_MSG);
+ mHandler.sendMessageDelayed(nmsg, mConstants.POWER_CHECK_INTERVAL);
+ // Tell anyone interested that we are done booting!
+ SystemProperties.set("sys.boot_completed", "1");
+
+ // And trigger dev.bootcomplete if we are not showing encryption progress
+ if (!"trigger_restart_min_framework".equals(SystemProperties.get("vold.decrypt"))
+ || "".equals(SystemProperties.get("vold.encrypt_progress"))) {
+ SystemProperties.set("dev.bootcomplete", "1");
+ }
+ mUserController.sendBootCompleted(
+ new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode,
+ String data, Bundle extras, boolean ordered,
+ boolean sticky, int sendingUser) {
+ synchronized (ActivityManagerService.this) {
+ requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
+ }
+ }
+ });
+ mUserController.scheduleStartProfiles();
}
}
@@ -8074,7 +8106,7 @@
final Rect sourceBounds = new Rect(r.pictureInPictureArgs.getSourceRectHint());
mStackSupervisor.moveActivityToPinnedStackLocked(r, sourceBounds, aspectRatio,
true /* moveHomeStackToFront */, "enterPictureInPictureMode");
- final PinnedActivityStack stack = mStackSupervisor.getStack(PINNED_STACK_ID);
+ final PinnedActivityStack stack = r.getStack();
stack.setPictureInPictureAspectRatio(aspectRatio);
stack.setPictureInPictureActions(actions);
@@ -8189,11 +8221,6 @@
+ ": Current activity does not support picture-in-picture.");
}
- if (!StackId.isAllowedToEnterPictureInPicture(r.getStack().getStackId())) {
- throw new IllegalStateException(caller
- + ": Activities on the home, assistant, or recents stack not supported");
- }
-
if (params.hasSetAspectRatio()
&& !mWindowManager.isValidPictureInPictureAspectRatio(r.getStack().mDisplayId,
params.getAspectRatio())) {
@@ -9831,7 +9858,7 @@
if (tr.mBounds != null) {
rti.bounds = new Rect(tr.mBounds);
}
- rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreen();
+ rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreenWindowingMode();
rti.resizeMode = tr.mResizeMode;
ActivityRecord base = null;
@@ -10150,21 +10177,23 @@
// - 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.getStackId();
+ ActivityStack stack = task.getStack();
if (!task.getWindowConfiguration().canResizeTask()) {
throw new IllegalArgumentException("resizeTask not allowed on task=" + task);
}
- if (bounds == null && stackId == FREEFORM_WORKSPACE_STACK_ID) {
- stackId = FULLSCREEN_WORKSPACE_STACK_ID;
- } else if (bounds != null && stackId != FREEFORM_WORKSPACE_STACK_ID ) {
- stackId = FREEFORM_WORKSPACE_STACK_ID;
+ if (bounds == null && stack.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ stack = stack.getDisplay().getOrCreateStack(
+ WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), ON_TOP);
+ } else if (bounds != null && stack.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
+ stack = stack.getDisplay().getOrCreateStack(
+ WINDOWING_MODE_FREEFORM, stack.getActivityType(), ON_TOP);
}
// Reparent the task to the right stack if necessary
boolean preserveWindow = (resizeMode & RESIZE_MODE_PRESERVE_WINDOW) != 0;
- if (stackId != task.getStackId()) {
+ if (stack != task.getStack()) {
// Defer resume until the task is resized below
- task.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE,
+ task.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE,
DEFER_RESUME, "resizeTask");
preserveWindow = false;
}
@@ -10337,13 +10366,14 @@
@Override
public void removeStack(int stackId) {
enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS, "removeStack()");
- if (StackId.isHomeOrRecentsStack(stackId)) {
- throw new IllegalArgumentException("Removing home or recents stack is not allowed.");
- }
-
synchronized (this) {
final long ident = Binder.clearCallingIdentity();
try {
+ final ActivityStack stack = mStackSupervisor.getStack(stackId);
+ if (stack != null && !stack.isActivityTypeStandardOrUndefined()) {
+ throw new IllegalArgumentException(
+ "Removing non-standard stack is not allowed.");
+ }
mStackSupervisor.removeStackLocked(stackId);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -10351,6 +10381,36 @@
}
}
+ /**
+ * Removes stacks in the input windowing modes from the system if they are of activity type
+ * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
+ */
+ @Override
+ public void removeStacksInWindowingModes(int[] windowingModes) {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "removeStacksInWindowingModes()");
+ synchronized (this) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mStackSupervisor.removeStacksInWindowingModes(windowingModes);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @Override
+ public void removeStacksWithActivityTypes(int[] activityTypes) {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "removeStacksWithActivityTypes()");
+ synchronized (this) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mStackSupervisor.removeStacksWithActivityTypes(activityTypes);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
@Override
public void moveStackToDisplay(int stackId, int displayId) {
enforceCallingPermission(INTERNAL_SYSTEM_WINDOW, "moveStackToDisplay()");
@@ -10494,13 +10554,15 @@
public int createStackOnDisplay(int displayId) throws RemoteException {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createStackOnDisplay()");
synchronized (this) {
- final int stackId = mStackSupervisor.getNextStackId();
- final ActivityStack stack =
- mStackSupervisor.createStackOnDisplay(stackId, displayId, true /*onTop*/);
- if (stack == null) {
+ final ActivityDisplay display =
+ mStackSupervisor.getActivityDisplayOrCreateLocked(displayId);
+ if (display == null) {
return INVALID_STACK_ID;
}
- return stack.mStackId;
+ // TODO(multi-display): Have the caller pass in the windowing mode and activity type.
+ final ActivityStack stack = display.createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /*onTop*/);
+ return (stack != null) ? stack.mStackId : INVALID_STACK_ID;
}
}
@@ -10532,8 +10594,12 @@
"exitFreeformMode: You can only go fullscreen from freeform.");
}
+ final ActivityStack fullscreenStack = stack.getDisplay().getOrCreateStack(
+ WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), ON_TOP);
+
if (DEBUG_STACK) Slog.d(TAG_STACK, "exitFreeformMode: " + r);
- r.getTask().reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP,
+ // TODO: Should just change windowing mode vs. re-parenting...
+ r.getTask().reparent(fullscreenStack, ON_TOP,
REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, "exitFreeformMode");
} finally {
Binder.restoreCallingIdentity(ident);
@@ -10544,10 +10610,6 @@
@Override
public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
- if (StackId.isHomeOrRecentsStack(stackId)) {
- throw new IllegalArgumentException(
- "moveTaskToStack: Attempt to move task " + taskId + " to stack " + stackId);
- }
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
@@ -10563,8 +10625,25 @@
mWindowManager.setDockedStackCreateState(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
null /* initialBounds */);
}
- task.reparent(stackId, toTop,
- REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, "moveTaskToStack");
+
+ ActivityStack stack = mStackSupervisor.getStack(stackId);
+ if (stack == null) {
+ if (!isStaticStack(stackId)) {
+ throw new IllegalStateException(
+ "moveTaskToStack: No stack for stackId=" + stackId);
+ }
+ final ActivityDisplay display = task.getStack().getDisplay();
+ final int windowingMode =
+ getWindowingModeForStackId(stackId, display.hasSplitScreenStack());
+ stack = display.getOrCreateStack(windowingMode,
+ task.getStack().getActivityType(), toTop);
+ }
+ if (!stack.isActivityTypeStandardOrUndefined()) {
+ throw new IllegalArgumentException("moveTaskToStack: Attempt to move task "
+ + taskId + " to stack " + stackId);
+ }
+ task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
+ "moveTaskToStack");
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -10597,13 +10676,18 @@
Slog.w(TAG, "moveTaskToDockedStack: No task for id=" + taskId);
return false;
}
-
if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToDockedStack: moving task=" + taskId
+ " to createMode=" + createMode + " toTop=" + toTop);
mWindowManager.setDockedStackCreateState(createMode, initialBounds);
+ final ActivityDisplay display = task.getStack().getDisplay();
+ final ActivityStack stack = display.getOrCreateStack(
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, task.getStack().getActivityType(),
+ toTop);
+
// Defer resuming until we move the home stack to the front below
- final boolean moved = task.reparent(DOCKED_STACK_ID, toTop,
+ // TODO: Should just change windowing mode vs. re-parenting...
+ final boolean moved = task.reparent(stack, toTop,
REPARENT_KEEP_STACK_AT_FRONT, animate, !DEFER_RESUME,
"moveTaskToDockedStack");
if (moved) {
@@ -10651,17 +10735,16 @@
try {
synchronized (this) {
if (animate) {
- if (stackId == PINNED_STACK_ID) {
- final PinnedActivityStack pinnedStack =
- mStackSupervisor.getStack(PINNED_STACK_ID);
- if (pinnedStack != null) {
- pinnedStack.animateResizePinnedStack(null /* sourceHintBounds */,
- destBounds, animationDuration, false /* fromFullscreen */);
- }
- } else {
+ final PinnedActivityStack stack = mStackSupervisor.getStack(stackId);
+ if (stack == null) {
+ return;
+ }
+ if (stack.getWindowingMode() != WINDOWING_MODE_PINNED) {
throw new IllegalArgumentException("Stack: " + stackId
+ " doesn't support animated resize.");
}
+ stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds,
+ animationDuration, false /* fromFullscreen */);
} else {
mStackSupervisor.resizeStackLocked(stackId, destBounds, null /* tempTaskBounds */,
null /* tempTaskInsetBounds */, preserveWindows,
@@ -10713,11 +10796,6 @@
@Override
public void positionTaskInStack(int taskId, int stackId, int position) {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "positionTaskInStack()");
- if (StackId.isHomeOrRecentsStack(stackId)) {
- throw new IllegalArgumentException(
- "positionTaskInStack: Attempt to change the position of task "
- + taskId + " in/to home/recents stack");
- }
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
@@ -10729,8 +10807,16 @@
+ taskId);
}
- final ActivityStack stack = mStackSupervisor.getStack(stackId, CREATE_IF_NEEDED,
- !ON_TOP);
+ final ActivityStack stack = mStackSupervisor.getStack(stackId);
+
+ if (stack == null) {
+ throw new IllegalArgumentException("positionTaskInStack: no stack for id="
+ + stackId);
+ }
+ if (!stack.isActivityTypeStandardOrUndefined()) {
+ throw new IllegalArgumentException("positionTaskInStack: Attempt to change"
+ + " the position of task " + taskId + " in/to non-standard stack");
+ }
// TODO: Have the callers of this API call a separate reparent method if that is
// what they intended to do vs. having this method also do reparenting.
@@ -10739,8 +10825,8 @@
stack.positionChildAt(task, position);
} else {
// Reparent to new stack.
- task.reparent(stackId, position, REPARENT_LEAVE_STACK_IN_PLACE,
- !ANIMATE, !DEFER_RESUME, "positionTaskInStack");
+ task.reparent(stack, position, REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE,
+ !DEFER_RESUME, "positionTaskInStack");
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -10762,12 +10848,12 @@
}
@Override
- public StackInfo getStackInfo(int stackId) {
+ public StackInfo getStackInfo(int windowingMode, int activityType) {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
- return mStackSupervisor.getStackInfoLocked(stackId);
+ return mStackSupervisor.getStackInfo(windowingMode, activityType);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -10818,11 +10904,7 @@
}
// When a task is locked, dismiss the pinned stack if it exists
- final PinnedActivityStack pinnedStack = mStackSupervisor.getStack(
- PINNED_STACK_ID);
- if (pinnedStack != null) {
- mStackSupervisor.removeStackLocked(PINNED_STACK_ID);
- }
+ mStackSupervisor.removeStacksInWindowingModes(WINDOWING_MODE_PINNED);
// isAppPinning is used to distinguish between locked and pinned mode, as pinned mode
// is initiated by system after the pinning request was shown and locked mode is initiated
@@ -11049,7 +11131,7 @@
boolean checkedGrants = false;
if (checkUser) {
// Looking for cross-user grants before enforcing the typical cross-users permissions
- int tmpTargetUserId = mUserController.unsafeConvertIncomingUserLocked(userId);
+ int tmpTargetUserId = mUserController.unsafeConvertIncomingUser(userId);
if (tmpTargetUserId != UserHandle.getUserId(callingUid)) {
if (checkAuthorityGrants(callingUid, cpi, tmpTargetUserId, checkUser)) {
return null;
@@ -11437,7 +11519,7 @@
// Make sure that the user who owns this provider is running. If not,
// we don't want to allow it to run.
- if (!mUserController.isUserRunningLocked(userId, 0)) {
+ if (!mUserController.isUserRunning(userId, 0)) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
@@ -12067,9 +12149,7 @@
int callingPid = Binder.getCallingPid();
long ident = 0;
boolean clearedIdentity = false;
- synchronized (this) {
- userId = mUserController.unsafeConvertIncomingUserLocked(userId);
- }
+ userId = mUserController.unsafeConvertIncomingUser(userId);
if (canClearIdentity(callingPid, callingUid, userId)) {
clearedIdentity = true;
ident = Binder.clearCallingIdentity();
@@ -12487,7 +12567,7 @@
if (mUserController.shouldConfirmCredentials(userId)) {
if (mKeyguardController.isKeyguardLocked()) {
// Showing launcher to avoid user entering credential twice.
- final int currentUserId = mUserController.getCurrentUserIdLocked();
+ final int currentUserId = mUserController.getCurrentUserId();
startHomeActivityLocked(currentUserId, "notifyLockedProfile");
}
mStackSupervisor.lockAllProfileTasks(userId);
@@ -14067,9 +14147,8 @@
}
retrieveSettings();
- final int currentUserId;
+ final int currentUserId = mUserController.getCurrentUserId();
synchronized (this) {
- currentUserId = mUserController.getCurrentUserIdLocked();
readGrantedUriPermissionsLocked();
}
@@ -14148,7 +14227,7 @@
Binder.restoreCallingIdentity(ident);
}
mStackSupervisor.resumeFocusedStackTopActivityLocked();
- mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
+ mUserController.sendUserSwitchBroadcasts(-1, currentUserId);
traceLog.traceEnd(); // ActivityManagerStartApps
traceLog.traceEnd(); // PhaseActivityManagerReady
}
@@ -18976,7 +19055,7 @@
// If not, we will just skip it. Make an exception for shutdown broadcasts
// and upgrade steps.
- if (userId != UserHandle.USER_ALL && !mUserController.isUserRunningLocked(userId, 0)) {
+ if (userId != UserHandle.USER_ALL && !mUserController.isUserRunning(userId, 0)) {
if ((callingUid != SYSTEM_UID
|| (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
&& !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
@@ -19395,7 +19474,7 @@
int[] users;
if (userId == UserHandle.USER_ALL) {
// Caller wants broadcast to go to all started users.
- users = mUserController.getStartedUserArrayLocked();
+ users = mUserController.getStartedUserArray();
} else {
// Caller wants broadcast to go to one specific user.
users = new int[] {userId};
@@ -20021,12 +20100,20 @@
}
@Override
- public int getFocusedStackId() throws RemoteException {
- ActivityStack focusedStack = getFocusedStack();
- if (focusedStack != null) {
- return focusedStack.getStackId();
+ public StackInfo getFocusedStackInfo() throws RemoteException {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ ActivityStack focusedStack = getFocusedStack();
+ if (focusedStack != null) {
+ return mStackSupervisor.getStackInfo(focusedStack.mStackId);
+ }
+ return null;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- return -1;
}
public Configuration getConfiguration() {
@@ -20052,16 +20139,18 @@
* activity and clearing the task at the same time.
*/
@Override
+ // TODO: API should just be about changing windowing modes...
public void moveTasksToFullscreenStack(int fromStackId, boolean onTop) {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTasksToFullscreenStack()");
- if (StackId.isHomeOrRecentsStack(fromStackId)) {
- throw new IllegalArgumentException("You can't move tasks from the home/recents stack.");
- }
synchronized (this) {
final long origId = Binder.clearCallingIdentity();
try {
final ActivityStack stack = mStackSupervisor.getStack(fromStackId);
if (stack != null){
+ if (!stack.isActivityTypeStandardOrUndefined()) {
+ throw new IllegalArgumentException(
+ "You can't move tasks from non-standard stacks.");
+ }
mStackSupervisor.moveTasksToFullscreenStackLocked(stack, onTop);
}
} finally {
@@ -20161,7 +20250,7 @@
void updateUserConfigurationLocked() {
final Configuration configuration = new Configuration(getGlobalConfiguration());
- final int currentUserId = mUserController.getCurrentUserIdLocked();
+ final int currentUserId = mUserController.getCurrentUserId();
Settings.System.adjustConfigurationForUser(mContext.getContentResolver(), configuration,
currentUserId, Settings.System.canWrite(mContext));
updateConfigurationLocked(configuration, null /* starting */, false /* initLocale */,
@@ -20272,7 +20361,7 @@
Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempConfig);
// TODO(multi-display): Update UsageEvents#Event to include displayId.
mUsageStatsService.reportConfigurationChange(mTempConfig,
- mUserController.getCurrentUserIdLocked());
+ mUserController.getCurrentUserId());
// TODO: If our config changes, should we auto dismiss any currently showing dialogs?
mShowDialogs = shouldShowDialogs(mTempConfig);
@@ -22203,7 +22292,7 @@
String authority) {
if (app == null) return;
if (app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
- UserState userState = mUserController.getStartedUserStateLocked(app.userId);
+ UserState userState = mUserController.getStartedUserState(app.userId);
if (userState == null) return;
final long now = SystemClock.elapsedRealtime();
Long lastReported = userState.mProviderLastReportedFg.get(authority);
@@ -23512,10 +23601,8 @@
}
String getStartedUserState(int userId) {
- synchronized (this) {
- final UserState userState = mUserController.getStartedUserStateLocked(userId);
- return UserState.stateToString(userState.state);
- }
+ final UserState userState = mUserController.getStartedUserState(userId);
+ return UserState.stateToString(userState.state);
}
@Override
@@ -23530,9 +23617,7 @@
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
- synchronized (this) {
- return mUserController.isUserRunningLocked(userId, flags);
- }
+ return mUserController.isUserRunning(userId, flags);
}
@Override
@@ -23546,9 +23631,7 @@
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
- synchronized (this) {
- return mUserController.getStartedUserArrayLocked();
- }
+ return mUserController.getStartedUserArray();
}
@Override
@@ -23569,9 +23652,7 @@
}
public boolean isUserStopped(int userId) {
- synchronized (this) {
- return mUserController.getStartedUserStateLocked(userId) == null;
- }
+ return mUserController.getStartedUserState(userId) == null;
}
ActivityInfo getActivityInfoForUser(ActivityInfo aInfo, int userId) {
@@ -24159,7 +24240,7 @@
permission.INTERACT_ACROSS_USERS_FULL, "getLastResumedActivityUserId()");
synchronized (this) {
if (mLastResumedActivity == null) {
- return mUserController.getCurrentUserIdLocked();
+ return mUserController.getCurrentUserId();
}
return mLastResumedActivity.userId;
}
@@ -24366,7 +24447,7 @@
if (updateFrameworkRes || packagesToUpdate.contains(packageName)) {
try {
final ApplicationInfo ai = AppGlobals.getPackageManager()
- .getApplicationInfo(packageName, 0 /*flags*/, app.userId);
+ .getApplicationInfo(packageName, STOCK_PM_FLAGS, app.userId);
if (ai != null) {
app.thread.scheduleApplicationInfoChanged(ai);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 5e0724e..4c93423 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -76,6 +76,7 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.INVALID_DISPLAY;
@@ -2113,9 +2114,9 @@
}
int runStackInfo(PrintWriter pw) throws RemoteException {
- String stackIdStr = getNextArgRequired();
- int stackId = Integer.parseInt(stackIdStr);
- ActivityManager.StackInfo info = mInterface.getStackInfo(stackId);
+ int windowingMode = Integer.parseInt(getNextArgRequired());
+ int activityType = Integer.parseInt(getNextArgRequired());
+ ActivityManager.StackInfo info = mInterface.getStackInfo(windowingMode, activityType);
pw.println(info);
return 0;
}
@@ -2149,7 +2150,8 @@
final String delayStr = getNextArg();
final int delayMs = (delayStr != null) ? Integer.parseInt(delayStr) : 0;
- ActivityManager.StackInfo info = mInterface.getStackInfo(DOCKED_STACK_ID);
+ ActivityManager.StackInfo info = mInterface.getStackInfo(
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
if (info == null) {
err.println("Docked stack doesn't exist");
return -1;
@@ -2252,10 +2254,6 @@
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 if (op.equals("focus")) {
return runTaskFocus(pw);
} else {
@@ -2308,58 +2306,6 @@
}
}
- 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 {
@@ -2422,133 +2368,6 @@
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 runTaskFocus(PrintWriter pw) throws RemoteException {
final int taskId = Integer.parseInt(getNextArgRequired());
pw.println("Setting focus to task " + taskId);
@@ -2880,8 +2699,8 @@
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(" info <WINDOWING_MODE> <ACTIVITY_TYPE>");
+ pw.println(" Display the information about activity stack in <WINDOWING_MODE> and <ACTIVITY_TYPE>.");
pw.println(" remove <STACK_ID>");
pw.println(" Remove stack <STACK_ID>.");
pw.println(" task [COMMAND] [...]: sub-commands for operating on activity tasks.");
@@ -2899,14 +2718,6 @@
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(" update-appinfo <USER_ID> <PACKAGE_NAME> [<PACKAGE_NAME>...]");
pw.println(" Update the ApplicationInfo objects of the listed packages for <USER_ID>");
pw.println(" without restarting any processes.");
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 0c8321d..fdcb8c6 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -2,12 +2,9 @@
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
-import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -32,13 +29,10 @@
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
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.ActivityStack.STACK_INVISIBLE;
-import android.app.ActivityManager.StackId;
import android.content.Context;
import android.metrics.LogMaker;
import android.os.SystemClock;
-import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 2241ed6..7b0b942 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -17,7 +17,6 @@
package com.android.server.am;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-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.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
@@ -103,7 +102,6 @@
import static com.android.server.am.ActivityStack.LAUNCH_TICK;
import static com.android.server.am.ActivityStack.LAUNCH_TICK_MSG;
import static com.android.server.am.ActivityStack.PAUSE_TIMEOUT_MSG;
-import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
import static com.android.server.am.ActivityStack.STOP_TIMEOUT_MSG;
import static com.android.server.am.EventLogTags.AM_ACTIVITY_FULLY_DRAWN_TIME;
import static com.android.server.am.EventLogTags.AM_ACTIVITY_LAUNCH_TIME;
@@ -1069,6 +1067,11 @@
return getStack() != null ? getStack().mStackId : INVALID_STACK_ID;
}
+ ActivityDisplay getDisplay() {
+ final ActivityStack stack = getStack();
+ return stack != null ? stack.getDisplay() : null;
+ }
+
boolean changeWindowTranslucency(boolean toOpaque) {
if (fullscreen == toOpaque) {
return false;
@@ -1134,10 +1137,12 @@
* @return whether this activity supports split-screen multi-window and can be put in the docked
* stack.
*/
- boolean supportsSplitScreen() {
+ @Override
+ public boolean supportsSplitScreenWindowingMode() {
// An activity can not be docked even if it is considered resizeable because it only
// supports picture-in-picture mode but has a non-resizeable resizeMode
- return service.mSupportsSplitScreenMultiWindow && supportsResizeableMultiWindow();
+ return super.supportsSplitScreenWindowingMode()
+ && service.mSupportsSplitScreenMultiWindow && supportsResizeableMultiWindow();
}
/**
@@ -1198,7 +1203,8 @@
boolean isKeyguardLocked = service.isKeyguardLocked();
boolean isCurrentAppLocked = service.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
- boolean hasPinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID) != null;
+ final ActivityDisplay display = getDisplay();
+ boolean hasPinnedStack = display != null && display.hasPinnedStack();
// Don't return early if !isNotLocked, since we want to throw an exception if the activity
// is in an incorrect state
boolean isNotLockedOrOnKeyguard = !isKeyguardLocked && !isCurrentAppLocked;
@@ -1544,8 +1550,9 @@
if (service.mSupportsLeanbackOnly && isVisible && isActivityTypeRecents()) {
// 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());
+ final ActivityDisplay display = getDisplay();
+ boolean hasSplitScreenStack = display != null && display.hasSplitScreenStack();
+ isVisible = hasSplitScreenStack || mStackSupervisor.isFocusedStack(getStack());
}
return isVisible;
@@ -1948,7 +1955,7 @@
return (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0
|| (mStackSupervisor.isCurrentProfileLocked(userId)
- && service.mUserController.isUserRunningLocked(userId, 0 /* flags */));
+ && service.mUserController.isUserRunning(userId, 0 /* flags */));
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 361d91a..7eb6eda 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -16,20 +16,19 @@
package com.android.server.am;
-import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
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.FULLSCREEN_WORKSPACE_STACK_ID;
-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.app.ActivityManager.StackId.getActivityTypeForStackId;
-import static android.app.ActivityManager.StackId.getWindowingModeForStackId;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
@@ -77,7 +76,6 @@
import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
-import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
@@ -112,7 +110,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
-import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
@@ -243,11 +240,6 @@
DESTROYED
}
- // Stack is not considered visible.
- static final int STACK_INVISIBLE = 0;
- // Stack is considered visible
- static final int STACK_VISIBLE = 1;
-
@VisibleForTesting
/* The various modes for the method {@link #removeTask}. */
// Task is being completely removed from all stacks in the system.
@@ -461,17 +453,18 @@
}
ActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
- boolean onTop) {
+ int windowingMode, int activityType, boolean onTop) {
mStackSupervisor = supervisor;
mService = supervisor.mService;
mHandler = new ActivityStackHandler(mService.mHandler.getLooper());
mWindowManager = mService.mWindowManager;
mStackId = stackId;
- mCurrentUser = mService.mUserController.getCurrentUserIdLocked();
+ mCurrentUser = mService.mUserController.getCurrentUserId();
mTaskPositioner = mStackId == FREEFORM_WORKSPACE_STACK_ID
? new LaunchingTaskPositioner() : null;
mTmpRect2.setEmpty();
- updateOverrideConfiguration();
+ setWindowingMode(windowingMode);
+ setActivityType(activityType);
mWindowContainerController = createStackWindowController(display.mDisplayId, onTop,
mTmpRect2);
postAddToDisplay(display, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
@@ -485,20 +478,6 @@
return mWindowContainerController;
}
- // TODO: Not needed once we are no longer using stack ids as the override config. can be passed
- // in.
- private void updateOverrideConfiguration() {
- final int windowingMode = getWindowingModeForStackId(
- mStackId, mStackSupervisor.getStack(DOCKED_STACK_ID) != null);
- if (windowingMode != WINDOWING_MODE_UNDEFINED) {
- setWindowingMode(windowingMode);
- }
- final int activityType = getActivityTypeForStackId(mStackId);
- if (activityType != ACTIVITY_TYPE_UNDEFINED) {
- setActivityType(activityType);
- }
- }
-
/** Adds the stack to specified display and calls WindowManager to do the same. */
void reparent(ActivityDisplay activityDisplay, boolean onTop) {
removeFromDisplay();
@@ -518,8 +497,7 @@
* @param activityDisplay New display to which this stack was attached.
* @param bounds Updated bounds.
*/
- private void postAddToDisplay(ActivityDisplay activityDisplay,
- Rect bounds, boolean onTop) {
+ private void postAddToDisplay(ActivityDisplay activityDisplay, Rect bounds, boolean onTop) {
mDisplayId = activityDisplay.mDisplayId;
mBounds = bounds != null ? new Rect(bounds) : null;
mFullscreen = mBounds == null;
@@ -571,12 +549,8 @@
return mStackSupervisor.getActivityDisplay(mDisplayId);
}
- void getDisplaySize(Point out) {
- getDisplay().mDisplay.getSize(out);
- }
-
/**
- * @see ActivityStack.getStackDockedModeBounds(Rect, Rect, Rect, boolean)
+ * @see #getStackDockedModeBounds(Rect, Rect, Rect, boolean)
*/
void getStackDockedModeBounds(Rect currentTempTaskBounds, Rect outStackBounds,
Rect outTempTaskBounds, boolean ignoreVisibility) {
@@ -840,7 +814,7 @@
}
final boolean isHomeOrRecentsStack() {
- return StackId.isHomeOrRecentsStack(mStackId);
+ return isActivityTypeHome() || isActivityTypeRecents();
}
final boolean isDockedStack() {
@@ -1068,7 +1042,6 @@
"Launch completed; removing icicle of " + r.icicle);
}
-
private void startLaunchTraces(String packageName) {
if (mFullyDrawnStartTime != 0) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0);
@@ -1483,7 +1456,7 @@
// focus). Also if there is an active pinned stack - we always want to notify it about
// task stack changes, because its positioning may depend on it.
if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause
- || mService.mStackSupervisor.getStack(PINNED_STACK_ID) != null) {
+ || getDisplay().hasPinnedStack()) {
mService.mTaskChangeNotificationController.notifyTaskStackChanged();
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
}
@@ -1558,9 +1531,11 @@
return false;
}
+ final ActivityStack stackBehind = mStackSupervisor.getStack(stackBehindId);
+ final boolean stackBehindHomeOrRecent = stackBehind != null
+ && stackBehind.isHomeOrRecentsStack();
if (!isHomeOrRecentsStack() && r.frontOfTask && task.isOverHomeStack()
- && !StackId.isHomeOrRecentsStack(stackBehindId)
- && !isActivityTypeAssistant()) {
+ && !stackBehindHomeOrRecent && !isActivityTypeAssistant()) {
// Stack isn't translucent if it's top activity should have the home stack
// behind it and the stack currently behind it isn't the home or recents stack
// or the assistant stack.
@@ -1591,7 +1566,8 @@
return true;
}
- final ArrayList<ActivityStack> displayStacks = getDisplay().mStacks;
+ final ActivityDisplay display = getDisplay();
+ final ArrayList<ActivityStack> displayStacks = display.mStacks;
final int stackIndex = displayStacks.indexOf(this);
if (stackIndex == displayStacks.size() - 1) {
@@ -1603,8 +1579,10 @@
// Check position and visibility of this stack relative to the front stack on its display.
final ActivityStack topStack = getTopStackOnDisplay();
final int topStackId = topStack.mStackId;
+ final int windowingMode = getWindowingMode();
+ final int activityType = getActivityType();
- if (mStackId == DOCKED_STACK_ID) {
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
// If the assistant stack is focused and translucent, then the docked stack is always
// visible
if (topStack.isActivityTypeAssistant()) {
@@ -1616,9 +1594,10 @@
// Set home stack to invisible when it is below but not immediately below the docked stack
// A case would be if recents stack exists but has no tasks and is below the docked stack
// and home stack is below recents
- if (mStackId == HOME_STACK_ID) {
- int dockedStackIndex = displayStacks.indexOf
- (mStackSupervisor.getStack(DOCKED_STACK_ID));
+ if (activityType == ACTIVITY_TYPE_HOME) {
+ final ActivityStack splitScreenStack = display.getStack(
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
+ int dockedStackIndex = displayStacks.indexOf(splitScreenStack);
if (dockedStackIndex > stackIndex && stackIndex != dockedStackIndex - 1) {
return false;
}
@@ -1630,26 +1609,35 @@
displayStacks.get(stackBehindTopIndex).topRunningActivityLocked() == null) {
stackBehindTopIndex--;
}
- final int stackBehindTopId = (stackBehindTopIndex >= 0)
- ? displayStacks.get(stackBehindTopIndex).mStackId : INVALID_STACK_ID;
+ final ActivityStack stackBehindTop = (stackBehindTopIndex >= 0)
+ ? displayStacks.get(stackBehindTopIndex) : null;
+ int stackBehindTopId = INVALID_STACK_ID;
+ int stackBehindTopWindowingMode = WINDOWING_MODE_UNDEFINED;
+ int stackBehindTopActivityType = ACTIVITY_TYPE_UNDEFINED;
+ if (stackBehindTop != null) {
+ stackBehindTopId = stackBehindTop.mStackId;
+ stackBehindTopWindowingMode = stackBehindTop.getWindowingMode();
+ stackBehindTopActivityType = stackBehindTop.getActivityType();
+ }
+
final boolean alwaysOnTop = topStack.getWindowConfiguration().isAlwaysOnTop();
- if (topStackId == DOCKED_STACK_ID || alwaysOnTop) {
+ if (topStack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY || alwaysOnTop) {
if (stackIndex == stackBehindTopIndex) {
// Stacks directly behind the docked or pinned stack are always visible.
return true;
} else if (alwaysOnTop && stackIndex == stackBehindTopIndex - 1) {
// Otherwise, this stack can also be visible if it is directly behind a docked stack
// or translucent assistant stack behind an always-on-top top-most stack
- if (stackBehindTopId == DOCKED_STACK_ID) {
+ if (stackBehindTopWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
return true;
- } else if (stackBehindTopId == ASSISTANT_STACK_ID) {
+ } else if (stackBehindTopActivityType == ACTIVITY_TYPE_ASSISTANT) {
return displayStacks.get(stackBehindTopIndex).isStackTranslucent(
starting, mStackId);
}
}
}
- if (StackId.isBackdropToTranslucentActivity(topStackId)
+ if (topStack.isBackdropToTranslucentActivity()
&& topStack.isStackTranslucent(starting, stackBehindTopId)) {
// Stacks behind the fullscreen or assistant stack with a translucent activity are
// always visible so they can act as a backdrop to the translucent activity.
@@ -1658,8 +1646,8 @@
return true;
}
if (stackBehindTopIndex >= 0) {
- if ((stackBehindTopId == DOCKED_STACK_ID
- || stackBehindTopId == PINNED_STACK_ID)
+ if ((stackBehindTopWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || stackBehindTopWindowingMode == WINDOWING_MODE_PINNED)
&& stackIndex == (stackBehindTopIndex - 1)) {
// The stack behind the docked or pinned stack is also visible so we can have a
// complete backdrop to the translucent activity when the docked stack is up.
@@ -1668,7 +1656,8 @@
}
}
- if (StackId.isStaticStack(mStackId)) {
+ if (StackId.isStaticStack(mStackId)
+ || isHomeOrRecentsStack() || isActivityTypeAssistant()) {
// Visibility of any static stack should have been determined by the conditions above.
return false;
}
@@ -1680,7 +1669,7 @@
continue;
}
- if (!StackId.isDynamicStacksVisibleBehindAllowed(stack.mStackId)) {
+ if (!stack.isDynamicStacksVisibleBehindAllowed()) {
// These stacks can't have any dynamic stacks visible behind them.
return false;
}
@@ -1693,6 +1682,19 @@
return true;
}
+ private boolean isBackdropToTranslucentActivity() {
+ if (isActivityTypeAssistant()) {
+ return true;
+ }
+ final int windowingMode = getWindowingMode();
+ return windowingMode == WINDOWING_MODE_FULLSCREEN
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+ }
+
+ private boolean isDynamicStacksVisibleBehindAllowed() {
+ return isActivityTypeAssistant() || getWindowingMode() == WINDOWING_MODE_PINNED;
+ }
+
final int rankTaskLayers(int baseLayer) {
int layer = 0;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -1727,8 +1729,8 @@
// If the top activity is not fullscreen, then we need to
// make sure any activities under it are now visible.
boolean aboveTop = top != null;
- final boolean stackVisible = shouldBeVisible(starting);
- boolean behindFullscreenActivity = !stackVisible;
+ final boolean stackShouldBeVisible = shouldBeVisible(starting);
+ boolean behindFullscreenActivity = !stackShouldBeVisible;
boolean resumeNextActivity = mStackSupervisor.isFocusedStack(this)
&& (isInStackLocked(starting) == null);
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -1754,7 +1756,7 @@
final boolean reallyVisible = checkKeyguardVisibility(r,
visibleIgnoringKeyguard, isTop);
if (visibleIgnoringKeyguard) {
- behindFullscreenActivity = updateBehindFullscreen(!stackVisible,
+ behindFullscreenActivity = updateBehindFullscreen(!stackShouldBeVisible,
behindFullscreenActivity, task, r);
}
if (reallyVisible) {
@@ -1792,7 +1794,7 @@
} else {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r
+ " finishing=" + r.finishing + " state=" + r.state
- + " stackVisible=" + stackVisible
+ + " stackShouldBeVisible=" + stackShouldBeVisible
+ " behindFullscreenActivity=" + behindFullscreenActivity
+ " mLaunchTaskBehind=" + r.mLaunchTaskBehind);
makeInvisible(r);
@@ -1802,10 +1804,10 @@
// The visibility of tasks and the activities they contain in freeform stack are
// determined individually unlike other stacks where the visibility or fullscreen
// status of an activity in a previous task affects other.
- behindFullscreenActivity = !stackVisible;
- } else if (mStackId == HOME_STACK_ID) {
+ behindFullscreenActivity = !stackShouldBeVisible;
+ } else if (isActivityTypeHome()) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + task
- + " stackVisible=" + stackVisible
+ + " stackShouldBeVisible=" + stackShouldBeVisible
+ " behindFullscreenActivity=" + behindFullscreenActivity);
// No other task in the home stack should be visible behind the home activity.
// Home activities is usually a translucent activity with the wallpaper behind
@@ -2445,128 +2447,139 @@
|| (lastStack.mLastPausedActivity != null
&& !lastStack.mLastPausedActivity.fullscreen));
- // This activity is now becoming visible.
- if (!next.visible || next.stopped || lastActivityTranslucent) {
- next.setVisibility(true);
- }
-
- // schedule launch ticks to collect information about slow apps.
- next.startLaunchTickingLocked();
-
- ActivityRecord lastResumedActivity =
- lastStack == null ? null :lastStack.mResumedActivity;
- ActivityState lastState = next.state;
-
- mService.updateCpuStats();
-
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next + " (in existing)");
-
- setResumedActivityLocked(next, "resumeTopActivityInnerLocked");
-
- mService.updateLruProcessLocked(next.app, true, null);
- updateLRUListLocked(next);
- mService.updateOomAdjLocked();
-
- // Have the window manager re-evaluate the orientation of
- // the screen based on the new activity order.
- boolean notUpdated = true;
- if (mStackSupervisor.isFocusedStack(this)) {
-
- // We have special rotation behavior when Keyguard is locked. Make sure all activity
- // visibilities are set correctly as well as the transition is updated if needed to
- // get the correct rotation behavior.
- // TODO: Remove this once visibilities are set correctly immediately when starting
- // an activity.
- if (mStackSupervisor.mKeyguardController.isKeyguardLocked()) {
- mStackSupervisor.ensureActivitiesVisibleLocked(null /* starting */,
- 0 /* configChanges */, false /* preserveWindows */);
- }
- final Configuration config = mWindowManager.updateOrientationFromAppTokens(
- mStackSupervisor.getDisplayOverrideConfiguration(mDisplayId),
- next.mayFreezeScreenLocked(next.app) ? next.appToken : null, mDisplayId);
- if (config != null) {
- next.frozenBeforeDestroy = true;
- }
- notUpdated = !mService.updateDisplayOverrideConfigurationLocked(config, next,
- false /* deferResume */, mDisplayId);
- }
-
- if (notUpdated) {
- // The configuration update wasn't able to keep the existing
- // instance of the activity, and instead started a new one.
- // We should be all done, but let's just make sure our activity
- // is still at the top and schedule another run if something
- // weird happened.
- ActivityRecord nextNext = topRunningActivityLocked();
- if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES,
- "Activity config changed during resume: " + next
- + ", new next: " + nextNext);
- if (nextNext != next) {
- // Do over!
- mStackSupervisor.scheduleResumeTopActivities();
- }
- if (!next.visible || next.stopped) {
+ // The contained logic must be synchronized, since we are both changing the visibility
+ // and updating the {@link Configuration}. {@link ActivityRecord#setVisibility} will
+ // ultimately cause the client code to schedule a layout. Since layouts retrieve the
+ // current {@link Configuration}, we must ensure that the below code updates it before
+ // the layout can occur.
+ synchronized(mWindowManager.getWindowManagerLock()) {
+ // This activity is now becoming visible.
+ if (!next.visible || next.stopped || lastActivityTranslucent) {
next.setVisibility(true);
}
- next.completeResumeLocked();
- if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
- return true;
- }
- try {
- // Deliver all pending results.
- ArrayList<ResultInfo> a = next.results;
- if (a != null) {
- final int N = a.size();
- if (!next.finishing && N > 0) {
- if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
- "Delivering results to " + next + ": " + a);
- next.app.thread.scheduleSendResult(next.appToken, a);
+ // schedule launch ticks to collect information about slow apps.
+ next.startLaunchTickingLocked();
+
+ ActivityRecord lastResumedActivity =
+ lastStack == null ? null :lastStack.mResumedActivity;
+ ActivityState lastState = next.state;
+
+ mService.updateCpuStats();
+
+ if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next
+ + " (in existing)");
+
+ setResumedActivityLocked(next, "resumeTopActivityInnerLocked");
+
+ mService.updateLruProcessLocked(next.app, true, null);
+ updateLRUListLocked(next);
+ mService.updateOomAdjLocked();
+
+ // Have the window manager re-evaluate the orientation of
+ // the screen based on the new activity order.
+ boolean notUpdated = true;
+
+ if (mStackSupervisor.isFocusedStack(this)) {
+
+ // We have special rotation behavior when Keyguard is locked. Make sure all
+ // activity visibilities are set correctly as well as the transition is updated
+ // if needed to get the correct rotation behavior.
+ // TODO: Remove this once visibilities are set correctly immediately when
+ // starting an activity.
+ if (mStackSupervisor.mKeyguardController.isKeyguardLocked()) {
+ mStackSupervisor.ensureActivitiesVisibleLocked(null /* starting */,
+ 0 /* configChanges */, false /* preserveWindows */);
}
+ final Configuration config = mWindowManager.updateOrientationFromAppTokens(
+ mStackSupervisor.getDisplayOverrideConfiguration(mDisplayId),
+ next.mayFreezeScreenLocked(next.app) ? next.appToken : null,
+ mDisplayId);
+ if (config != null) {
+ next.frozenBeforeDestroy = true;
+ }
+ notUpdated = !mService.updateDisplayOverrideConfigurationLocked(config, next,
+ false /* deferResume */, mDisplayId);
}
- if (next.newIntents != null) {
- next.app.thread.scheduleNewIntent(
- next.newIntents, next.appToken, false /* andPause */);
+ if (notUpdated) {
+ // The configuration update wasn't able to keep the existing
+ // instance of the activity, and instead started a new one.
+ // We should be all done, but let's just make sure our activity
+ // is still at the top and schedule another run if something
+ // weird happened.
+ ActivityRecord nextNext = topRunningActivityLocked();
+ if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES,
+ "Activity config changed during resume: " + next
+ + ", new next: " + nextNext);
+ if (nextNext != next) {
+ // Do over!
+ mStackSupervisor.scheduleResumeTopActivities();
+ }
+ if (!next.visible || next.stopped) {
+ next.setVisibility(true);
+ }
+ next.completeResumeLocked();
+ if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
+ return true;
}
- // Well the app will no longer be stopped.
- // Clear app token stopped state in window manager if needed.
- next.notifyAppResumed(next.stopped);
+ try {
+ // Deliver all pending results.
+ ArrayList<ResultInfo> a = next.results;
+ if (a != null) {
+ final int N = a.size();
+ if (!next.finishing && N > 0) {
+ if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
+ "Delivering results to " + next + ": " + a);
+ next.app.thread.scheduleSendResult(next.appToken, a);
+ }
+ }
- EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
- System.identityHashCode(next), next.getTask().taskId,
- next.shortComponentName);
+ if (next.newIntents != null) {
+ next.app.thread.scheduleNewIntent(
+ next.newIntents, next.appToken, false /* andPause */);
+ }
- next.sleeping = false;
- mService.showUnsupportedZoomDialogIfNeededLocked(next);
- mService.showAskCompatModeDialogLocked(next);
- next.app.pendingUiClean = true;
- next.app.forceProcessStateUpTo(mService.mTopProcessState);
- next.clearOptionsLocked();
- next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
- mService.isNextTransitionForward(), resumeAnimOptions);
+ // Well the app will no longer be stopped.
+ // Clear app token stopped state in window manager if needed.
+ next.notifyAppResumed(next.stopped);
- if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed " + next);
- } catch (Exception e) {
- // Whoops, need to restart this activity!
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to "
- + lastState + ": " + next);
- next.state = lastState;
- if (lastStack != null) {
- lastStack.mResumedActivity = lastResumedActivity;
+ EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
+ System.identityHashCode(next), next.getTask().taskId,
+ next.shortComponentName);
+
+ next.sleeping = false;
+ mService.showUnsupportedZoomDialogIfNeededLocked(next);
+ mService.showAskCompatModeDialogLocked(next);
+ next.app.pendingUiClean = true;
+ next.app.forceProcessStateUpTo(mService.mTopProcessState);
+ next.clearOptionsLocked();
+ next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
+ mService.isNextTransitionForward(), resumeAnimOptions);
+
+ if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
+ + next);
+ } catch (Exception e) {
+ // Whoops, need to restart this activity!
+ if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to "
+ + lastState + ": " + next);
+ next.state = lastState;
+ if (lastStack != null) {
+ lastStack.mResumedActivity = lastResumedActivity;
+ }
+ Slog.i(TAG, "Restarting because process died: " + next);
+ if (!next.hasBeenLaunched) {
+ next.hasBeenLaunched = true;
+ } else if (SHOW_APP_STARTING_PREVIEW && lastStack != null &&
+ mStackSupervisor.isFrontStackOnDisplay(lastStack)) {
+ next.showStartingWindow(null /* prev */, false /* newTask */,
+ false /* taskSwitch */);
+ }
+ mStackSupervisor.startSpecificActivityLocked(next, true, false);
+ if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
+ return true;
}
- Slog.i(TAG, "Restarting because process died: " + next);
- if (!next.hasBeenLaunched) {
- next.hasBeenLaunched = true;
- } else if (SHOW_APP_STARTING_PREVIEW && lastStack != null &&
- mStackSupervisor.isFrontStackOnDisplay(lastStack)) {
- next.showStartingWindow(null /* prev */, false /* newTask */,
- false /* taskSwitch */);
- }
- mStackSupervisor.startSpecificActivityLocked(next, true, false);
- if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
- return true;
}
// From this point on, if something goes wrong there is no way
@@ -2891,9 +2904,9 @@
// Ensure that we do not trigger entering PiP an activity on the pinned stack
return false;
}
- final int targetStackId = toFrontTask != null ? toFrontTask.getStackId()
- : toFrontActivity.getStackId();
- if (targetStackId == ASSISTANT_STACK_ID) {
+ final ActivityStack targetStack = toFrontTask != null
+ ? toFrontTask.getStack() : toFrontActivity.getStack();
+ if (targetStack != null && targetStack.isActivityTypeAssistant()) {
// Ensure the task/activity being brought forward is not the assistant
return false;
}
@@ -4503,7 +4516,7 @@
Slog.i(TAG, "moveTaskToBack: " + tr);
// If the task is locked, then show the lock task toast
- if (!mService.mLockTaskController.checkLockedTask(tr)) {
+ if (mService.mLockTaskController.checkLockedTask(tr)) {
return false;
}
@@ -4884,8 +4897,9 @@
}
ci.numActivities = numActivities;
ci.numRunning = numRunning;
- ci.supportsSplitScreenMultiWindow = task.supportsSplitScreen();
+ ci.supportsSplitScreenMultiWindow = task.supportsSplitScreenWindowingMode();
ci.resizeMode = task.mResizeMode;
+ ci.configuration = task.getConfiguration();
list.add(ci);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index bf0c3a4..d2cc557 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -21,21 +21,14 @@
import static android.Manifest.permission.START_ANY_ACTIVITY;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
-import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
-import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
-import static android.app.ActivityManager.StackId.getStackIdForActivityType;
-import static android.app.ActivityManager.StackId.getStackIdForWindowingMode;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -87,8 +80,6 @@
import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
-import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
-import static com.android.server.am.ActivityStack.STACK_VISIBLE;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
@@ -100,8 +91,6 @@
import static com.android.server.am.proto.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER;
import static com.android.server.am.proto.ActivityStackSupervisorProto.RESUMED_ACTIVITY;
import static com.android.server.am.proto.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
-import static com.android.server.am.proto.ActivityDisplayProto.STACKS;
-import static com.android.server.am.proto.ActivityDisplayProto.ID;
import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static java.lang.Integer.MAX_VALUE;
@@ -121,6 +110,7 @@
import android.app.ProfilerInfo;
import android.app.ResultInfo;
import android.app.WaitResult;
+import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -172,7 +162,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.am.ActivityStack.ActivityState;
-import com.android.server.am.proto.ActivityDisplayProto;
import com.android.server.wm.ConfigurationContainer;
import com.android.server.wm.PinnedStackWindowController;
import com.android.server.wm.WindowManagerService;
@@ -619,8 +608,8 @@
calculateDefaultMinimalSizeOfResizeableTasks(activityDisplay);
}
- mHomeStack = mFocusedStack = mLastFocusedStack =
- getStack(HOME_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
+ mHomeStack = mFocusedStack = mLastFocusedStack = getDefaultDisplay().getOrCreateStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
}
@@ -676,7 +665,8 @@
}
void moveRecentsStackToFront(String reason) {
- final ActivityStack recentsStack = getStack(RECENTS_STACK_ID);
+ final ActivityStack recentsStack = getDefaultDisplay().getStack(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS);
if (recentsStack != null) {
recentsStack.moveToFront(reason);
}
@@ -1163,8 +1153,7 @@
void getTasksLocked(int maxNum, List<RunningTaskInfo> list, int callingUid, boolean allowed) {
// Gather all of the running tasks for each stack into runningTaskLists.
- ArrayList<ArrayList<RunningTaskInfo>> runningTaskLists =
- new ArrayList<ArrayList<RunningTaskInfo>>();
+ ArrayList<ArrayList<RunningTaskInfo>> runningTaskLists = new ArrayList<>();
final int numDisplays = mActivityDisplays.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
@@ -1966,7 +1955,7 @@
*/
void updateUserStackLocked(int userId, ActivityStack stack) {
if (userId != mCurrentUser) {
- mUserStackInFront.put(userId, stack != null ? stack.getStackId() : HOME_STACK_ID);
+ mUserStackInFront.put(userId, stack != null ? stack.getStackId() : mHomeStack.mStackId);
}
}
@@ -2107,19 +2096,19 @@
final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds());
task.updateOverrideConfiguration(bounds);
- int stackId = getLaunchStackId(null, options, task);
+ ActivityStack stack = getLaunchStack(null, options, task, ON_TOP);
- if (stackId != currentStack.mStackId) {
- task.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE,
- DEFER_RESUME, "findTaskToMoveToFrontLocked");
- stackId = currentStack.mStackId;
+ if (stack != currentStack) {
+ task.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, DEFER_RESUME,
+ "findTaskToMoveToFrontLocked");
+ stack = currentStack;
// moveTaskToStackUncheckedLocked() should already placed the task on top,
// still need moveTaskToFrontLocked() below for any transition settings.
}
- if (StackId.resizeStackWithLaunchBounds(stackId)) {
- resizeStackLocked(stackId, bounds,
- null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
- !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, !DEFER_RESUME);
+ if (StackId.resizeStackWithLaunchBounds(stack.mStackId)) {
+ resizeStackLocked(stack.mStackId, bounds, null /* tempTaskBounds */,
+ null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS,
+ true /* allowResizeInDockedMode */, !DEFER_RESUME);
} else {
// 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
@@ -2160,25 +2149,57 @@
return null;
}
- protected <T extends ActivityStack> T getStack(int stackId, boolean createStaticStackIfNeeded,
- boolean createOnTop) {
- final ActivityStack stack = getStack(stackId);
- if (stack != null) {
- return (T) stack;
+ /** @see ActivityDisplay#getStack(int, int) */
+ private <T extends ActivityStack> T getStack(int windowingMode, int activityType) {
+ for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
+ final T stack = mActivityDisplays.valueAt(i).getStack(windowingMode, activityType);
+ if (stack != null) {
+ return stack;
+ }
}
- if (!createStaticStackIfNeeded || !StackId.isStaticStack(stackId)) {
- return null;
+ return null;
+ }
+
+ /**
+ * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
+ * @param windowingMode The windowing mode we are checking support for.
+ * @param supportsMultiWindow If we should consider support for multi-window mode in general.
+ * @param supportsSplitScreen If we should consider support for split-screen multi-window.
+ * @param supportsFreeform If we should consider support for freeform multi-window.
+ * @param supportsPip If we should consider support for picture-in-picture mutli-window.
+ * @param activityType The activity type under consideration.
+ * @return true if the windowing mode is supported.
+ */
+ boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
+ boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
+ int activityType) {
+
+ if (windowingMode == WINDOWING_MODE_UNDEFINED
+ || windowingMode == WINDOWING_MODE_FULLSCREEN) {
+ return true;
}
- if (stackId == DOCKED_STACK_ID) {
- // Make sure recents stack exist when creating a dock stack as it normally need to be on
- // the other side of the docked stack and we make visibility decisions based on that.
- getStack(RECENTS_STACK_ID, CREATE_IF_NEEDED, createOnTop);
+ if (!supportsMultiWindow) {
+ return false;
}
- return (T) createStackOnDisplay(stackId, DEFAULT_DISPLAY, createOnTop);
+
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
+ return supportsSplitScreen && WindowConfiguration.supportSplitScreenWindowingMode(
+ windowingMode, activityType);
+ }
+
+ if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
+ return false;
+ }
+
+ if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
+ return false;
+ }
+ return true;
}
private int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
- @Nullable TaskRecord task) {
+ @Nullable TaskRecord task, int activityType) {
// First preference if the windowing mode in the activity options if set.
int windowingMode = (options != null)
@@ -2196,47 +2217,47 @@
}
// Make sure the windowing mode we are trying to use makes sense for what is supported.
- if (!mService.mSupportsMultiWindow && windowingMode != WINDOWING_MODE_FULLSCREEN) {
- windowingMode = WINDOWING_MODE_FULLSCREEN;
+ boolean supportsMultiWindow = mService.mSupportsMultiWindow;
+ boolean supportsSplitScreen = mService.mSupportsSplitScreenMultiWindow;
+ boolean supportsFreeform = mService.mSupportsFreeformWindowManagement;
+ boolean supportsPip = mService.mSupportsPictureInPicture;
+ if (supportsMultiWindow) {
+ if (task != null) {
+ supportsMultiWindow = task.isResizeable();
+ supportsSplitScreen = task.supportsSplitScreenWindowingMode();
+ // TODO: Do we need to check for freeform and Pip support here?
+ } else if (r != null) {
+ supportsMultiWindow = r.isResizeable();
+ supportsSplitScreen = r.supportsSplitScreenWindowingMode();
+ supportsFreeform = r.supportsFreeform();
+ supportsPip = r.supportsPictureInPicture();
+ }
}
- if (!mService.mSupportsSplitScreenMultiWindow
- && (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)) {
- windowingMode = WINDOWING_MODE_FULLSCREEN;
+ if (isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
+ supportsFreeform, supportsPip, activityType)) {
+ return windowingMode;
}
-
- if (windowingMode == WINDOWING_MODE_FREEFORM
- && !mService.mSupportsFreeformWindowManagement) {
- windowingMode = WINDOWING_MODE_FULLSCREEN;
- }
-
- return windowingMode;
+ return WINDOWING_MODE_FULLSCREEN;
}
- private int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+ int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
@Nullable TaskRecord task) {
- // First preference if the activity type in the activity options if set.
- int activityType = (options != null)
- ? options.getLaunchActivityType() : ACTIVITY_TYPE_UNDEFINED;
-
+ // Preference is given to the activity type for the activity then the task since the type
+ // once set shouldn't change.
+ int activityType = r != null ? r.getActivityType() : ACTIVITY_TYPE_UNDEFINED;
+ if (activityType == ACTIVITY_TYPE_UNDEFINED && task != null) {
+ activityType = task.getActivityType();
+ }
if (activityType != ACTIVITY_TYPE_UNDEFINED) {
return activityType;
}
-
- // If activity type is unset, then next preference is the task, then the activity record.
- if (task != null) {
- activityType = task.getActivityType();
- }
- if (activityType == ACTIVITY_TYPE_UNDEFINED && r != null) {
- activityType = r.getActivityType();
- }
- return activityType;
+ return options != null ? options.getLaunchActivityType() : ACTIVITY_TYPE_UNDEFINED;
}
- int getLaunchStackId(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
- @Nullable TaskRecord candidateTask) {
- return getLaunchStackId(r, options, candidateTask, INVALID_DISPLAY);
+ <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r,
+ @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop) {
+ return getLaunchStack(r, options, candidateTask, onTop, INVALID_DISPLAY);
}
/**
@@ -2248,8 +2269,9 @@
*
* @return The stack to use for the launch or INVALID_STACK_ID.
*/
- int getLaunchStackId(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
- @Nullable TaskRecord candidateTask, int candidateDisplayId) {
+ <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r,
+ @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop,
+ int candidateDisplayId) {
int taskId = INVALID_TASK_ID;
int displayId = INVALID_DISPLAY;
//Rect bounds = null;
@@ -2271,13 +2293,13 @@
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options);
options.setLaunchTaskId(taskId);
if (task != null) {
- return task.getStack().mStackId;
+ return task.getStack();
}
}
- final int windowingMode = resolveWindowingMode(r, options, candidateTask);
final int activityType = resolveActivityType(r, options, candidateTask);
- ActivityStack stack = null;
+ int windowingMode = resolveWindowingMode(r, options, candidateTask, activityType);
+ T stack = null;
// Next preference for stack goes to the display Id set in the activity options or the
// candidate display.
@@ -2287,18 +2309,17 @@
if (displayId != INVALID_DISPLAY) {
if (r != null) {
// TODO: This should also take in the windowing mode and activity type into account.
- stack = getValidLaunchStackOnDisplay(displayId, r);
+ stack = (T) getValidLaunchStackOnDisplay(displayId, r);
if (stack != null) {
- return stack.mStackId;
+ return stack;
}
}
final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId);
if (display != null) {
for (int i = display.mStacks.size() - 1; i >= 0; --i) {
- stack = display.mStacks.get(i);
- if (stack.getWindowingMode() == windowingMode
- && stack.getActivityType() == activityType) {
- return stack.mStackId;
+ stack = (T) display.mStacks.get(i);
+ if (stack.isCompatible(windowingMode, activityType)) {
+ return stack;
}
}
// TODO: We should create the stack we want on the display at this point.
@@ -2307,6 +2328,8 @@
// Give preference to the stack and display of the input task and activity if they match the
// mode we want to launch into.
+ stack = null;
+ ActivityDisplay display = null;
if (candidateTask != null) {
stack = candidateTask.getStack();
}
@@ -2314,40 +2337,33 @@
stack = r.getStack();
}
if (stack != null) {
- if (stack.getWindowingMode() == windowingMode
- && stack.getActivityType() == activityType) {
- return stack.mStackId;
+ if (stack.isCompatible(windowingMode, activityType)) {
+ return stack;
}
- ActivityDisplay display = stack.getDisplay();
-
- if (display != null) {
- for (int i = display.mStacks.size() - 1; i >= 0; --i) {
- stack = display.mStacks.get(i);
- if (stack.getWindowingMode() == windowingMode
- && stack.getActivityType() == activityType) {
- return stack.mStackId;
- }
- }
- }
+ display = stack.getDisplay();
}
- // Give preference to the type of activity we are trying to launch followed by the windowing
- // mode.
- int stackId = getStackIdForActivityType(activityType);
- if (stackId != INVALID_STACK_ID) {
- return stackId;
+ if (display == null
+ // TODO: Can be removed once we figure-out how non-standard types should launch
+ // outside the default display.
+ || (activityType != ACTIVITY_TYPE_STANDARD
+ && activityType != ACTIVITY_TYPE_UNDEFINED)) {
+ display = getDefaultDisplay();
}
- stackId = getStackIdForWindowingMode(windowingMode);
- if (stackId != INVALID_STACK_ID) {
- return stackId;
+
+ stack = display.getOrCreateStack(windowingMode, activityType, onTop);
+ if (stack != null) {
+ return stack;
}
// Whatever...return some default for now.
if (candidateTask != null && candidateTask.mBounds != null
&& mService.mSupportsFreeformWindowManagement) {
- return FREEFORM_WORKSPACE_STACK_ID;
+ windowingMode = WINDOWING_MODE_FREEFORM;
+ } else {
+ windowingMode = WINDOWING_MODE_FULLSCREEN;
}
- return FULLSCREEN_WORKSPACE_STACK_ID;
+ return display.getOrCreateStack(windowingMode, activityType, onTop);
}
/**
@@ -2364,50 +2380,48 @@
"Display with displayId=" + displayId + " not found.");
}
+ if (!r.canBeLaunchedOnDisplay(displayId)) {
+ return null;
+ }
+
// Return the topmost valid stack on the display.
for (int i = activityDisplay.mStacks.size() - 1; i >= 0; --i) {
final ActivityStack stack = activityDisplay.mStacks.get(i);
- if (isValidLaunchStackId(stack.mStackId, displayId, r)) {
+ if (isValidLaunchStack(stack, displayId, r)) {
return stack;
}
}
// If there is no valid stack on the external display - check if new dynamic stack will do.
- if (displayId != Display.DEFAULT_DISPLAY) {
- final int newDynamicStackId = getNextStackId();
- if (isValidLaunchStackId(newDynamicStackId, displayId, r)) {
- return createStackOnDisplay(newDynamicStackId, displayId, true /*onTop*/);
- }
+ if (displayId != DEFAULT_DISPLAY) {
+ return activityDisplay.createStack(
+ r.getWindowingMode(), r.getActivityType(), true /*onTop*/);
}
Slog.w(TAG, "getValidLaunchStackOnDisplay: can't launch on displayId " + displayId);
return null;
}
- boolean isValidLaunchStackId(int stackId, int displayId, ActivityRecord r) {
- switch (stackId) {
- case INVALID_STACK_ID:
- case HOME_STACK_ID:
- return false;
- case FULLSCREEN_WORKSPACE_STACK_ID:
- return true;
- case FREEFORM_WORKSPACE_STACK_ID:
- return r.supportsFreeform();
- case DOCKED_STACK_ID:
- return r.supportsSplitScreen();
- case PINNED_STACK_ID:
- return r.supportsPictureInPicture();
- case RECENTS_STACK_ID:
- return r.isActivityTypeRecents();
- case ASSISTANT_STACK_ID:
- return r.isActivityTypeAssistant();
- default:
- if (StackId.isDynamicStack(stackId)) {
- return r.canBeLaunchedOnDisplay(displayId);
- }
- Slog.e(TAG, "isValidLaunchStackId: Unexpected stackId=" + stackId);
- return false;
+ // TODO: Can probably be consolidated into getLaunchStack()...
+ private boolean isValidLaunchStack(ActivityStack stack, int displayId, ActivityRecord r) {
+ switch (stack.getActivityType()) {
+ case ACTIVITY_TYPE_HOME: return r.isActivityTypeHome();
+ case ACTIVITY_TYPE_RECENTS: return r.isActivityTypeRecents();
+ case ACTIVITY_TYPE_ASSISTANT: return r.isActivityTypeAssistant();
}
+ switch (stack.getWindowingMode()) {
+ case WINDOWING_MODE_FULLSCREEN: return true;
+ case WINDOWING_MODE_FREEFORM: return r.supportsFreeform();
+ case WINDOWING_MODE_PINNED: return r.supportsPictureInPicture();
+ case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return r.supportsSplitScreenWindowingMode();
+ case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return r.supportsSplitScreenWindowingMode();
+ }
+
+ if (StackId.isDynamicStack(stack.mStackId)) {
+ return r.canBeLaunchedOnDisplay(displayId);
+ }
+ Slog.e(TAG, "isValidLaunchStack: Unexpected stack=" + stack);
+ return false;
}
ArrayList<ActivityStack> getStacks() {
@@ -2440,7 +2454,8 @@
final List<ActivityStack> stacks = getActivityDisplayOrCreateLocked(displayId).mStacks;
for (int j = stacks.size() - 1; j >= 0; --j) {
final ActivityStack stack = stacks.get(j);
- if (stack != currentFocus && stack.isFocusable() && stack.shouldBeVisible(null)) {
+ if (stack != currentFocus && stack.isFocusable()
+ && stack.shouldBeVisible(null)) {
return stack;
}
}
@@ -2509,7 +2524,7 @@
return;
}
- final boolean splitScreenActive = getStack(DOCKED_STACK_ID) != null;
+ final boolean splitScreenActive = getDefaultDisplay().hasSplitScreenStack();
if (!allowResizeInDockedMode
&& !stack.getWindowConfiguration().tasksAreFloating() && splitScreenActive) {
// If the docked stack exists, don't resize non-floating stacks independently of the
@@ -2520,7 +2535,7 @@
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
mWindowManager.deferSurfaceLayout();
try {
- if (stack.supportSplitScreenWindowingMode()) {
+ if (stack.supportsSplitScreenWindowingMode()) {
if (bounds == null && stack.inSplitScreenWindowingMode()) {
// null bounds = fullscreen windowing mode...at least for now.
stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
@@ -2541,22 +2556,22 @@
}
}
- private void deferUpdateBounds(int stackId) {
- final ActivityStack stack = getStack(stackId);
+ private void deferUpdateBounds(int activityType) {
+ final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
if (stack != null) {
stack.deferUpdateBounds();
}
}
- private void continueUpdateBounds(int stackId) {
- final ActivityStack stack = getStack(stackId);
+ private void continueUpdateBounds(int activityType) {
+ final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
if (stack != null) {
stack.continueUpdateBounds();
}
}
void notifyAppTransitionDone() {
- continueUpdateBounds(RECENTS_STACK_ID);
+ continueUpdateBounds(ACTIVITY_TYPE_RECENTS);
for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) {
final int taskId = mResizingTasksDuringAnimation.valueAt(i);
final TaskRecord task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_ONLY);
@@ -2567,25 +2582,31 @@
mResizingTasksDuringAnimation.clear();
}
+ /**
+ * TODO: This should just change the windowing mode and resize vs. actually moving task around.
+ * Can do that once we are no longer using static stack ids. Specially when
+ * {@link ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} is removed.
+ */
private void moveTasksToFullscreenStackInSurfaceTransaction(ActivityStack fromStack,
- boolean onTop) {
+ int toDisplayId, boolean onTop) {
mWindowManager.deferSurfaceLayout();
try {
- final int fromStackId = fromStack.mStackId;
- if (fromStackId == DOCKED_STACK_ID) {
+ final int windowingMode = fromStack.getWindowingMode();
+ final boolean inPinnedWindowingMode = windowingMode == WINDOWING_MODE_PINNED;
+ final ActivityDisplay toDisplay = getActivityDisplay(toDisplayId);
+
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
// We are moving all tasks from the docked stack to the fullscreen stack,
// which is dismissing the docked stack, so resize all other stacks to
// fullscreen here already so we don't end up with resize trashing.
- for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
- final ActivityStack otherStack = getStack(i);
- if (otherStack == null) {
- continue;
- }
+ final ArrayList<ActivityStack> displayStacks = toDisplay.mStacks;
+ for (int i = displayStacks.size() - 1; i >= 0; --i) {
+ final ActivityStack otherStack = displayStacks.get(i);
if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
continue;
}
- resizeStackLocked(i, null, null, null, PRESERVE_WINDOWS,
+ resizeStackLocked(otherStack.mStackId, null, null, null, PRESERVE_WINDOWS,
true /* allowResizeInDockedMode */, DEFER_RESUME);
}
@@ -2594,35 +2615,35 @@
// resize when we remove task from it below and it is detached from the
// display because it no longer contains any tasks.
mAllowDockedStackResize = false;
- } else if (fromStackId == PINNED_STACK_ID) {
- if (onTop) {
- // Log if we are expanding the PiP to fullscreen
- MetricsLogger.action(mService.mContext,
- ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN);
- }
+ } else if (inPinnedWindowingMode && onTop) {
+ // Log if we are expanding the PiP to fullscreen
+ MetricsLogger.action(mService.mContext,
+ ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN);
}
- ActivityStack fullscreenStack = getStack(FULLSCREEN_WORKSPACE_STACK_ID);
- final boolean isFullscreenStackVisible = fullscreenStack != null
- && fullscreenStack.shouldBeVisible(null);
+
// If we are moving from the pinned stack, then the animation takes care of updating
// the picture-in-picture mode.
- final boolean schedulePictureInPictureModeChange = (fromStackId == PINNED_STACK_ID);
+ final boolean schedulePictureInPictureModeChange = inPinnedWindowingMode;
final ArrayList<TaskRecord> tasks = fromStack.getAllTasks();
final int size = tasks.size();
+ final ActivityStack fullscreenStack = toDisplay.getOrCreateStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, onTop);
+
if (onTop) {
+ final int returnToType =
+ toDisplay.getTopVisibleStackActivityType(WINDOWING_MODE_PINNED);
for (int i = 0; i < size; i++) {
final TaskRecord task = tasks.get(i);
final boolean isTopTask = i == (size - 1);
- if (fromStackId == PINNED_STACK_ID) {
+ if (inPinnedWindowingMode) {
// Update the return-to to reflect where the pinned stack task was moved
// from so that we retain the stack that was previously visible if the
// pinned stack is recreated. See moveActivityToPinnedStackLocked().
- task.setTaskToReturnTo(isFullscreenStackVisible ?
- ACTIVITY_TYPE_STANDARD : ACTIVITY_TYPE_HOME);
+ task.setTaskToReturnTo(returnToType);
}
// Defer resume until all the tasks have been moved to the fullscreen stack
- task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP,
- REPARENT_MOVE_STACK_TO_FRONT, isTopTask /* animate */, DEFER_RESUME,
+ task.reparent(fullscreenStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT,
+ isTopTask /* animate */, DEFER_RESUME,
schedulePictureInPictureModeChange,
"moveTasksToFullscreenStack - onTop");
}
@@ -2632,7 +2653,7 @@
// Position the tasks in the fullscreen stack in order at the bottom of the
// stack. Also defer resume until all the tasks have been moved to the
// fullscreen stack.
- task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, i /* position */,
+ task.reparent(fullscreenStack, i /* position */,
REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE, DEFER_RESUME,
schedulePictureInPictureModeChange,
"moveTasksToFullscreenStack - NOT_onTop");
@@ -2648,8 +2669,12 @@
}
void moveTasksToFullscreenStackLocked(ActivityStack fromStack, boolean onTop) {
- mWindowManager.inSurfaceTransaction(
- () -> moveTasksToFullscreenStackInSurfaceTransaction(fromStack, onTop));
+ moveTasksToFullscreenStackLocked(fromStack, DEFAULT_DISPLAY, onTop);
+ }
+
+ void moveTasksToFullscreenStackLocked(ActivityStack fromStack, int toDisplayId, boolean onTop) {
+ mWindowManager.inSurfaceTransaction(() ->
+ moveTasksToFullscreenStackInSurfaceTransaction(fromStack, toDisplayId, onTop));
}
void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds,
@@ -2660,7 +2685,7 @@
false /* deferResume */);
}
- void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds,
+ private void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds,
Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds,
boolean preserveWindows, boolean deferResume) {
@@ -2669,7 +2694,8 @@
return;
}
- final ActivityStack stack = getStack(DOCKED_STACK_ID);
+ final ActivityStack stack = getDefaultDisplay().getStack(
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
if (stack == null) {
Slog.w(TAG, "resizeDockedStackLocked: docked stack not found");
return;
@@ -2698,13 +2724,14 @@
// static stacks need to be adjusted so they don't overlap with the docked stack.
// We get the bounds to use from window manager which has been adjusted for any
// screen controls and is also the same for all stacks.
+ final ArrayList<ActivityStack> stacks = getStacksOnDefaultDisplay();
final Rect otherTaskRect = new Rect();
- for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
- if (i == DOCKED_STACK_ID) {
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ final ActivityStack current = stacks.get(i);
+ if (current.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
continue;
}
- final ActivityStack current = getStack(i);
- if (current == null || !current.supportSplitScreenWindowingMode()) {
+ if (!current.supportsSplitScreenWindowingMode()) {
continue;
}
// Need to set windowing mode here before we try to get the dock bounds.
@@ -2714,7 +2741,7 @@
tempRect /* outStackBounds */,
otherTaskRect /* outTempTaskBounds */, true /* ignoreVisibility */);
- resizeStackLocked(i, !tempRect.isEmpty() ? tempRect : null,
+ resizeStackLocked(current.mStackId, !tempRect.isEmpty() ? tempRect : null,
!otherTaskRect.isEmpty() ? otherTaskRect : tempOtherTaskBounds,
tempOtherTaskInsetBounds, preserveWindows,
true /* allowResizeInDockedMode */, deferResume);
@@ -2731,7 +2758,9 @@
}
void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
- final PinnedActivityStack stack = getStack(PINNED_STACK_ID);
+ // TODO(multi-display): Pinned stack display should be passed in.
+ final PinnedActivityStack stack = getDefaultDisplay().getStack(
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
if (stack == null) {
Slog.w(TAG, "resizePinnedStackLocked: pinned stack not found");
return;
@@ -2769,32 +2798,14 @@
}
}
- ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
- final ActivityDisplay activityDisplay = getActivityDisplayOrCreateLocked(displayId);
- if (activityDisplay == null) {
- return null;
- }
- return createStack(stackId, activityDisplay, onTop);
-
- }
-
- ActivityStack createStack(int stackId, ActivityDisplay display, boolean onTop) {
- switch (stackId) {
- case PINNED_STACK_ID:
- return new PinnedActivityStack(display, stackId, this, onTop);
- default:
- return new ActivityStack(display, stackId, this, onTop);
- }
- }
-
- void removeStackInSurfaceTransaction(int stackId) {
+ private void removeStackInSurfaceTransaction(int stackId) {
final ActivityStack stack = getStack(stackId);
if (stack == null) {
return;
}
final ArrayList<TaskRecord> tasks = stack.getAllTasks();
- if (stack.getStackId() == PINNED_STACK_ID) {
+ if (stack.getWindowingMode() == WINDOWING_MODE_PINNED) {
/**
* Workaround: Force-stop all the activities in the pinned stack before we reparent them
* to the fullscreen stack. This is to guarantee that when we are removing a stack,
@@ -2827,8 +2838,23 @@
* instead moved back onto the fullscreen stack.
*/
void removeStackLocked(int stackId) {
- mWindowManager.inSurfaceTransaction(
- () -> removeStackInSurfaceTransaction(stackId));
+ mWindowManager.inSurfaceTransaction(() -> removeStackInSurfaceTransaction(stackId));
+ }
+
+ /**
+ * Removes stacks in the input windowing modes from the system if they are of activity type
+ * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
+ */
+ void removeStacksInWindowingModes(int... windowingModes) {
+ for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
+ mActivityDisplays.valueAt(i).removeStacksInWindowingModes(windowingModes);
+ }
+ }
+
+ void removeStacksWithActivityTypes(int... activityTypes) {
+ for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
+ mActivityDisplays.valueAt(i).removeStacksWithActivityTypes(activityTypes);
+ }
}
/**
@@ -2966,11 +2992,11 @@
* @return true if the task has been restored successfully.
*/
boolean restoreRecentTaskLocked(TaskRecord task, ActivityOptions aOptions) {
- final int stackId = getLaunchStackId(null, aOptions, task);
+ final ActivityStack stack = getLaunchStack(null, aOptions, task, !ON_TOP);
final ActivityStack currentStack = task.getStack();
if (currentStack != null) {
// Task has already been restored once. See if we need to do anything more
- if (currentStack.mStackId == stackId) {
+ if (currentStack == stack) {
// Nothing else to do since it is already restored in the right stack.
return true;
}
@@ -2979,11 +3005,9 @@
currentStack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING);
}
- final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, !ON_TOP);
-
- stack.addTask(task, false /* toTop */, "restoreRecentTask");
+ stack.addTask(task, !ON_TOP, "restoreRecentTask");
// TODO: move call for creation here and other place into Stack.addTask()
- task.createWindowContainer(false /* toTop */, true /* showForAllUsers */);
+ task.createWindowContainer(!ON_TOP, true /* showForAllUsers */);
if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
"Added restored task=" + task + " to stack=" + stack);
final ArrayList<ActivityRecord> activities = task.mActivities;
@@ -3030,8 +3054,10 @@
* Returns the reparent target stack, creating the stack if necessary. This call also enforces
* the various checks on tasks that are going to be reparented from one stack to another.
*/
- ActivityStack getReparentTargetStack(TaskRecord task, int stackId, boolean toTop) {
+ ActivityStack getReparentTargetStack(TaskRecord task, ActivityStack stack, boolean toTop) {
final ActivityStack prevStack = task.getStack();
+ final int stackId = stack.mStackId;
+ final boolean inMultiWindowMode = stack.inMultiWindowMode();
// Check that we aren't reparenting to the same stack that the task is already in
if (prevStack != null && prevStack.mStackId == stackId) {
@@ -3042,22 +3068,22 @@
// Ensure that we aren't trying to move into a multi-window stack without multi-window
// support
- if (StackId.isMultiWindowStack(stackId) && !mService.mSupportsMultiWindow) {
+ if (inMultiWindowMode && !mService.mSupportsMultiWindow) {
throw new IllegalArgumentException("Device doesn't support multi-window, can not"
- + " reparent task=" + task + " to stackId=" + stackId);
+ + " reparent task=" + task + " to stack=" + stack);
}
// Ensure that we're not moving a task to a dynamic stack if device doesn't support
// multi-display.
- // TODO(multi-display): Support non-dynamic stacks on secondary displays.
- if (StackId.isDynamicStack(stackId) && !mService.mSupportsMultiDisplay) {
+ if (stack.mDisplayId != DEFAULT_DISPLAY && !mService.mSupportsMultiDisplay) {
throw new IllegalArgumentException("Device doesn't support multi-display, can not"
+ " reparent task=" + task + " to stackId=" + stackId);
}
// Ensure that we aren't trying to move into a freeform stack without freeform
// support
- if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
+ if (stack.getWindowingMode() == WINDOWING_MODE_FREEFORM
+ && !mService.mSupportsFreeformWindowManagement) {
throw new IllegalArgumentException("Device doesn't support freeform, can not reparent"
+ " task=" + task);
}
@@ -3066,25 +3092,25 @@
// used for split-screen mode and will cause things like the docked divider to show up. We
// instead leave the task in its current stack or move it to the fullscreen stack if it
// isn't currently in a stack.
- if (stackId == DOCKED_STACK_ID && !task.isResizeable()) {
- stackId = (prevStack != null) ? prevStack.mStackId : FULLSCREEN_WORKSPACE_STACK_ID;
+ if (inMultiWindowMode && !task.isResizeable()) {
Slog.w(TAG, "Can not move unresizeable task=" + task + " to docked stack."
+ " Moving to stackId=" + stackId + " instead.");
+ // Temporarily disable resizeablility of the task as we don't want it to be resized if,
+ // for example, a docked stack is created which will lead to the stack we are moving
+ // from being resized and and its resizeable tasks being resized.
+ try {
+ task.mTemporarilyUnresizable = true;
+ stack = stack.getDisplay().createStack(
+ WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), toTop);
+ } finally {
+ task.mTemporarilyUnresizable = false;
+ }
}
-
- // Temporarily disable resizeablility of the task as we don't want it to be resized if, for
- // example, a docked stack is created which will lead to the stack we are moving from being
- // resized and and its resizeable tasks being resized.
- try {
- task.mTemporarilyUnresizable = true;
- return getStack(stackId, CREATE_IF_NEEDED, toTop);
- } finally {
- task.mTemporarilyUnresizable = false;
- }
+ return stack;
}
boolean moveTopStackActivityToPinnedStackLocked(int stackId, Rect destBounds) {
- final ActivityStack stack = getStack(stackId, !CREATE_IF_NEEDED, !ON_TOP);
+ final ActivityStack stack = getStack(stackId);
if (stack == null) {
throw new IllegalArgumentException(
"moveTopStackActivityToPinnedStackLocked: Unknown stackId=" + stackId);
@@ -3114,7 +3140,8 @@
mWindowManager.deferSurfaceLayout();
- PinnedActivityStack stack = getStack(PINNED_STACK_ID);
+ final ActivityDisplay display = r.getStack().getDisplay();
+ PinnedActivityStack stack = display.getPinnedStack();
// This will clear the pinned stack by moving an existing task to the full screen stack,
// ensuring only one task is present.
@@ -3123,7 +3150,7 @@
}
// Need to make sure the pinned stack exist so we can resize it below...
- stack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
+ stack = display.getOrCreateStack(WINDOWING_MODE_PINNED, r.getActivityType(), ON_TOP);
try {
final TaskRecord task = r.getTask();
@@ -3147,8 +3174,8 @@
moveHomeStackToFront(reason);
}
// Defer resume until below, and do not schedule PiP changes until we animate below
- task.reparent(PINNED_STACK_ID, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE,
- DEFER_RESUME, false /* schedulePictureInPictureModeChange */, reason);
+ task.reparent(stack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE, DEFER_RESUME,
+ false /* schedulePictureInPictureModeChange */, reason);
} else {
// There are multiple activities in the task and moving the top activity should
// reveal/leave the other activities in their original task.
@@ -3163,7 +3190,7 @@
r.reparent(newTask, MAX_VALUE, "moveActivityToStack");
// Defer resume until below, and do not schedule PiP changes until we animate below
- newTask.reparent(PINNED_STACK_ID, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE,
+ newTask.reparent(stack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE,
DEFER_RESUME, false /* schedulePictureInPictureModeChange */, reason);
}
@@ -3617,7 +3644,7 @@
boolean switchUserLocked(int userId, UserState uss) {
final int focusStackId = mFocusedStack.getStackId();
// We dismiss the docked stack whenever we switch users.
- final ActivityStack dockedStack = getStack(DOCKED_STACK_ID);
+ final ActivityStack dockedStack = getDefaultDisplay().getSplitScreenStack();
if (dockedStack != null) {
moveTasksToFullscreenStackLocked(dockedStack, mFocusedStack == dockedStack);
}
@@ -3627,7 +3654,7 @@
removeStackLocked(PINNED_STACK_ID);
mUserStackInFront.put(mCurrentUser, focusStackId);
- final int restoreStackId = mUserStackInFront.get(userId, HOME_STACK_ID);
+ final int restoreStackId = mUserStackInFront.get(userId, mHomeStack.mStackId);
mCurrentUser = userId;
mStartingUsers.add(uss);
@@ -3660,7 +3687,7 @@
/** Checks whether the userid is a profile of the current user. */
boolean isCurrentProfileLocked(int userId) {
if (userId == mCurrentUser) return true;
- return mService.mUserController.isCurrentProfileLocked(userId);
+ return mService.mUserController.isCurrentProfile(userId);
}
/**
@@ -4057,15 +4084,22 @@
return getActivityDisplayOrCreateLocked(displayId) != null;
}
+ // TODO: Look into consolidating with getActivityDisplayOrCreateLocked()
ActivityDisplay getActivityDisplay(int displayId) {
return mActivityDisplays.get(displayId);
}
+ // TODO(multi-display): Look at all callpoints to make sure they make sense in multi-display.
+ ActivityDisplay getDefaultDisplay() {
+ return mActivityDisplays.get(DEFAULT_DISPLAY);
+ }
+
/**
* Get an existing instance of {@link ActivityDisplay} or create new if there is a
* corresponding record in display manager.
*/
- private ActivityDisplay getActivityDisplayOrCreateLocked(int displayId) {
+ // TODO: Look into consolidating with getActivityDisplay()
+ ActivityDisplay getActivityDisplayOrCreateLocked(int displayId) {
ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
if (activityDisplay != null) {
return activityDisplay;
@@ -4189,7 +4223,7 @@
mService.updateSleepIfNeededLocked();
}
- private StackInfo getStackInfoLocked(ActivityStack stack) {
+ private StackInfo getStackInfo(ActivityStack stack) {
final int displayId = stack.mDisplayId;
final ActivityDisplay display = mActivityDisplays.get(displayId);
StackInfo info = new StackInfo();
@@ -4199,9 +4233,8 @@
info.userId = stack.mCurrentUser;
info.visible = stack.shouldBeVisible(null);
// A stack might be not attached to a display.
- info.position = display != null
- ? display.mStacks.indexOf(stack)
- : 0;
+ info.position = display != null ? display.mStacks.indexOf(stack) : 0;
+ info.configuration.setTo(stack.getConfiguration());
ArrayList<TaskRecord> tasks = stack.getAllTasks();
final int numTasks = tasks.size();
@@ -4230,20 +4263,25 @@
return info;
}
- StackInfo getStackInfoLocked(int stackId) {
+ StackInfo getStackInfo(int stackId) {
ActivityStack stack = getStack(stackId);
if (stack != null) {
- return getStackInfoLocked(stack);
+ return getStackInfo(stack);
}
return null;
}
+ StackInfo getStackInfo(int windowingMode, int activityType) {
+ final ActivityStack stack = getStack(windowingMode, activityType);
+ return (stack != null) ? getStackInfo(stack) : null;
+ }
+
ArrayList<StackInfo> getAllStackInfosLocked() {
ArrayList<StackInfo> list = new ArrayList<>();
for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) {
- list.add(getStackInfoLocked(stacks.get(ndx)));
+ list.add(getStackInfo(stacks.get(ndx)));
}
}
return list;
@@ -4290,7 +4328,8 @@
}
final ActivityRecord topActivity = task.getTopActivity();
- if (launchOnSecondaryDisplayFailed || !task.supportsSplitScreen() || forceNonResizable) {
+ if (launchOnSecondaryDisplayFailed
+ || !task.supportsSplitScreenWindowingMode() || forceNonResizable) {
if (launchOnSecondaryDisplayFailed) {
// Display a warning toast that we tried to put a non-resizeable task on a secondary
// display with config different from global config.
@@ -4304,7 +4343,8 @@
// Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
// we need to move it to top of fullscreen stack, otherwise it will be covered.
- final ActivityStack dockedStack = getStack(DOCKED_STACK_ID);
+
+ final ActivityStack dockedStack = task.getStack().getDisplay().getSplitScreenStack();
if (dockedStack != null) {
moveTasksToFullscreenStackLocked(dockedStack,
actualStackId == dockedStack.getStackId());
@@ -4567,14 +4607,14 @@
// Defer updating the stack in which recents is until the app transition is done, to
// not run into issues where we still need to draw the task in recents but the
// docked stack is already created.
- deferUpdateBounds(RECENTS_STACK_ID);
+ deferUpdateBounds(ACTIVITY_TYPE_RECENTS);
mWindowManager.prepareAppTransition(TRANSIT_DOCK_TASK_FROM_RECENTS, false);
}
task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE,
activityOptions);
if (task == null) {
- continueUpdateBounds(RECENTS_STACK_ID);
+ continueUpdateBounds(ACTIVITY_TYPE_RECENTS);
mWindowManager.executeAppTransition();
throw new IllegalArgumentException(
"startActivityFromRecentsInner: Task " + taskId + " not found.");
@@ -4582,13 +4622,10 @@
// Since we don't have an actual source record here, we assume that the currently
// focused activity was the source.
- final ActivityStack focusedStack = getFocusedStack();
- final ActivityRecord sourceRecord = focusedStack != null
- ? focusedStack.topActivity() : null;
- final int stackId = getLaunchStackId(null, activityOptions, task);
+ final ActivityStack stack = getLaunchStack(null, activityOptions, task, ON_TOP);
- if (stackId != INVALID_STACK_ID && task.getStackId() != stackId) {
- task.reparent(stackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
+ if (stack != null && task.getStack() != stack) {
+ task.reparent(stack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"startActivityFromRecents");
}
@@ -4613,10 +4650,7 @@
}
mService.mActivityStarter.postStartActivityProcessing(task.getTopActivity(),
- ActivityManager.START_TASK_TO_FRONT,
- sourceRecord != null
- ? sourceRecord.getTask().getStackId() : INVALID_STACK_ID,
- sourceRecord, task.getStack());
+ ActivityManager.START_TASK_TO_FRONT, 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 1a2b46c..ccb9181 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -27,18 +27,18 @@
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.ActivityManager.StackId;
-import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
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.FULLSCREEN_WORKSPACE_STACK_ID;
-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.app.ActivityManager.StackId.RECENTS_STACK_ID;
import static android.app.ActivityManager.StackId.isDynamicStack;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
@@ -77,7 +77,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.ANIMATE;
import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
-import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -590,9 +589,7 @@
auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo);
}
- void postStartActivityProcessing(
- ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord,
- ActivityStack targetStack) {
+ void postStartActivityProcessing(ActivityRecord r, int result, ActivityStack targetStack) {
if (ActivityManager.isStartResultFatalError(result)) {
return;
@@ -614,7 +611,8 @@
}
if (startedActivityStackId == DOCKED_STACK_ID) {
- final ActivityStack homeStack = mSupervisor.getStack(HOME_STACK_ID);
+ final ActivityStack homeStack = mSupervisor.getDefaultDisplay().getStack(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME);
final boolean homeStackVisible = homeStack != null && homeStack.isVisible();
if (homeStackVisible) {
// We launch an activity while being in home stack, which means either launcher or
@@ -1002,8 +1000,7 @@
mService.mWindowManager.continueSurfaceLayout();
}
- postStartActivityProcessing(r, result, mSupervisor.getLastStack().mStackId, mSourceRecord,
- mTargetStack);
+ postStartActivityProcessing(r, result, mTargetStack);
return result;
}
@@ -1612,12 +1609,11 @@
mTargetStack.moveTaskToFrontLocked(intentTask, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
mMovedToFront = true;
- } else if (launchStack.mStackId == DOCKED_STACK_ID
- || launchStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+ } else if (launchStack.inSplitScreenWindowingMode()) {
if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
// If we want to launch adjacent and mTargetStack is not the computed
// launch stack - move task to top of computed stack.
- intentTask.reparent(launchStack.mStackId, ON_TOP,
+ intentTask.reparent(launchStack, ON_TOP,
REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"launchToSide");
} else {
@@ -1634,17 +1630,17 @@
// Target and computed stacks are on different displays and we've
// found a matching task - move the existing instance to that display and
// move it to front.
- intentActivity.getTask().reparent(launchStack.mStackId, ON_TOP,
+ intentActivity.getTask().reparent(launchStack, ON_TOP,
REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"reparentToDisplay");
mMovedToFront = true;
- } else if (launchStack.getStackId() == StackId.HOME_STACK_ID
- && mTargetStack.getStackId() != StackId.HOME_STACK_ID) {
+ } else if (launchStack.isActivityTypeHome()
+ && !mTargetStack.isActivityTypeHome()) {
// It is possible for the home activity to be in another stack initially.
// For example, the activity may have been initially started with an intent
// which placed it in the fullscreen stack. To ensure the proper handling of
// the activity based on home stack assumptions, we must move it over.
- intentActivity.getTask().reparent(launchStack.mStackId, ON_TOP,
+ intentActivity.getTask().reparent(launchStack, ON_TOP,
REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"reparentingHome");
mMovedToFront = true;
@@ -1879,8 +1875,8 @@
if (mTargetStack == null) {
mTargetStack = sourceStack;
} else if (mTargetStack != sourceStack) {
- sourceTask.reparent(mTargetStack.mStackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT,
- !ANIMATE, DEFER_RESUME, "launchToSide");
+ sourceTask.reparent(mTargetStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE,
+ DEFER_RESUME, "launchToSide");
}
final TaskRecord topTask = mTargetStack.topTask();
@@ -1977,15 +1973,16 @@
if (mLaunchBounds != null) {
mInTask.updateOverrideConfiguration(mLaunchBounds);
// TODO: Shouldn't we already know what stack to use by the time we get here?
- int stackId = mSupervisor.getLaunchStackId(null, null, mInTask);
- if (stackId != mInTask.getStackId()) {
- mInTask.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE,
+ ActivityStack stack = mSupervisor.getLaunchStack(null, null, mInTask, ON_TOP);
+ if (stack != mInTask.getStack()) {
+ mInTask.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE,
DEFER_RESUME, "inTaskToFront");
- stackId = mInTask.getStackId();
+ stack = mInTask.getStack();
mTargetStack = mInTask.getStack();
}
- if (StackId.resizeStackWithLaunchBounds(stackId)) {
- mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
+ if (StackId.resizeStackWithLaunchBounds(stack.mStackId)) {
+ mService.resizeStack(
+ stack.mStackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
}
}
@@ -2116,11 +2113,7 @@
}
}
// If there is no suitable dynamic stack then we figure out which static stack to use.
- final int stackId = task != null ? mSupervisor.getLaunchStackId(r, aOptions, task)
- // TODO: This should go in mSupervisor.getLaunchStackId method...
- : bounds != null && mService.mSupportsFreeformWindowManagement
- ? FREEFORM_WORKSPACE_STACK_ID : FULLSCREEN_WORKSPACE_STACK_ID;
- stack = mSupervisor.getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
+ stack = mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP);
}
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
+ r + " stackId=" + stack.mStackId);
@@ -2128,36 +2121,39 @@
}
/** Check if provided activity record can launch in currently focused stack. */
+ // TODO: This method can probably be consolidated into getLaunchStack() below.
private boolean canLaunchIntoFocusedStack(ActivityRecord r, boolean newTask) {
final ActivityStack focusedStack = mSupervisor.mFocusedStack;
- final int focusedStackId = mSupervisor.mFocusedStack.mStackId;
final boolean canUseFocusedStack;
- switch (focusedStackId) {
- case FULLSCREEN_WORKSPACE_STACK_ID:
- // The fullscreen stack can contain any task regardless of if the task is resizeable
- // or not. So, we let the task go in the fullscreen task if it is the focus stack.
- canUseFocusedStack = true;
- break;
- case ASSISTANT_STACK_ID:
- canUseFocusedStack = r.isActivityTypeAssistant();
- break;
- case DOCKED_STACK_ID:
- // Any activity which supports split screen can go in the docked stack.
- canUseFocusedStack = r.supportsSplitScreen();
- break;
- case FREEFORM_WORKSPACE_STACK_ID:
- // Any activity which supports freeform can go in the freeform stack.
- canUseFocusedStack = r.supportsFreeform();
- break;
- default:
- // Dynamic stacks behave similarly to the fullscreen stack and can contain any
- // resizeable task.
- canUseFocusedStack = isDynamicStack(focusedStackId)
- && r.canBeLaunchedOnDisplay(focusedStack.mDisplayId);
+ final int focusedStackId = mSupervisor.mFocusedStack.mStackId;
+ if (focusedStack.isActivityTypeAssistant()) {
+ canUseFocusedStack = r.isActivityTypeAssistant();
+ } else {
+ switch (focusedStack.getWindowingMode()) {
+ case WINDOWING_MODE_FULLSCREEN:
+ // The fullscreen stack can contain any task regardless of if the task is
+ // resizeable or not. So, we let the task go in the fullscreen task if it is the
+ // focus stack.
+ canUseFocusedStack = true;
+ break;
+ case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
+ case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
+ // Any activity which supports split screen can go in the docked stack.
+ canUseFocusedStack = r.supportsSplitScreenWindowingMode();
+ break;
+ case WINDOWING_MODE_FREEFORM:
+ // Any activity which supports freeform can go in the freeform stack.
+ canUseFocusedStack = r.supportsFreeform();
+ break;
+ default:
+ // Dynamic stacks behave similarly to the fullscreen stack and can contain any
+ // resizeable task.
+ canUseFocusedStack = isDynamicStack(focusedStackId)
+ && r.canBeLaunchedOnDisplay(focusedStack.mDisplayId);
+ }
}
-
return canUseFocusedStack && !newTask
- // Using the focus stack isn't important enough to override the prefered display.
+ // Using the focus stack isn't important enough to override the preferred display.
&& (mPreferredDisplayId == focusedStack.mDisplayId);
}
@@ -2168,50 +2164,12 @@
return mReuseTask.getStack();
}
- // If the activity is of a specific type, return the associated stack, creating it if
- // necessary
- if (r.isActivityTypeHome()) {
- return mSupervisor.mHomeStack;
- }
- if (r.isActivityTypeRecents()) {
- return mSupervisor.getStack(RECENTS_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
- }
- if (r.isActivityTypeAssistant()) {
- return mSupervisor.getStack(ASSISTANT_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
- }
+ final int vrDisplayId = mUsingVr2dDisplay ? mPreferredDisplayId : INVALID_DISPLAY;
+ final ActivityStack launchStack = mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP,
+ vrDisplayId);
- int launchDisplayId = INVALID_DISPLAY;
- int launchStackId = INVALID_STACK_ID;
- if (aOptions != null) {
- launchDisplayId = aOptions.getLaunchDisplayId();
- final int vrDisplayId = mUsingVr2dDisplay ? mPreferredDisplayId : INVALID_DISPLAY;
- launchStackId = mSupervisor.getLaunchStackId(r, aOptions, task, vrDisplayId);
- }
-
- // TODO: Will no longer be needed once we are on longer using static stack ids.
- if (mSupervisor.isValidLaunchStackId(launchStackId, launchDisplayId, r)) {
- return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP);
- }
- if (launchStackId == DOCKED_STACK_ID) {
- // The preferred launch stack is the docked stack, but it isn't a valid launch stack
- // for this activity, so we put the activity in the fullscreen stack.
- return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
- }
- // TODO: Can probably be removed since ASS.getLaunchStackId() does display resolution.
- if (launchDisplayId != INVALID_DISPLAY) {
- // Stack id has higher priority than display id.
- return mSupervisor.getValidLaunchStackOnDisplay(launchDisplayId, r);
- }
-
- // If we are using Vr2d display, find the virtual display stack.
- // TODO: Can be removed.
- if (mUsingVr2dDisplay) {
- ActivityStack as = mSupervisor.getValidLaunchStackOnDisplay(mPreferredDisplayId, r);
- if (DEBUG_STACK) {
- Slog.v(TAG, "Launch stack for app: " + r.toString() +
- ", on virtual display stack:" + as.toString());
- }
- return as;
+ if (launchStack != null) {
+ return launchStack;
}
if (((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0)
@@ -2237,13 +2195,15 @@
if (parentStack != null && parentStack.isDockedStack()) {
// If parent was in docked stack, the natural place to launch another activity
// will be fullscreen, so it can appear alongside the docked window.
- return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED,
- ON_TOP);
+ final int activityType = mSupervisor.resolveActivityType(r, mOptions, task);
+ return parentStack.getDisplay().getOrCreateStack(
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, activityType, ON_TOP);
} else {
// If the parent is not in the docked stack, we check if there is docked window
// and if yes, we will launch into that stack. If not, we just put the new
// activity into parent's stack, because we can't find a better place.
- final ActivityStack dockedStack = mSupervisor.getStack(DOCKED_STACK_ID);
+ final ActivityStack dockedStack = mSupervisor.getDefaultDisplay().getStack(
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
if (dockedStack != null && !dockedStack.shouldBeVisible(r)) {
// There is a docked stack, but it isn't visible, so we can't launch into that.
return null;
@@ -2267,15 +2227,6 @@
mWindowManager = wm;
}
- void removePendingActivityLaunchesLocked(ActivityStack stack) {
- for (int palNdx = mPendingActivityLaunches.size() - 1; palNdx >= 0; --palNdx) {
- PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx);
- if (pal.stack == stack) {
- mPendingActivityLaunches.remove(palNdx);
- }
- }
- }
-
static boolean isDocumentLaunchesIntoExisting(int flags) {
return (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
(flags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0;
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 440b3d3b..fe38097 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -507,7 +507,7 @@
// launching the report UI under a different user.
app.errorReportReceiver = null;
- for (int userId : mService.mUserController.getCurrentProfileIdsLocked()) {
+ for (int userId : mService.mUserController.getCurrentProfileIds()) {
if (app.userId == userId) {
app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
mContext, app.info.packageName, app.info.flags);
@@ -728,7 +728,7 @@
boolean isBackground = (UserHandle.getAppId(proc.uid)
>= Process.FIRST_APPLICATION_UID
&& proc.pid != MY_PID);
- for (int userId : mService.mUserController.getCurrentProfileIdsLocked()) {
+ for (int userId : mService.mUserController.getCurrentProfileIds()) {
isBackground &= (proc.userId != userId);
}
if (isBackground && !showBackground) {
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 7101fc4..5c48f90 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -342,7 +342,7 @@
// show on top of the lock screen. In this can we want to dismiss the docked
// stack since it will be complicated/risky to try to put the activity on top
// of the lock screen in the right fullscreen configuration.
- final ActivityStack stack = mStackSupervisor.getStack(DOCKED_STACK_ID);
+ final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getSplitScreenStack();
if (stack == null) {
return;
}
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index ee59386..7930f53 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -308,7 +308,7 @@
boolean sendFinish = finishedReceiver != null;
int userId = key.userId;
if (userId == UserHandle.USER_CURRENT) {
- userId = owner.mUserController.getCurrentOrTargetUserIdLocked();
+ userId = owner.mUserController.getCurrentOrTargetUserId();
}
int res = 0;
switch (key.type) {
diff --git a/services/core/java/com/android/server/am/PinnedActivityStack.java b/services/core/java/com/android/server/am/PinnedActivityStack.java
index 33f5664..468b867 100644
--- a/services/core/java/com/android/server/am/PinnedActivityStack.java
+++ b/services/core/java/com/android/server/am/PinnedActivityStack.java
@@ -16,6 +16,9 @@
package com.android.server.am;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
import android.app.RemoteAction;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -34,7 +37,7 @@
PinnedActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
boolean onTop) {
- super(display, stackId, supervisor, onTop);
+ super(display, stackId, supervisor, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, onTop);
}
@Override
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index f6e20cd..61994b5 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -54,9 +54,6 @@
import java.util.Comparator;
import java.util.List;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-
import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
public class TaskPersister {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index fb8b034..0d8df79 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -18,20 +18,19 @@
import static android.app.ActivityManager.RESIZE_MODE_FORCED;
import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
-import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
-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.FULLSCREEN_WORKSPACE_STACK_ID;
-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.app.ActivityManager.StackId.RECENTS_STACK_ID;
-import static android.app.ActivityManager.StackId.getWindowingModeForStackId;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
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_RELINQUISH_TASK_IDENTITY;
@@ -573,36 +572,36 @@
/**
* Convenience method to reparent a task to the top or bottom position of the stack.
*/
- boolean reparent(int preferredStackId, boolean toTop, @ReparentMoveStackMode int moveStackMode,
- boolean animate, boolean deferResume, String reason) {
- return reparent(preferredStackId, toTop ? MAX_VALUE : 0, moveStackMode, animate,
- deferResume, true /* schedulePictureInPictureModeChange */, reason);
+ boolean reparent(ActivityStack preferredStack, boolean toTop,
+ @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ String reason) {
+ return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume,
+ true /* schedulePictureInPictureModeChange */, reason);
}
/**
* Convenience method to reparent a task to the top or bottom position of the stack, with
* an option to skip scheduling the picture-in-picture mode change.
*/
- boolean reparent(int preferredStackId, boolean toTop, @ReparentMoveStackMode int moveStackMode,
- boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange,
- String reason) {
- return reparent(preferredStackId, toTop ? MAX_VALUE : 0, moveStackMode, animate,
+ boolean reparent(ActivityStack preferredStack, boolean toTop,
+ @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ boolean schedulePictureInPictureModeChange, String reason) {
+ return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate,
deferResume, schedulePictureInPictureModeChange, reason);
}
- /**
- * Convenience method to reparent a task to a specific position of the stack.
- */
- boolean reparent(int preferredStackId, int position, @ReparentMoveStackMode int moveStackMode,
- boolean animate, boolean deferResume, String reason) {
- return reparent(preferredStackId, position, moveStackMode, animate, deferResume,
+ /** Convenience method to reparent a task to a specific position of the stack. */
+ boolean reparent(ActivityStack preferredStack, int position,
+ @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ String reason) {
+ return reparent(preferredStack, position, moveStackMode, animate, deferResume,
true /* schedulePictureInPictureModeChange */, reason);
}
/**
* Reparents the task into a preferred stack, creating it if necessary.
*
- * @param preferredStackId the stack id of the target stack to move this task
+ * @param preferredStack the target stack to move this task
* @param position the position to place this task in the new stack
* @param animate whether or not we should wait for the new window created as a part of the
* reparenting to be drawn and animated in
@@ -616,13 +615,16 @@
* @param reason the caller of this reparenting
* @return whether the task was reparented
*/
- boolean reparent(int preferredStackId, int position, @ReparentMoveStackMode int moveStackMode,
- boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange,
- String reason) {
+ // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs.
+ // re-parenting the task. Can only be done when we are no longer using static stack Ids like
+ /** {@link ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} */
+ boolean reparent(ActivityStack preferredStack, int position,
+ @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ boolean schedulePictureInPictureModeChange, String reason) {
final ActivityStackSupervisor supervisor = mService.mStackSupervisor;
final WindowManagerService windowManager = mService.mWindowManager;
final ActivityStack sourceStack = getStack();
- final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStackId,
+ final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack,
position == MAX_VALUE);
if (toStack == sourceStack) {
return false;
@@ -705,19 +707,22 @@
toStack.prepareFreezingTaskBounds();
// Make sure the task has the appropriate bounds/size for the stack it is in.
+ final int toStackWindowingMode = toStack.getWindowingMode();
+ final boolean toStackSplitScreenPrimary =
+ toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
if (stackId == FULLSCREEN_WORKSPACE_STACK_ID
&& !Objects.equals(mBounds, toStack.mBounds)) {
kept = resize(toStack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow,
deferResume);
- } else if (stackId == FREEFORM_WORKSPACE_STACK_ID) {
+ } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) {
Rect bounds = getLaunchBounds();
if (bounds == null) {
toStack.layoutTaskInStack(this, null);
bounds = mBounds;
}
kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
- } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) {
- if (stackId == DOCKED_STACK_ID && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
+ } else if (toStackSplitScreenPrimary || toStackWindowingMode == WINDOWING_MODE_PINNED) {
+ if (toStackSplitScreenPrimary && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
// Move recents to front so it is not behind home stack when going into docked
// mode
mService.mStackSupervisor.moveRecentsStackToFront(reason);
@@ -744,11 +749,12 @@
}
// TODO: Handle incorrect request to move before the actual move, not after.
- supervisor.handleNonResizableTaskIfNeeded(this, getWindowingModeForStackId(preferredStackId,
- supervisor.getStack(DOCKED_STACK_ID) != null), DEFAULT_DISPLAY, stackId);
+ final boolean inSplitScreenMode = supervisor.getDefaultDisplay().hasSplitScreenStack();
+ supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(),
+ DEFAULT_DISPLAY, stackId);
- boolean successful = (preferredStackId == stackId);
- if (successful && stackId == DOCKED_STACK_ID) {
+ boolean successful = (preferredStack == toStack);
+ if (successful && toStack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
// If task moved to docked stack - show recents if needed.
mService.mWindowManager.showRecentApps(false /* fromHome */);
}
@@ -941,8 +947,8 @@
mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.taskId;
}
- ActivityStack getStack() {
- return mStack;
+ <T extends ActivityStack> T getStack() {
+ return (T) mStack;
}
/**
@@ -1457,10 +1463,12 @@
return isResizeable(true /* checkSupportsPip */);
}
- boolean supportsSplitScreen() {
+ @Override
+ public boolean supportsSplitScreenWindowingMode() {
// A task can not be docked even if it is considered resizeable because it only supports
// picture-in-picture mode but has a non-resizeable resizeMode
- return mService.mSupportsSplitScreenMultiWindow
+ return super.supportsSplitScreenWindowingMode()
+ && mService.mSupportsSplitScreenMultiWindow
&& (mService.mForceResizableActivities
|| (isResizeable(false /* checkSupportsPip */)
&& !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
@@ -2101,12 +2109,10 @@
return null;
}
- final int stackId = mStack.mStackId;
- if (stackId == HOME_STACK_ID
- || stackId == RECENTS_STACK_ID
- || stackId == ASSISTANT_STACK_ID
- || stackId == FULLSCREEN_WORKSPACE_STACK_ID
- || (stackId == DOCKED_STACK_ID && !isResizeable())) {
+ final int windowingMode = getWindowingMode();
+ if (!isActivityTypeStandardOrUndefined()
+ || windowingMode == WINDOWING_MODE_FULLSCREEN
+ || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) {
return isResizeable() ? mStack.mBounds : null;
} else if (!getWindowConfiguration().persistTaskBounds()) {
return mStack.mBounds;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index f2e2942..055c9f6 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -103,11 +103,30 @@
/**
* Helper class for {@link ActivityManagerService} responsible for multi-user functionality.
+ *
+ * <p>This class use {@link #mLock} to synchronize access to internal state. Methods that require
+ * {@link #mLock} to be held should have "LU" suffix in the name.
+ *
+ * <p><strong>Important:</strong> Synchronized code, i.e. one executed inside a synchronized(mLock)
+ * block or inside LU method, should only access internal state of this class or make calls to
+ * other LU methods. Non-LU method calls or calls to external classes are discouraged as they
+ * may cause lock inversion.
*/
class UserController implements Handler.Callback {
private static final String TAG = TAG_WITH_CLASS_NAME ? "UserController" : TAG_AM;
- // Maximum number of users we allow to be running at a time.
+ /**
+ * Maximum number of users we allow to be running at a time, including the system user and
+ * its profiles.
+ * Note changing this to 2 is not recommended, since that would mean, if the user uses
+ * work profile and then switch to a secondary user, then the work profile user would be killed,
+ * which should work fine, but aggressively killing the work profile user that has just been
+ * running could cause data loss. (Even without work profile, witching from secondary user A
+ * to secondary user B would cause similar issues on user B.)
+ *
+ * TODO: Consider adding or replacing with "MAX_RUNNING_*SECONDARY*_USERS", which is the max
+ * number of running *secondary, switchable* users.
+ */
static final int MAX_RUNNING_USERS = 3;
// Amount of time we wait for observers to handle a user switch before
@@ -136,7 +155,9 @@
// when it never calls back.
private static final int USER_SWITCH_CALLBACKS_TIMEOUT_MS = 5 * 1000;
- private final Object mLock;
+ // Lock for internal state.
+ private final Object mLock = new Object();
+
private final Injector mInjector;
private final Handler mHandler;
private final Handler mUiHandler;
@@ -175,7 +196,8 @@
/**
* Mapping from each known user ID to the profile group ID it is associated with.
*/
- private final SparseIntArray mUserProfileGroupIdsSelfLocked = new SparseIntArray();
+ @GuardedBy("mLock")
+ private final SparseIntArray mUserProfileGroupIds = new SparseIntArray();
/**
* Registered observers of the user switching mechanics.
@@ -206,7 +228,6 @@
@VisibleForTesting
UserController(Injector injector) {
mInjector = injector;
- mLock = injector.getLock();
mHandler = mInjector.getHandler(this);
mUiHandler = mInjector.getUiHandler(this);
// User 0 is the first and only user that runs at boot.
@@ -214,19 +235,18 @@
mStartedUsers.put(UserHandle.USER_SYSTEM, uss);
mUserLru.add(UserHandle.USER_SYSTEM);
mLockPatternUtils = mInjector.getLockPatternUtils();
- updateStartedUserArrayLocked();
+ updateStartedUserArrayLU();
}
void finishUserSwitch(UserState uss) {
+ finishUserBoot(uss);
+ startProfiles();
synchronized (mLock) {
- finishUserBoot(uss);
-
- startProfilesLocked();
- stopRunningUsersLocked(MAX_RUNNING_USERS);
+ stopRunningUsersLU(MAX_RUNNING_USERS);
}
}
- void stopRunningUsersLocked(int maxRunningUsers) {
+ void stopRunningUsersLU(int maxRunningUsers) {
int num = mUserLru.size();
int i = 0;
while (num > maxRunningUsers && i < mUserLru.size()) {
@@ -255,7 +275,7 @@
continue;
}
// This is a user to be stopped.
- if (stopUsersLocked(oldUserId, false, null) != USER_OP_SUCCESS) {
+ if (stopUsersLU(oldUserId, false, null) != USER_OP_SUCCESS) {
num--;
}
num--;
@@ -273,55 +293,57 @@
Slog.d(TAG, "Finishing user boot " + userId);
synchronized (mLock) {
// Bail if we ended up with a stale user
- if (mStartedUsers.get(userId) != uss) return;
+ if (mStartedUsers.get(userId) != uss) {
+ return;
+ }
+ }
- // We always walk through all the user lifecycle states to send
- // consistent developer events. We step into RUNNING_LOCKED here,
- // but we might immediately step into RUNNING below if the user
- // storage is already unlocked.
- if (uss.setState(STATE_BOOTING, STATE_RUNNING_LOCKED)) {
- mInjector.getUserManagerInternal().setUserState(userId, uss.state);
- // Do not report secondary users, runtime restarts or first boot/upgrade
- if (userId == UserHandle.USER_SYSTEM
- && !mInjector.isRuntimeRestarted() && !mInjector.isFirstBootOrUpgrade()) {
- int uptimeSeconds = (int)(SystemClock.elapsedRealtime() / 1000);
- MetricsLogger.histogram(mInjector.getContext(),
- "framework_locked_boot_completed", uptimeSeconds);
- final int MAX_UPTIME_SECONDS = 120;
- if (uptimeSeconds > MAX_UPTIME_SECONDS) {
- Slog.wtf("SystemServerTiming",
- "finishUserBoot took too long. uptimeSeconds=" + uptimeSeconds);
- }
+ // We always walk through all the user lifecycle states to send
+ // consistent developer events. We step into RUNNING_LOCKED here,
+ // but we might immediately step into RUNNING below if the user
+ // storage is already unlocked.
+ if (uss.setState(STATE_BOOTING, STATE_RUNNING_LOCKED)) {
+ mInjector.getUserManagerInternal().setUserState(userId, uss.state);
+ // Do not report secondary users, runtime restarts or first boot/upgrade
+ if (userId == UserHandle.USER_SYSTEM
+ && !mInjector.isRuntimeRestarted() && !mInjector.isFirstBootOrUpgrade()) {
+ int uptimeSeconds = (int)(SystemClock.elapsedRealtime() / 1000);
+ MetricsLogger.histogram(mInjector.getContext(),
+ "framework_locked_boot_completed", uptimeSeconds);
+ final int MAX_UPTIME_SECONDS = 120;
+ if (uptimeSeconds > MAX_UPTIME_SECONDS) {
+ Slog.wtf("SystemServerTiming",
+ "finishUserBoot took too long. uptimeSeconds=" + uptimeSeconds);
}
-
- mHandler.sendMessage(mHandler.obtainMessage(REPORT_LOCKED_BOOT_COMPLETE_MSG,
- userId, 0));
- Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
- | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- mInjector.broadcastIntentLocked(intent, null, resultTo, 0, null, null,
- new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED },
- AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
}
- // We need to delay unlocking managed profiles until the parent user
- // is also unlocked.
- if (mInjector.getUserManager().isManagedProfile(userId)) {
- final UserInfo parent = mInjector.getUserManager().getProfileParent(userId);
- if (parent != null
- && isUserRunningLocked(parent.id, ActivityManager.FLAG_AND_UNLOCKED)) {
- Slog.d(TAG, "User " + userId + " (parent " + parent.id
- + "): attempting unlock because parent is unlocked");
- maybeUnlockUser(userId);
- } else {
- String parentId = (parent == null) ? "<null>" : String.valueOf(parent.id);
- Slog.d(TAG, "User " + userId + " (parent " + parentId
- + "): delaying unlock because parent is locked");
- }
- } else {
+ mHandler.sendMessage(mHandler.obtainMessage(REPORT_LOCKED_BOOT_COMPLETE_MSG,
+ userId, 0));
+ Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ mInjector.broadcastIntent(intent, null, resultTo, 0, null, null,
+ new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
+ AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
+ }
+
+ // We need to delay unlocking managed profiles until the parent user
+ // is also unlocked.
+ if (mInjector.getUserManager().isManagedProfile(userId)) {
+ final UserInfo parent = mInjector.getUserManager().getProfileParent(userId);
+ if (parent != null
+ && isUserRunning(parent.id, ActivityManager.FLAG_AND_UNLOCKED)) {
+ Slog.d(TAG, "User " + userId + " (parent " + parent.id
+ + "): attempting unlock because parent is unlocked");
maybeUnlockUser(userId);
+ } else {
+ String parentId = (parent == null) ? "<null>" : String.valueOf(parent.id);
+ Slog.d(TAG, "User " + userId + " (parent " + parentId
+ + "): delaying unlock because parent is locked");
}
+ } else {
+ maybeUnlockUser(userId);
}
}
@@ -331,34 +353,30 @@
*/
private void finishUserUnlocking(final UserState uss) {
final int userId = uss.mHandle.getIdentifier();
- boolean proceedWithUnlock = false;
+ // Only keep marching forward if user is actually unlocked
+ if (!StorageManager.isUserKeyUnlocked(userId)) return;
synchronized (mLock) {
// Bail if we ended up with a stale user
if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
- // Only keep marching forward if user is actually unlocked
- if (!StorageManager.isUserKeyUnlocked(userId)) return;
-
- if (uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) {
- mInjector.getUserManagerInternal().setUserState(userId, uss.state);
- proceedWithUnlock = true;
+ // Do not proceed if unexpected state
+ if (!uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) {
+ return;
}
}
+ mInjector.getUserManagerInternal().setUserState(userId, uss.state);
+ uss.mUnlockProgress.start();
- if (proceedWithUnlock) {
- uss.mUnlockProgress.start();
+ // Prepare app storage before we go any further
+ uss.mUnlockProgress.setProgress(5,
+ mInjector.getContext().getString(R.string.android_start_title));
+ mInjector.getUserManager().onBeforeUnlockUser(userId);
+ uss.mUnlockProgress.setProgress(20);
- // Prepare app storage before we go any further
- uss.mUnlockProgress.setProgress(5,
- mInjector.getContext().getString(R.string.android_start_title));
- mInjector.getUserManager().onBeforeUnlockUser(userId);
- uss.mUnlockProgress.setProgress(20);
-
- // Dispatch unlocked to system services; when fully dispatched,
- // that calls through to the next "unlocked" phase
- mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
- .sendToTarget();
- }
+ // Dispatch unlocked to system services; when fully dispatched,
+ // that calls through to the next "unlocked" phase
+ mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
+ .sendToTarget();
}
/**
@@ -367,64 +385,64 @@
*/
void finishUserUnlocked(final UserState uss) {
final int userId = uss.mHandle.getIdentifier();
+ // Only keep marching forward if user is actually unlocked
+ if (!StorageManager.isUserKeyUnlocked(userId)) return;
synchronized (mLock) {
// Bail if we ended up with a stale user
if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
- // Only keep marching forward if user is actually unlocked
- if (!StorageManager.isUserKeyUnlocked(userId)) return;
-
- if (uss.setState(STATE_RUNNING_UNLOCKING, STATE_RUNNING_UNLOCKED)) {
- mInjector.getUserManagerInternal().setUserState(userId, uss.state);
- uss.mUnlockProgress.finish();
-
- // Dispatch unlocked to external apps
- final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
- unlockedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- unlockedIntent.addFlags(
- Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
- mInjector.broadcastIntentLocked(unlockedIntent, null, null, 0, null,
- null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- userId);
-
- if (getUserInfo(userId).isManagedProfile()) {
- UserInfo parent = mInjector.getUserManager().getProfileParent(userId);
- if (parent != null) {
- final Intent profileUnlockedIntent = new Intent(
- Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
- profileUnlockedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
- profileUnlockedIntent.addFlags(
- Intent.FLAG_RECEIVER_REGISTERED_ONLY
- | Intent.FLAG_RECEIVER_FOREGROUND);
- mInjector.broadcastIntentLocked(profileUnlockedIntent,
- null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID,
- parent.id);
- }
- }
-
- // Send PRE_BOOT broadcasts if user fingerprint changed; we
- // purposefully block sending BOOT_COMPLETED until after all
- // PRE_BOOT receivers are finished to avoid ANR'ing apps
- final UserInfo info = getUserInfo(userId);
- if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)) {
- // Suppress double notifications for managed profiles that
- // were unlocked automatically as part of their parent user
- // being unlocked.
- final boolean quiet;
- if (info.isManagedProfile()) {
- quiet = !uss.tokenProvided
- || !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
- } else {
- quiet = false;
- }
- mInjector.sendPreBootBroadcast(userId, quiet,
- () -> finishUserUnlockedCompleted(uss));
- } else {
- finishUserUnlockedCompleted(uss);
- }
+ // Do not proceed if unexpected state
+ if (!uss.setState(STATE_RUNNING_UNLOCKING, STATE_RUNNING_UNLOCKED)) {
+ return;
}
}
+ mInjector.getUserManagerInternal().setUserState(userId, uss.state);
+ uss.mUnlockProgress.finish();
+ // Dispatch unlocked to external apps
+ final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
+ unlockedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ unlockedIntent.addFlags(
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
+ mInjector.broadcastIntent(unlockedIntent, null, null, 0, null,
+ null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ userId);
+
+ if (getUserInfo(userId).isManagedProfile()) {
+ UserInfo parent = mInjector.getUserManager().getProfileParent(userId);
+ if (parent != null) {
+ final Intent profileUnlockedIntent = new Intent(
+ Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
+ profileUnlockedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
+ profileUnlockedIntent.addFlags(
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ mInjector.broadcastIntent(profileUnlockedIntent,
+ null, null, 0, null, null, null, AppOpsManager.OP_NONE,
+ null, false, false, MY_PID, SYSTEM_UID,
+ parent.id);
+ }
+ }
+
+ // Send PRE_BOOT broadcasts if user fingerprint changed; we
+ // purposefully block sending BOOT_COMPLETED until after all
+ // PRE_BOOT receivers are finished to avoid ANR'ing apps
+ final UserInfo info = getUserInfo(userId);
+ if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)) {
+ // Suppress double notifications for managed profiles that
+ // were unlocked automatically as part of their parent user
+ // being unlocked.
+ final boolean quiet;
+ if (info.isManagedProfile()) {
+ quiet = !uss.tokenProvided
+ || !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
+ } else {
+ quiet = false;
+ }
+ mInjector.sendPreBootBroadcast(userId, quiet,
+ () -> finishUserUnlockedCompleted(uss));
+ } else {
+ finishUserUnlockedCompleted(uss);
+ }
}
private void finishUserUnlockedCompleted(UserState uss) {
@@ -432,60 +450,59 @@
synchronized (mLock) {
// Bail if we ended up with a stale user
if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
- final UserInfo userInfo = getUserInfo(userId);
- if (userInfo == null) {
- return;
- }
-
- // Only keep marching forward if user is actually unlocked
- if (!StorageManager.isUserKeyUnlocked(userId)) return;
-
- // Remember that we logged in
- mInjector.getUserManager().onUserLoggedIn(userId);
-
- if (!userInfo.isInitialized()) {
- if (userId != UserHandle.USER_SYSTEM) {
- Slog.d(TAG, "Initializing user #" + userId);
- Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
- | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- mInjector.broadcastIntentLocked(intent, null,
- new IIntentReceiver.Stub() {
- @Override
- public void performReceive(Intent intent, int resultCode,
- String data, Bundle extras, boolean ordered,
- boolean sticky, int sendingUser) {
- // Note: performReceive is called with mService lock held
- mInjector.getUserManager().makeInitialized(userInfo.id);
- }
- }, 0, null, null, null, AppOpsManager.OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, userId);
- }
- }
-
- Slog.i(TAG, "Sending BOOT_COMPLETE user #" + userId);
- // Do not report secondary users, runtime restarts or first boot/upgrade
- if (userId == UserHandle.USER_SYSTEM
- && !mInjector.isRuntimeRestarted() && !mInjector.isFirstBootOrUpgrade()) {
- int uptimeSeconds = (int) (SystemClock.elapsedRealtime() / 1000);
- MetricsLogger.histogram(mInjector.getContext(), "framework_boot_completed",
- uptimeSeconds);
- }
- final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
- bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
- | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- mInjector.broadcastIntentLocked(bootIntent, null, new IIntentReceiver.Stub() {
- @Override
- public void performReceive(Intent intent, int resultCode, String data,
- Bundle extras, boolean ordered, boolean sticky, int sendingUser)
- throws RemoteException {
- Slog.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u" + userId);
- }
- }, 0, null, null,
- new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED },
- AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
}
+ UserInfo userInfo = getUserInfo(userId);
+ if (userInfo == null) {
+ return;
+ }
+ // Only keep marching forward if user is actually unlocked
+ if (!StorageManager.isUserKeyUnlocked(userId)) return;
+
+ // Remember that we logged in
+ mInjector.getUserManager().onUserLoggedIn(userId);
+
+ if (!userInfo.isInitialized()) {
+ if (userId != UserHandle.USER_SYSTEM) {
+ Slog.d(TAG, "Initializing user #" + userId);
+ Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ mInjector.broadcastIntent(intent, null,
+ new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode,
+ String data, Bundle extras, boolean ordered,
+ boolean sticky, int sendingUser) {
+ // Note: performReceive is called with mService lock held
+ mInjector.getUserManager().makeInitialized(userInfo.id);
+ }
+ }, 0, null, null, null, AppOpsManager.OP_NONE,
+ null, true, false, MY_PID, SYSTEM_UID, userId);
+ }
+ }
+
+ Slog.i(TAG, "Sending BOOT_COMPLETE user #" + userId);
+ // Do not report secondary users, runtime restarts or first boot/upgrade
+ if (userId == UserHandle.USER_SYSTEM
+ && !mInjector.isRuntimeRestarted() && !mInjector.isFirstBootOrUpgrade()) {
+ int uptimeSeconds = (int) (SystemClock.elapsedRealtime() / 1000);
+ MetricsLogger.histogram(mInjector.getContext(), "framework_boot_completed",
+ uptimeSeconds);
+ }
+ final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
+ bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ mInjector.broadcastIntent(bootIntent, null, new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode, String data,
+ Bundle extras, boolean ordered, boolean sticky, int sendingUser)
+ throws RemoteException {
+ Slog.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u" + userId);
+ }
+ }, 0, null, null,
+ new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
+ AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
}
int restartUser(final int userId, final boolean foreground) {
@@ -516,33 +533,33 @@
}
enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userId);
synchronized (mLock) {
- return stopUsersLocked(userId, force, callback);
+ return stopUsersLU(userId, force, callback);
}
}
/**
* Stops the user along with its related users. The method calls
- * {@link #getUsersToStopLocked(int)} to determine the list of users that should be stopped.
+ * {@link #getUsersToStopLU(int)} to determine the list of users that should be stopped.
*/
- private int stopUsersLocked(final int userId, boolean force, final IStopUserCallback callback) {
+ private int stopUsersLU(final int userId, boolean force, final IStopUserCallback callback) {
if (userId == UserHandle.USER_SYSTEM) {
return USER_OP_ERROR_IS_SYSTEM;
}
- if (isCurrentUserLocked(userId)) {
+ if (isCurrentUserLU(userId)) {
return USER_OP_IS_CURRENT;
}
- int[] usersToStop = getUsersToStopLocked(userId);
+ int[] usersToStop = getUsersToStopLU(userId);
// If one of related users is system or current, no related users should be stopped
for (int i = 0; i < usersToStop.length; i++) {
int relatedUserId = usersToStop[i];
- if ((UserHandle.USER_SYSTEM == relatedUserId) || isCurrentUserLocked(relatedUserId)) {
+ if ((UserHandle.USER_SYSTEM == relatedUserId) || isCurrentUserLU(relatedUserId)) {
if (DEBUG_MU) Slog.i(TAG, "stopUsersLocked cannot stop related user "
+ relatedUserId);
// We still need to stop the requested user if it's a force stop.
if (force) {
Slog.i(TAG,
"Force stop user " + userId + ". Related users will not be stopped");
- stopSingleUserLocked(userId, callback);
+ stopSingleUserLU(userId, callback);
return USER_OP_SUCCESS;
}
return USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
@@ -550,25 +567,22 @@
}
if (DEBUG_MU) Slog.i(TAG, "stopUsersLocked usersToStop=" + Arrays.toString(usersToStop));
for (int userIdToStop : usersToStop) {
- stopSingleUserLocked(userIdToStop, userIdToStop == userId ? callback : null);
+ stopSingleUserLU(userIdToStop, userIdToStop == userId ? callback : null);
}
return USER_OP_SUCCESS;
}
- private void stopSingleUserLocked(final int userId, final IStopUserCallback callback) {
+ private void stopSingleUserLU(final int userId, final IStopUserCallback callback) {
if (DEBUG_MU) Slog.i(TAG, "stopSingleUserLocked userId=" + userId);
final UserState uss = mStartedUsers.get(userId);
if (uss == null) {
// User is not started, nothing to do... but we do need to
// callback if requested.
if (callback != null) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- callback.userStopped(userId);
- } catch (RemoteException e) {
- }
+ mHandler.post(() -> {
+ try {
+ callback.userStopped(userId);
+ } catch (RemoteException e) {
}
});
}
@@ -583,10 +597,10 @@
&& uss.state != UserState.STATE_SHUTDOWN) {
uss.setState(UserState.STATE_STOPPING);
mInjector.getUserManagerInternal().setUserState(userId, uss.state);
- updateStartedUserArrayLocked();
+ updateStartedUserArrayLU();
- long ident = Binder.clearCallingIdentity();
- try {
+ // Post to handler to obtain amLock
+ mHandler.post(() -> {
// We are going to broadcast ACTION_USER_STOPPING and then
// once that is done send a final ACTION_SHUTDOWN and then
// stop the user.
@@ -599,24 +613,18 @@
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- finishUserStopping(userId, uss);
- }
- });
+ mHandler.post(() -> finishUserStopping(userId, uss));
}
};
+
// Clear broadcast queue for the user to avoid delivering stale broadcasts
- mInjector.clearBroadcastQueueForUserLocked(userId);
+ mInjector.clearBroadcastQueueForUser(userId);
// Kick things off.
- mInjector.broadcastIntentLocked(stoppingIntent,
+ mInjector.broadcastIntent(stoppingIntent,
null, stoppingReceiver, 0, null, null,
new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ });
}
}
@@ -652,18 +660,17 @@
Integer.toString(userId), userId);
mInjector.getSystemServiceManager().stopUser(userId);
- synchronized (mLock) {
- mInjector.broadcastIntentLocked(shutdownIntent,
- null, shutdownReceiver, 0, null, null, null,
- AppOpsManager.OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, userId);
- }
+ mInjector.broadcastIntent(shutdownIntent,
+ null, shutdownReceiver, 0, null, null, null,
+ AppOpsManager.OP_NONE,
+ null, true, false, MY_PID, SYSTEM_UID, userId);
}
void finishUserStopped(UserState uss) {
final int userId = uss.mHandle.getIdentifier();
boolean stopped;
ArrayList<IStopUserCallback> callbacks;
+ boolean forceStopUser = false;
synchronized (mLock) {
callbacks = new ArrayList<>(uss.mStopCallbacks);
if (mStartedUsers.get(userId) != uss) {
@@ -674,16 +681,18 @@
stopped = true;
// User can no longer run.
mStartedUsers.remove(userId);
- mInjector.getUserManagerInternal().removeUserState(userId);
mUserLru.remove(Integer.valueOf(userId));
- updateStartedUserArrayLocked();
-
- mInjector.activityManagerOnUserStopped(userId);
- // Clean up all state and processes associated with the user.
- // Kill all the processes for the user.
- forceStopUserLocked(userId, "finish user");
+ updateStartedUserArrayLU();
+ forceStopUser = true;
}
}
+ if (forceStopUser) {
+ mInjector.getUserManagerInternal().removeUserState(userId);
+ mInjector.activityManagerOnUserStopped(userId);
+ // Clean up all state and processes associated with the user.
+ // Kill all the processes for the user.
+ forceStopUser(userId, "finish user");
+ }
for (int i = 0; i < callbacks.size(); i++) {
try {
@@ -695,9 +704,7 @@
if (stopped) {
mInjector.systemServiceManagerCleanupUser(userId);
- synchronized (mLock) {
- mInjector.getActivityStackSupervisor().removeUserLocked(userId);
- }
+ mInjector.stackSupervisorRemoveUser(userId);
// Remove the user if it is ephemeral.
if (getUserInfo(userId).isEphemeral()) {
mInjector.getUserManager().removeUser(userId);
@@ -715,39 +722,36 @@
* Determines the list of users that should be stopped together with the specified
* {@code userId}. The returned list includes {@code userId}.
*/
- private @NonNull int[] getUsersToStopLocked(int userId) {
+ private @NonNull int[] getUsersToStopLU(int userId) {
int startedUsersSize = mStartedUsers.size();
IntArray userIds = new IntArray();
userIds.add(userId);
- synchronized (mUserProfileGroupIdsSelfLocked) {
- int userGroupId = mUserProfileGroupIdsSelfLocked.get(userId,
+ int userGroupId = mUserProfileGroupIds.get(userId, UserInfo.NO_PROFILE_GROUP_ID);
+ for (int i = 0; i < startedUsersSize; i++) {
+ UserState uss = mStartedUsers.valueAt(i);
+ int startedUserId = uss.mHandle.getIdentifier();
+ // Skip unrelated users (profileGroupId mismatch)
+ int startedUserGroupId = mUserProfileGroupIds.get(startedUserId,
UserInfo.NO_PROFILE_GROUP_ID);
- for (int i = 0; i < startedUsersSize; i++) {
- UserState uss = mStartedUsers.valueAt(i);
- int startedUserId = uss.mHandle.getIdentifier();
- // Skip unrelated users (profileGroupId mismatch)
- int startedUserGroupId = mUserProfileGroupIdsSelfLocked.get(startedUserId,
- UserInfo.NO_PROFILE_GROUP_ID);
- boolean sameGroup = (userGroupId != UserInfo.NO_PROFILE_GROUP_ID)
- && (userGroupId == startedUserGroupId);
- // userId has already been added
- boolean sameUserId = startedUserId == userId;
- if (!sameGroup || sameUserId) {
- continue;
- }
- userIds.add(startedUserId);
+ boolean sameGroup = (userGroupId != UserInfo.NO_PROFILE_GROUP_ID)
+ && (userGroupId == startedUserGroupId);
+ // userId has already been added
+ boolean sameUserId = startedUserId == userId;
+ if (!sameGroup || sameUserId) {
+ continue;
}
+ userIds.add(startedUserId);
}
return userIds.toArray();
}
- private void forceStopUserLocked(int userId, String reason) {
- mInjector.activityManagerForceStopPackageLocked(userId, reason);
+ private void forceStopUser(int userId, String reason) {
+ mInjector.activityManagerForceStopPackage(userId, reason);
Intent intent = new Intent(Intent.ACTION_USER_STOPPED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- mInjector.broadcastIntentLocked(intent,
+ mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
}
@@ -756,6 +760,7 @@
* Stops the guest or ephemeral user if it has gone to the background.
*/
private void stopGuestOrEphemeralUserIfBackground() {
+ IntArray userIds = new IntArray();
synchronized (mLock) {
final int num = mUserLru.size();
for (int i = 0; i < num; i++) {
@@ -766,35 +771,42 @@
|| oldUss.state == UserState.STATE_SHUTDOWN) {
continue;
}
- UserInfo userInfo = getUserInfo(oldUserId);
- if (userInfo.isEphemeral()) {
- LocalServices.getService(UserManagerInternal.class)
- .onEphemeralUserStop(oldUserId);
+ userIds.add(oldUserId);
+ }
+ }
+ final int userIdsSize = userIds.size();
+ for (int i = 0; i < userIdsSize; i++) {
+ int oldUserId = userIds.get(i);
+ UserInfo userInfo = getUserInfo(oldUserId);
+ if (userInfo.isEphemeral()) {
+ LocalServices.getService(UserManagerInternal.class).onEphemeralUserStop(oldUserId);
+ }
+ if (userInfo.isGuest() || userInfo.isEphemeral()) {
+ // This is a user to be stopped.
+ synchronized (mLock) {
+ stopUsersLU(oldUserId, true, null);
}
- if (userInfo.isGuest() || userInfo.isEphemeral()) {
- // This is a user to be stopped.
- stopUsersLocked(oldUserId, true, null);
- break;
- }
+ break;
}
}
}
- void scheduleStartProfilesLocked() {
+ void scheduleStartProfiles() {
if (!mHandler.hasMessages(START_PROFILES_MSG)) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(START_PROFILES_MSG),
DateUtils.SECOND_IN_MILLIS);
}
}
- void startProfilesLocked() {
+ void startProfiles() {
+ int currentUserId = getCurrentUserId();
if (DEBUG_MU) Slog.i(TAG, "startProfilesLocked");
List<UserInfo> profiles = mInjector.getUserManager().getProfiles(
- mCurrentUserId, false /* enabledOnly */);
+ currentUserId, false /* enabledOnly */);
List<UserInfo> profilesToStart = new ArrayList<>(profiles.size());
for (UserInfo user : profiles) {
if ((user.flags & UserInfo.FLAG_INITIALIZED) == UserInfo.FLAG_INITIALIZED
- && user.id != mCurrentUserId && !user.isQuietModeEnabled()) {
+ && user.id != currentUserId && !user.isQuietModeEnabled()) {
profilesToStart.add(user);
}
}
@@ -856,143 +868,156 @@
final long ident = Binder.clearCallingIdentity();
try {
+ final int oldUserId = getCurrentUserId();
+ if (oldUserId == userId) {
+ return true;
+ }
+
+ if (foreground) {
+ // TODO: I don't think this does what the caller think it does. Seems to only
+ // remove one locked task and won't work if multiple locked tasks are present.
+ mInjector.clearLockTaskMode("startUser");
+ }
+
+ final UserInfo userInfo = getUserInfo(userId);
+ if (userInfo == null) {
+ Slog.w(TAG, "No user info for user #" + userId);
+ return false;
+ }
+ if (foreground && userInfo.isManagedProfile()) {
+ Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
+ return false;
+ }
+
+ if (foreground && mUserSwitchUiEnabled) {
+ mInjector.getWindowManager().startFreezingScreen(
+ R.anim.screen_user_exit, R.anim.screen_user_enter);
+ }
+
+ boolean needStart = false;
+ boolean updateUmState = false;
+ UserState uss;
+
+ // If the user we are switching to is not currently started, then
+ // we need to start it now.
synchronized (mLock) {
- final int oldUserId = mCurrentUserId;
- if (oldUserId == userId) {
- return true;
- }
-
- if (foreground) {
- // TODO: I don't think this does what the caller think it does. Seems to only
- // remove one locked task and won't work if multiple locked tasks are present.
- mInjector.getLockTaskController().clearLockTaskMode("startUser");
- }
-
- final UserInfo userInfo = getUserInfo(userId);
- if (userInfo == null) {
- Slog.w(TAG, "No user info for user #" + userId);
- return false;
- }
- if (foreground && userInfo.isManagedProfile()) {
- Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
- return false;
- }
-
- if (foreground && mUserSwitchUiEnabled) {
- mInjector.getWindowManager().startFreezingScreen(
- R.anim.screen_user_exit, R.anim.screen_user_enter);
- }
-
- boolean needStart = false;
-
- // If the user we are switching to is not currently started, then
- // we need to start it now.
- if (mStartedUsers.get(userId) == null) {
- UserState userState = new UserState(UserHandle.of(userId));
- mStartedUsers.put(userId, userState);
- mInjector.getUserManagerInternal().setUserState(userId, userState.state);
- updateStartedUserArrayLocked();
+ uss = mStartedUsers.get(userId);
+ if (uss == null) {
+ uss = new UserState(UserHandle.of(userId));
+ mStartedUsers.put(userId, uss);
+ updateStartedUserArrayLU();
needStart = true;
+ updateUmState = true;
}
-
- final UserState uss = mStartedUsers.get(userId);
final Integer userIdInt = userId;
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
-
- if (foreground) {
+ }
+ if (updateUmState) {
+ mInjector.getUserManagerInternal().setUserState(userId, uss.state);
+ }
+ if (foreground) {
+ synchronized (mLock) {
mCurrentUserId = userId;
- mInjector.updateUserConfigurationLocked();
mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
- updateCurrentProfileIdsLocked();
- mInjector.getWindowManager().setCurrentUser(userId, mCurrentProfileIds);
- // Once the internal notion of the active user has switched, we lock the device
- // with the option to show the user switcher on the keyguard.
- if (mUserSwitchUiEnabled) {
- mInjector.getWindowManager().setSwitchingUser(true);
- mInjector.getWindowManager().lockNow(null);
- }
- } else {
- final Integer currentUserIdInt = mCurrentUserId;
- updateCurrentProfileIdsLocked();
- mInjector.getWindowManager().setCurrentProfileIds(mCurrentProfileIds);
+ }
+ mInjector.updateUserConfiguration();
+ updateCurrentProfileIds();
+ mInjector.getWindowManager().setCurrentUser(userId, getCurrentProfileIds());
+ // Once the internal notion of the active user has switched, we lock the device
+ // with the option to show the user switcher on the keyguard.
+ if (mUserSwitchUiEnabled) {
+ mInjector.getWindowManager().setSwitchingUser(true);
+ mInjector.getWindowManager().lockNow(null);
+ }
+ } else {
+ final Integer currentUserIdInt = mCurrentUserId;
+ updateCurrentProfileIds();
+ mInjector.getWindowManager().setCurrentProfileIds(getCurrentProfileIds());
+ synchronized (mLock) {
mUserLru.remove(currentUserIdInt);
mUserLru.add(currentUserIdInt);
}
+ }
- // Make sure user is in the started state. If it is currently
- // stopping, we need to knock that off.
- if (uss.state == UserState.STATE_STOPPING) {
- // If we are stopping, we haven't sent ACTION_SHUTDOWN,
- // so we can just fairly silently bring the user back from
- // the almost-dead.
- uss.setState(uss.lastState);
- mInjector.getUserManagerInternal().setUserState(userId, uss.state);
- updateStartedUserArrayLocked();
- needStart = true;
- } else if (uss.state == UserState.STATE_SHUTDOWN) {
- // This means ACTION_SHUTDOWN has been sent, so we will
- // need to treat this as a new boot of the user.
- uss.setState(UserState.STATE_BOOTING);
- mInjector.getUserManagerInternal().setUserState(userId, uss.state);
- updateStartedUserArrayLocked();
- needStart = true;
+ // Make sure user is in the started state. If it is currently
+ // stopping, we need to knock that off.
+ if (uss.state == UserState.STATE_STOPPING) {
+ // If we are stopping, we haven't sent ACTION_SHUTDOWN,
+ // so we can just fairly silently bring the user back from
+ // the almost-dead.
+ uss.setState(uss.lastState);
+ mInjector.getUserManagerInternal().setUserState(userId, uss.state);
+ synchronized (mLock) {
+ updateStartedUserArrayLU();
}
-
- if (uss.state == UserState.STATE_BOOTING) {
- // Give user manager a chance to propagate user restrictions
- // to other services and prepare app storage
- mInjector.getUserManager().onBeforeStartUser(userId);
-
- // Booting up a new user, need to tell system services about it.
- // Note that this is on the same handler as scheduling of broadcasts,
- // which is important because it needs to go first.
- mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId, 0));
+ needStart = true;
+ } else if (uss.state == UserState.STATE_SHUTDOWN) {
+ // This means ACTION_SHUTDOWN has been sent, so we will
+ // need to treat this as a new boot of the user.
+ uss.setState(UserState.STATE_BOOTING);
+ mInjector.getUserManagerInternal().setUserState(userId, uss.state);
+ synchronized (mLock) {
+ updateStartedUserArrayLU();
}
+ needStart = true;
+ }
- if (foreground) {
- mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId,
- oldUserId));
- mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
- mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
- mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
- oldUserId, userId, uss));
- mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
- oldUserId, userId, uss), USER_SWITCH_TIMEOUT_MS);
- }
+ if (uss.state == UserState.STATE_BOOTING) {
+ // Give user manager a chance to propagate user restrictions
+ // to other services and prepare app storage
+ mInjector.getUserManager().onBeforeStartUser(userId);
- if (needStart) {
- // Send USER_STARTED broadcast
- Intent intent = new Intent(Intent.ACTION_USER_STARTED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
- | Intent.FLAG_RECEIVER_FOREGROUND);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- mInjector.broadcastIntentLocked(intent,
- null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, userId);
- }
+ // Booting up a new user, need to tell system services about it.
+ // Note that this is on the same handler as scheduling of broadcasts,
+ // which is important because it needs to go first.
+ mHandler.sendMessage(
+ mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId, 0));
+ }
- if (foreground) {
- moveUserToForegroundLocked(uss, oldUserId, userId);
- } else {
- finishUserBoot(uss);
- }
+ if (foreground) {
+ mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId,
+ oldUserId));
+ mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
+ mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
+ mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
+ oldUserId, userId, uss));
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
+ oldUserId, userId, uss), USER_SWITCH_TIMEOUT_MS);
+ }
- if (needStart) {
- Intent intent = new Intent(Intent.ACTION_USER_STARTING);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- mInjector.broadcastIntentLocked(intent,
- null, new IIntentReceiver.Stub() {
- @Override
- public void performReceive(Intent intent, int resultCode,
- String data, Bundle extras, boolean ordered, boolean sticky,
- int sendingUser) throws RemoteException {
- }
- }, 0, null, null,
- new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
- }
+ if (needStart) {
+ // Send USER_STARTED broadcast
+ Intent intent = new Intent(Intent.ACTION_USER_STARTED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ mInjector.broadcastIntent(intent,
+ null, null, 0, null, null, null, AppOpsManager.OP_NONE,
+ null, false, false, MY_PID, SYSTEM_UID, userId);
+ }
+
+ if (foreground) {
+ moveUserToForeground(uss, oldUserId, userId);
+ } else {
+ finishUserBoot(uss);
+ }
+
+ if (needStart) {
+ Intent intent = new Intent(Intent.ACTION_USER_STARTING);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ mInjector.broadcastIntent(intent,
+ null, new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode,
+ String data, Bundle extras, boolean ordered,
+ boolean sticky,
+ int sendingUser) throws RemoteException {
+ }
+ }, 0, null, null,
+ new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
+ null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -1036,7 +1061,7 @@
* when the the credential-encrypted storage isn't tied to a user-provided
* PIN or pattern.
*/
- boolean maybeUnlockUser(final int userId) {
+ private boolean maybeUnlockUser(final int userId) {
// Try unlocking storage using empty token
return unlockUserCleared(userId, null, null, null);
}
@@ -1049,54 +1074,53 @@
}
}
- boolean unlockUserCleared(final int userId, byte[] token, byte[] secret,
+ private boolean unlockUserCleared(final int userId, byte[] token, byte[] secret,
IProgressListener listener) {
UserState uss;
- synchronized (mLock) {
- // TODO Move this block outside of synchronized if it causes lock contention
- if (!StorageManager.isUserKeyUnlocked(userId)) {
- final UserInfo userInfo = getUserInfo(userId);
- final IStorageManager storageManager = getStorageManager();
- try {
- // We always want to unlock user storage, even user is not started yet
- storageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret);
- } catch (RemoteException | RuntimeException e) {
- Slog.w(TAG, "Failed to unlock: " + e.getMessage());
- }
+ if (!StorageManager.isUserKeyUnlocked(userId)) {
+ final UserInfo userInfo = getUserInfo(userId);
+ final IStorageManager storageManager = getStorageManager();
+ try {
+ // We always want to unlock user storage, even user is not started yet
+ storageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret);
+ } catch (RemoteException | RuntimeException e) {
+ Slog.w(TAG, "Failed to unlock: " + e.getMessage());
}
- // Bail if user isn't actually running, otherwise register the given
- // listener to watch for unlock progress
+ }
+ synchronized (mLock) {
+ // Register the given listener to watch for unlock progress
uss = mStartedUsers.get(userId);
- if (uss == null) {
- notifyFinished(userId, listener);
- return false;
- } else {
+ if (uss != null) {
uss.mUnlockProgress.addListener(listener);
uss.tokenProvided = (token != null);
}
}
+ // Bail if user isn't actually running
+ if (uss == null) {
+ notifyFinished(userId, listener);
+ return false;
+ }
finishUserUnlocking(uss);
- final ArraySet<Integer> childProfilesToUnlock = new ArraySet<>();
- synchronized (mLock) {
+ // We just unlocked a user, so let's now attempt to unlock any
+ // managed profiles under that user.
- // We just unlocked a user, so let's now attempt to unlock any
- // managed profiles under that user.
- for (int i = 0; i < mStartedUsers.size(); i++) {
- final int testUserId = mStartedUsers.keyAt(i);
- final UserInfo parent = mInjector.getUserManager().getProfileParent(testUserId);
- if (parent != null && parent.id == userId && testUserId != userId) {
- Slog.d(TAG, "User " + testUserId + " (parent " + parent.id
- + "): attempting unlock because parent was just unlocked");
- childProfilesToUnlock.add(testUserId);
- }
+ // First, get list of userIds. Requires mLock, so we cannot make external calls, e.g. to UMS
+ int[] userIds;
+ synchronized (mLock) {
+ userIds = new int[mStartedUsers.size()];
+ for (int i = 0; i < userIds.length; i++) {
+ userIds[i] = mStartedUsers.keyAt(i);
}
}
-
- final int size = childProfilesToUnlock.size();
- for (int i = 0; i < size; i++) {
- maybeUnlockUser(childProfilesToUnlock.valueAt(i));
+ for (int testUserId : userIds) {
+ final UserInfo parent = mInjector.getUserManager().getProfileParent(testUserId);
+ if (parent != null && parent.id == userId && testUserId != userId) {
+ Slog.d(TAG, "User " + testUserId + " (parent " + parent.id
+ + "): attempting unlock because parent was just unlocked");
+ maybeUnlockUser(testUserId);
+ }
}
return true;
@@ -1104,33 +1128,31 @@
boolean switchUser(final int targetUserId) {
enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, targetUserId);
- int currentUserId;
- UserInfo targetUserInfo;
+ int currentUserId = getCurrentUserId();
+ UserInfo targetUserInfo = getUserInfo(targetUserId);
+ if (targetUserId == currentUserId) {
+ Slog.i(TAG, "user #" + targetUserId + " is already the current user");
+ return true;
+ }
+ if (targetUserInfo == null) {
+ Slog.w(TAG, "No user info for user #" + targetUserId);
+ return false;
+ }
+ if (!targetUserInfo.isDemo() && UserManager.isDeviceInDemoMode(mInjector.getContext())) {
+ Slog.w(TAG, "Cannot switch to non-demo user #" + targetUserId
+ + " when device is in demo mode");
+ return false;
+ }
+ if (!targetUserInfo.supportsSwitchTo()) {
+ Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not supported");
+ return false;
+ }
+ if (targetUserInfo.isManagedProfile()) {
+ Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not a full user");
+ return false;
+ }
synchronized (mLock) {
- currentUserId = getCurrentUserIdLocked();
- targetUserInfo = getUserInfo(targetUserId);
- if (targetUserId == currentUserId) {
- Slog.i(TAG, "user #" + targetUserId + " is already the current user");
- return true;
- }
- if (targetUserInfo == null) {
- Slog.w(TAG, "No user info for user #" + targetUserId);
- return false;
- }
- if (!targetUserInfo.isDemo() && UserManager.isDeviceInDemoMode(mInjector.getContext())) {
- Slog.w(TAG, "Cannot switch to non-demo user #" + targetUserId
- + " when device is in demo mode");
- return false;
- }
- if (!targetUserInfo.supportsSwitchTo()) {
- Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not supported");
- return false;
- }
- if (targetUserInfo.isManagedProfile()) {
- Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not a full user");
- return false;
- }
- setTargetUserIdLocked(targetUserId);
+ mTargetUserId = targetUserId;
}
if (mUserSwitchUiEnabled) {
UserInfo currentUserInfo = getUserInfo(currentUserId);
@@ -1146,12 +1168,12 @@
return true;
}
- void showUserSwitchDialog(Pair<UserInfo, UserInfo> fromToUserPair) {
+ private void showUserSwitchDialog(Pair<UserInfo, UserInfo> fromToUserPair) {
// The dialog will show and then initiate the user switch by calling startUserInForeground
mInjector.showUserSwitchingDialog(fromToUserPair.first, fromToUserPair.second);
}
- void dispatchForegroundProfileChanged(int userId) {
+ private void dispatchForegroundProfileChanged(int userId) {
final int observerCount = mUserSwitchObservers.beginBroadcast();
for (int i = 0; i < observerCount; i++) {
try {
@@ -1176,7 +1198,7 @@
mUserSwitchObservers.finishBroadcast();
}
- void dispatchLockedBootComplete(int userId) {
+ private void dispatchLockedBootComplete(int userId) {
final int observerCount = mUserSwitchObservers.beginBroadcast();
for (int i = 0; i < observerCount; i++) {
try {
@@ -1202,23 +1224,23 @@
synchronized (mLock) {
if (DEBUG_MU) Slog.i(TAG, "stopBackgroundUsersIfEnforced stopping " + oldUserId
+ " and related users");
- stopUsersLocked(oldUserId, false, null);
+ stopUsersLU(oldUserId, false, null);
}
}
- void timeoutUserSwitch(UserState uss, int oldUserId, int newUserId) {
+ private void timeoutUserSwitch(UserState uss, int oldUserId, int newUserId) {
synchronized (mLock) {
Slog.e(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);
mTimeoutUserSwitchCallbacks = mCurWaitingUserSwitchCallbacks;
mHandler.removeMessages(USER_SWITCH_CALLBACKS_TIMEOUT_MSG);
- sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
+ sendContinueUserSwitchLU(uss, oldUserId, newUserId);
// Report observers that never called back (USER_SWITCH_CALLBACKS_TIMEOUT)
mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_CALLBACKS_TIMEOUT_MSG,
oldUserId, newUserId), USER_SWITCH_CALLBACKS_TIMEOUT_MS);
}
}
- void timeoutUserSwitchCallbacks(int oldUserId, int newUserId) {
+ private void timeoutUserSwitchCallbacks(int oldUserId, int newUserId) {
synchronized (mLock) {
if (mTimeoutUserSwitchCallbacks != null && !mTimeoutUserSwitchCallbacks.isEmpty()) {
Slog.wtf(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId
@@ -1261,7 +1283,7 @@
if (waitingCallbacksCount.decrementAndGet() == 0
&& (curWaitingUserSwitchCallbacks
== mCurWaitingUserSwitchCallbacks)) {
- sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
+ sendContinueUserSwitchLU(uss, oldUserId, newUserId);
}
}
}
@@ -1272,13 +1294,13 @@
}
} else {
synchronized (mLock) {
- sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
+ sendContinueUserSwitchLU(uss, oldUserId, newUserId);
}
}
mUserSwitchObservers.finishBroadcast();
}
- void sendContinueUserSwitchLocked(UserState uss, int oldUserId, int newUserId) {
+ void sendContinueUserSwitchLU(UserState uss, int oldUserId, int newUserId) {
mCurWaitingUserSwitchCallbacks = null;
mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
mHandler.sendMessage(mHandler.obtainMessage(CONTINUE_USER_SWITCH_MSG,
@@ -1288,9 +1310,7 @@
void continueUserSwitch(UserState uss, int oldUserId, int newUserId) {
Slog.d(TAG, "Continue user switch oldUser #" + oldUserId + ", newUser #" + newUserId);
if (mUserSwitchUiEnabled) {
- synchronized (mLock) {
- mInjector.getWindowManager().stopFreezingScreen();
- }
+ mInjector.getWindowManager().stopFreezingScreen();
}
uss.switching = false;
mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
@@ -1300,19 +1320,18 @@
stopBackgroundUsersIfEnforced(oldUserId);
}
- void moveUserToForegroundLocked(UserState uss, int oldUserId, int newUserId) {
- boolean homeInFront =
- mInjector.getActivityStackSupervisor().switchUserLocked(newUserId, uss);
+ private void moveUserToForeground(UserState uss, int oldUserId, int newUserId) {
+ boolean homeInFront = mInjector.stackSupervisorSwitchUser(newUserId, uss);
if (homeInFront) {
- mInjector.startHomeActivityLocked(newUserId, "moveUserToForeground");
+ mInjector.startHomeActivity(newUserId, "moveUserToForeground");
} else {
- mInjector.getActivityStackSupervisor().resumeFocusedStackTopActivityLocked();
+ mInjector.stackSupervisorResumeFocusedStackTopActivity();
}
EventLogTags.writeAmSwitchUser(newUserId);
- sendUserSwitchBroadcastsLocked(oldUserId, newUserId);
+ sendUserSwitchBroadcasts(oldUserId, newUserId);
}
- void sendUserSwitchBroadcastsLocked(int oldUserId, int newUserId) {
+ void sendUserSwitchBroadcasts(int oldUserId, int newUserId) {
long ident = Binder.clearCallingIdentity();
try {
Intent intent;
@@ -1326,7 +1345,7 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
- mInjector.broadcastIntentLocked(intent,
+ mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, profileUserId);
}
@@ -1341,7 +1360,7 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
- mInjector.broadcastIntentLocked(intent,
+ mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, profileUserId);
}
@@ -1349,7 +1368,7 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId);
- mInjector.broadcastIntentLocked(intent,
+ mInjector.broadcastIntent(intent,
null, null, 0, null, null,
new String[] {android.Manifest.permission.MANAGE_USERS},
AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
@@ -1374,7 +1393,7 @@
// the value the caller will receive and someone else changing it.
// We assume that USER_CURRENT_OR_SELF will use the current user; later
// we will switch to the calling user if access to the current user fails.
- int targetUserId = unsafeConvertIncomingUserLocked(userId);
+ int targetUserId = unsafeConvertIncomingUser(userId);
if (callingUid != 0 && callingUid != SYSTEM_UID) {
final boolean allow;
@@ -1442,9 +1461,9 @@
return targetUserId;
}
- int unsafeConvertIncomingUserLocked(int userId) {
+ int unsafeConvertIncomingUser(int userId) {
return (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF)
- ? getCurrentUserIdLocked(): userId;
+ ? getCurrentUserId(): userId;
}
void registerUserSwitchObserver(IUserSwitchObserver observer, String name) {
@@ -1470,15 +1489,17 @@
mUserSwitchObservers.unregister(observer);
}
- UserState getStartedUserStateLocked(int userId) {
- return mStartedUsers.get(userId);
+ UserState getStartedUserState(int userId) {
+ synchronized (mLock) {
+ return mStartedUsers.get(userId);
+ }
}
boolean hasStartedUserState(int userId) {
return mStartedUsers.get(userId) != null;
}
- private void updateStartedUserArrayLocked() {
+ private void updateStartedUserArrayLU() {
int num = 0;
for (int i = 0; i < mStartedUsers.size(); i++) {
UserState uss = mStartedUsers.valueAt(i);
@@ -1499,15 +1520,20 @@
}
}
- void sendBootCompletedLocked(IIntentReceiver resultTo) {
- for (int i = 0; i < mStartedUsers.size(); i++) {
- UserState uss = mStartedUsers.valueAt(i);
+ void sendBootCompleted(IIntentReceiver resultTo) {
+ // Get a copy of mStartedUsers to use outside of lock
+ SparseArray<UserState> startedUsers;
+ synchronized (mLock) {
+ startedUsers = mStartedUsers.clone();
+ }
+ for (int i = 0; i < startedUsers.size(); i++) {
+ UserState uss = startedUsers.valueAt(i);
finishUserBoot(uss, resultTo);
}
}
void onSystemReady() {
- updateCurrentProfileIdsLocked();
+ updateCurrentProfileIds();
}
/**
@@ -1515,33 +1541,35 @@
* user switch happens or when a new related user is started in the
* background.
*/
- private void updateCurrentProfileIdsLocked() {
- final List<UserInfo> profiles = mInjector.getUserManager().getProfiles(mCurrentUserId,
+ private void updateCurrentProfileIds() {
+ final List<UserInfo> profiles = mInjector.getUserManager().getProfiles(getCurrentUserId(),
false /* enabledOnly */);
int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
for (int i = 0; i < currentProfileIds.length; i++) {
currentProfileIds[i] = profiles.get(i).id;
}
- mCurrentProfileIds = currentProfileIds;
+ final List<UserInfo> users = mInjector.getUserManager().getUsers(false);
+ synchronized (mLock) {
+ mCurrentProfileIds = currentProfileIds;
- synchronized (mUserProfileGroupIdsSelfLocked) {
- mUserProfileGroupIdsSelfLocked.clear();
- final List<UserInfo> users = mInjector.getUserManager().getUsers(false);
+ mUserProfileGroupIds.clear();
for (int i = 0; i < users.size(); i++) {
UserInfo user = users.get(i);
if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
- mUserProfileGroupIdsSelfLocked.put(user.id, user.profileGroupId);
+ mUserProfileGroupIds.put(user.id, user.profileGroupId);
}
}
}
}
- int[] getStartedUserArrayLocked() {
- return mStartedUserArray;
+ int[] getStartedUserArray() {
+ synchronized (mLock) {
+ return mStartedUserArray;
+ }
}
- boolean isUserRunningLocked(int userId, int flags) {
- UserState state = getStartedUserStateLocked(userId);
+ boolean isUserRunning(int userId, int flags) {
+ UserState state = getStartedUserState(userId);
if (state == null) {
return false;
}
@@ -1604,29 +1632,38 @@
return getUserInfo(mCurrentUserId);
}
synchronized (mLock) {
- return getCurrentUserLocked();
+ return getCurrentUserLU();
}
}
- UserInfo getCurrentUserLocked() {
+ UserInfo getCurrentUserLU() {
int userId = mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId;
return getUserInfo(userId);
}
- int getCurrentOrTargetUserIdLocked() {
+ int getCurrentOrTargetUserId() {
+ synchronized (mLock) {
+ return mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId;
+ }
+ }
+
+ int getCurrentOrTargetUserIdLU() {
return mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId;
}
- int getCurrentUserIdLocked() {
+
+ int getCurrentUserIdLU() {
return mCurrentUserId;
}
- private boolean isCurrentUserLocked(int userId) {
- return userId == getCurrentOrTargetUserIdLocked();
+ int getCurrentUserId() {
+ synchronized (mLock) {
+ return mCurrentUserId;
+ }
}
- int setTargetUserIdLocked(int targetUserId) {
- return mTargetUserId = targetUserId;
+ private boolean isCurrentUserLU(int userId) {
+ return userId == getCurrentOrTargetUserIdLU();
}
int[] getUsers() {
@@ -1673,22 +1710,26 @@
if (callingUserId == targetUserId) {
return true;
}
- synchronized (mUserProfileGroupIdsSelfLocked) {
- int callingProfile = mUserProfileGroupIdsSelfLocked.get(callingUserId,
+ synchronized (mLock) {
+ int callingProfile = mUserProfileGroupIds.get(callingUserId,
UserInfo.NO_PROFILE_GROUP_ID);
- int targetProfile = mUserProfileGroupIdsSelfLocked.get(targetUserId,
+ int targetProfile = mUserProfileGroupIds.get(targetUserId,
UserInfo.NO_PROFILE_GROUP_ID);
return callingProfile != UserInfo.NO_PROFILE_GROUP_ID
&& callingProfile == targetProfile;
}
}
- boolean isCurrentProfileLocked(int userId) {
- return ArrayUtils.contains(mCurrentProfileIds, userId);
+ boolean isCurrentProfile(int userId) {
+ synchronized (mLock) {
+ return ArrayUtils.contains(mCurrentProfileIds, userId);
+ }
}
- int[] getCurrentProfileIdsLocked() {
- return mCurrentProfileIds;
+ int[] getCurrentProfileIds() {
+ synchronized (mLock) {
+ return mCurrentProfileIds;
+ }
}
/**
@@ -1713,35 +1754,40 @@
}
void dump(PrintWriter pw, boolean dumpAll) {
- pw.println(" mStartedUsers:");
- for (int i = 0; i < mStartedUsers.size(); i++) {
- UserState uss = mStartedUsers.valueAt(i);
- pw.print(" User #"); pw.print(uss.mHandle.getIdentifier());
- pw.print(": "); uss.dump("", pw);
- }
- pw.print(" mStartedUserArray: [");
- for (int i = 0; i < mStartedUserArray.length; i++) {
- if (i > 0) pw.print(", ");
- pw.print(mStartedUserArray[i]);
- }
- pw.println("]");
- pw.print(" mUserLru: [");
- for (int i = 0; i < mUserLru.size(); i++) {
- if (i > 0) pw.print(", ");
- pw.print(mUserLru.get(i));
- }
- pw.println("]");
- if (dumpAll) {
- pw.print(" mStartedUserArray: "); pw.println(Arrays.toString(mStartedUserArray));
- }
- synchronized (mUserProfileGroupIdsSelfLocked) {
- if (mUserProfileGroupIdsSelfLocked.size() > 0) {
+ synchronized (mLock) {
+ pw.println(" mStartedUsers:");
+ for (int i = 0; i < mStartedUsers.size(); i++) {
+ UserState uss = mStartedUsers.valueAt(i);
+ pw.print(" User #");
+ pw.print(uss.mHandle.getIdentifier());
+ pw.print(": ");
+ uss.dump("", pw);
+ }
+ pw.print(" mStartedUserArray: [");
+ for (int i = 0; i < mStartedUserArray.length; i++) {
+ if (i > 0)
+ pw.print(", ");
+ pw.print(mStartedUserArray[i]);
+ }
+ pw.println("]");
+ pw.print(" mUserLru: [");
+ for (int i = 0; i < mUserLru.size(); i++) {
+ if (i > 0)
+ pw.print(", ");
+ pw.print(mUserLru.get(i));
+ }
+ pw.println("]");
+ if (dumpAll) {
+ pw.print(" mStartedUserArray: ");
+ pw.println(Arrays.toString(mStartedUserArray));
+ }
+ if (mUserProfileGroupIds.size() > 0) {
pw.println(" mUserProfileGroupIds:");
- for (int i=0; i<mUserProfileGroupIdsSelfLocked.size(); i++) {
+ for (int i=0; i< mUserProfileGroupIds.size(); i++) {
pw.print(" User #");
- pw.print(mUserProfileGroupIdsSelfLocked.keyAt(i));
+ pw.print(mUserProfileGroupIds.keyAt(i));
pw.print(" -> profile #");
- pw.println(mUserProfileGroupIdsSelfLocked.valueAt(i));
+ pw.println(mUserProfileGroupIds.valueAt(i));
}
}
}
@@ -1765,9 +1811,7 @@
timeoutUserSwitchCallbacks(msg.arg1, msg.arg2);
break;
case START_PROFILES_MSG:
- synchronized (mLock) {
- startProfilesLocked();
- }
+ startProfiles();
break;
case SYSTEM_USER_START_MSG:
mInjector.batteryStatsServiceNoteEvent(
@@ -1778,9 +1822,7 @@
case SYSTEM_USER_UNLOCK_MSG:
final int userId = msg.arg1;
mInjector.getSystemServiceManager().unlockUser(userId);
- synchronized (mLock) {
- mInjector.loadUserRecentsLocked(userId);
- }
+ mInjector.loadUserRecents(userId);
if (userId == UserHandle.USER_SYSTEM) {
mInjector.startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
}
@@ -1823,10 +1865,6 @@
mService = service;
}
- protected Object getLock() {
- return mService;
- }
-
protected Handler getHandler(Handler.Callback callback) {
return new Handler(mService.mHandlerThread.getLooper(), callback);
}
@@ -1843,13 +1881,16 @@
return new LockPatternUtils(getContext());
}
- protected int broadcastIntentLocked(Intent intent, String resolvedType,
+ protected int broadcastIntent(Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
- return mService.broadcastIntentLocked(null, null, intent, resolvedType, resultTo,
- resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions,
- ordered, sticky, callingPid, callingUid, userId);
+ // TODO b/64165549 Verify that mLock is not held before calling AMS methods
+ synchronized (mService) {
+ return mService.broadcastIntentLocked(null, null, intent, resolvedType, resultTo,
+ resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions,
+ ordered, sticky, callingPid, callingUid, userId);
+ }
}
int checkCallingPermission(String permission) {
@@ -1860,7 +1901,9 @@
return mService.mWindowManager;
}
void activityManagerOnUserStopped(int userId) {
- mService.onUserStoppedLocked(userId);
+ synchronized (mService) {
+ mService.onUserStoppedLocked(userId);
+ }
}
void systemServiceManagerCleanupUser(int userId) {
@@ -1916,9 +1959,11 @@
}.sendNext();
}
- void activityManagerForceStopPackageLocked(int userId, String reason) {
- mService.forceStopPackageLocked(null, -1, false, false, true, false, false,
- userId, reason);
+ void activityManagerForceStopPackage(int userId, String reason) {
+ synchronized (mService) {
+ mService.forceStopPackageLocked(null, -1, false, false, true, false, false,
+ userId, reason);
+ }
};
int checkComponentPermission(String permission, int pid, int uid, int owningUid,
@@ -1926,20 +1971,28 @@
return mService.checkComponentPermission(permission, pid, uid, owningUid, exported);
}
- void startHomeActivityLocked(int userId, String reason) {
- mService.startHomeActivityLocked(userId, reason);
+ protected void startHomeActivity(int userId, String reason) {
+ synchronized (mService) {
+ mService.startHomeActivityLocked(userId, reason);
+ }
}
- void updateUserConfigurationLocked() {
- mService.updateUserConfigurationLocked();
+ void updateUserConfiguration() {
+ synchronized (mService) {
+ mService.updateUserConfigurationLocked();
+ }
}
- void clearBroadcastQueueForUserLocked(int userId) {
- mService.clearBroadcastQueueForUserLocked(userId);
+ void clearBroadcastQueueForUser(int userId) {
+ synchronized (mService) {
+ mService.clearBroadcastQueueForUserLocked(userId);
+ }
}
- void loadUserRecentsLocked(int userId) {
- mService.mRecentTasks.loadUserRecentsLocked(userId);
+ void loadUserRecents(int userId) {
+ synchronized (mService) {
+ mService.mRecentTasks.loadUserRecentsLocked(userId);
+ }
}
void startPersistentApps(int matchFlags) {
@@ -1956,12 +2009,28 @@
d.show();
}
- ActivityStackSupervisor getActivityStackSupervisor() {
- return mService.mStackSupervisor;
+ void stackSupervisorRemoveUser(int userId) {
+ synchronized (mService) {
+ mService.mStackSupervisor.removeUserLocked(userId);
+ }
}
- LockTaskController getLockTaskController() {
- return mService.mLockTaskController;
+ protected boolean stackSupervisorSwitchUser(int userId, UserState uss) {
+ synchronized (mService) {
+ return mService.mStackSupervisor.switchUserLocked(userId, uss);
+ }
+ }
+
+ protected void stackSupervisorResumeFocusedStackTopActivity() {
+ synchronized (mService) {
+ mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
+ }
+ }
+
+ protected void clearLockTaskMode(String reason) {
+ synchronized (mService) {
+ mService.mLockTaskController.clearLockTaskMode(reason);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index 2e27387..d36d9cb 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -59,8 +59,10 @@
/**
* The last time that a provider was reported to usage stats as being brought to important
* foreground procstate.
+ * <p><strong>Important: </strong>Only access this field when holding ActivityManagerService
+ * lock.
*/
- public final ArrayMap<String,Long> mProviderLastReportedFg = new ArrayMap<>();
+ final ArrayMap<String,Long> mProviderLastReportedFg = new ArrayMap<>();
public UserState(UserHandle handle) {
mHandle = handle;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 11d0470..0bc20a2e 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -461,6 +461,8 @@
// Forced device usage for communications
private int mForcedUseForComm;
+ private int mForcedUseForCommExt; // External state returned by getters: always consistent
+ // with requests by setters
// List of binder death handlers for setMode() client processes.
// The last process to have called setMode() is at the top of the list.
@@ -2544,13 +2546,15 @@
}
}
int status = AudioSystem.AUDIO_STATUS_OK;
+ int actualMode;
do {
+ actualMode = mode;
if (mode == AudioSystem.MODE_NORMAL) {
// get new mode from client at top the list if any
if (!mSetModeDeathHandlers.isEmpty()) {
hdlr = mSetModeDeathHandlers.get(0);
cb = hdlr.getBinder();
- mode = hdlr.getMode();
+ actualMode = hdlr.getMode();
if (DEBUG_MODE) {
Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
+ hdlr.mPid);
@@ -2574,12 +2578,11 @@
hdlr.setMode(mode);
}
- if (mode != mMode) {
- status = AudioSystem.setPhoneState(mode);
+ if (actualMode != mMode) {
+ status = AudioSystem.setPhoneState(actualMode);
if (status == AudioSystem.AUDIO_STATUS_OK) {
- if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
- mMode = mode;
- mModeLogger.log(new PhoneStateEvent(caller, pid, mode));
+ if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + actualMode); }
+ mMode = actualMode;
} else {
if (hdlr != null) {
mSetModeDeathHandlers.remove(hdlr);
@@ -2595,13 +2598,16 @@
} while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
if (status == AudioSystem.AUDIO_STATUS_OK) {
- if (mode != AudioSystem.MODE_NORMAL) {
+ if (actualMode != AudioSystem.MODE_NORMAL) {
if (mSetModeDeathHandlers.isEmpty()) {
Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
} else {
newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
}
}
+ // Note: newModeOwnerPid is always 0 when actualMode is MODE_NORMAL
+ mModeLogger.log(
+ new PhoneStateEvent(caller, pid, mode, newModeOwnerPid, actualMode));
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
int device = getDeviceForStream(streamType);
int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
@@ -2890,13 +2896,14 @@
mForcedUseForComm = AudioSystem.FORCE_NONE;
}
+ mForcedUseForCommExt = mForcedUseForComm;
sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource, 0);
}
/** @see AudioManager#isSpeakerphoneOn() */
public boolean isSpeakerphoneOn() {
- return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
+ return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
}
/** @see AudioManager#setBluetoothScoOn(boolean) */
@@ -2904,6 +2911,13 @@
if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
return;
}
+
+ // Only enable calls from system components
+ if (Binder.getCallingUid() >= FIRST_APPLICATION_UID) {
+ mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
+ return;
+ }
+
// for logging only
final String eventSource = new StringBuilder("setBluetoothScoOn(").append(on)
.append(") from u/pid:").append(Binder.getCallingUid()).append("/")
@@ -2913,11 +2927,21 @@
public void setBluetoothScoOnInt(boolean on, String eventSource) {
if (on) {
+ // do not accept SCO ON if SCO audio is not connected
+ synchronized(mScoClients) {
+ if ((mBluetoothHeadset != null) &&
+ (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+ != BluetoothHeadset.STATE_AUDIO_CONNECTED)) {
+ mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
+ return;
+ }
+ }
mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
} else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
mForcedUseForComm = AudioSystem.FORCE_NONE;
}
-
+ mForcedUseForCommExt = mForcedUseForComm;
+ AudioSystem.setParameters("BT_SCO="+ (on ? "on" : "off"));
sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource, 0);
sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
@@ -2926,7 +2950,7 @@
/** @see AudioManager#isBluetoothScoOn() */
public boolean isBluetoothScoOn() {
- return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
+ return (mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO);
}
/** @see AudioManager#setBluetoothA2dpOn(boolean) */
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index 634c8c2..9d9e35b 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -26,20 +26,27 @@
final static class PhoneStateEvent extends AudioEventLogger.Event {
final String mPackage;
- final int mPid;
- final int mMode;
+ final int mOwnerPid;
+ final int mRequesterPid;
+ final int mRequestedMode;
+ final int mActualMode;
- PhoneStateEvent(String callingPackage, int pid, int mode) {
+ PhoneStateEvent(String callingPackage, int requesterPid, int requestedMode,
+ int ownerPid, int actualMode) {
mPackage = callingPackage;
- mPid = pid;
- mMode = mode;
+ mRequesterPid = requesterPid;
+ mRequestedMode = requestedMode;
+ mOwnerPid = ownerPid;
+ mActualMode = actualMode;
}
@Override
public String eventToString() {
- return new StringBuilder("setMode(").append(AudioSystem.modeToString(mMode))
+ return new StringBuilder("setMode(").append(AudioSystem.modeToString(mRequestedMode))
.append(") from package=").append(mPackage)
- .append(" pid=").append(mPid).toString();
+ .append(" pid=").append(mRequesterPid)
+ .append(" selected mode=").append(AudioSystem.modeToString(mActualMode))
+ .append(" by pid=").append(mOwnerPid).toString();
}
}
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 475d786..f2445fa 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -34,6 +34,7 @@
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.RingBuffer;
import com.android.internal.util.TokenBucket;
import com.android.server.SystemService;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
@@ -44,7 +45,11 @@
import java.util.List;
import java.util.function.ToIntFunction;
-/** {@hide} */
+/**
+ * Event buffering service for core networking and connectivity metrics.
+ *
+ * {@hide}
+ */
final public class IpConnectivityMetrics extends SystemService {
private static final String TAG = IpConnectivityMetrics.class.getSimpleName();
private static final boolean DBG = false;
@@ -58,7 +63,10 @@
private static final String SERVICE_NAME = IpConnectivityLog.SERVICE_NAME;
- // Default size of the event buffer. Once the buffer is full, incoming events are dropped.
+ // Default size of the event rolling log for bug report dumps.
+ private static final int DEFAULT_LOG_SIZE = 500;
+ // Default size of the event buffer for metrics reporting.
+ // Once the buffer is full, incoming events are dropped.
private static final int DEFAULT_BUFFER_SIZE = 2000;
// Maximum size of the event buffer.
private static final int MAXIMUM_BUFFER_SIZE = DEFAULT_BUFFER_SIZE * 10;
@@ -67,24 +75,38 @@
private static final int ERROR_RATE_LIMITED = -1;
- // Lock ensuring that concurrent manipulations of the event buffer are correct.
+ // Lock ensuring that concurrent manipulations of the event buffers are correct.
// There are three concurrent operations to synchronize:
// - appending events to the buffer.
// - iterating throught the buffer.
// - flushing the buffer content and replacing it by a new buffer.
private final Object mLock = new Object();
+ // Implementation instance of IIpConnectivityMetrics.aidl.
@VisibleForTesting
public final Impl impl = new Impl();
+ // Subservice listening to Netd events via INetdEventListener.aidl.
@VisibleForTesting
NetdEventListenerService mNetdListener;
+ // Rolling log of the most recent events. This log is used for dumping
+ // connectivity events in bug reports.
+ @GuardedBy("mLock")
+ private final RingBuffer<ConnectivityMetricsEvent> mEventLog =
+ new RingBuffer(ConnectivityMetricsEvent.class, DEFAULT_LOG_SIZE);
+ // Buffer of connectivity events used for metrics reporting. This buffer
+ // does not rotate automatically and instead saturates when it becomes full.
+ // It is flushed at metrics reporting.
@GuardedBy("mLock")
private ArrayList<ConnectivityMetricsEvent> mBuffer;
+ // Total number of events dropped from mBuffer since last metrics reporting.
@GuardedBy("mLock")
private int mDropped;
+ // Capacity of mBuffer
@GuardedBy("mLock")
private int mCapacity;
+ // A list of rate limiting counters keyed by connectivity event types for
+ // metrics reporting mBuffer.
@GuardedBy("mLock")
private final ArrayMap<Class<?>, TokenBucket> mBuckets = makeRateLimitingBuckets();
@@ -132,6 +154,7 @@
private int append(ConnectivityMetricsEvent event) {
if (DBG) Log.d(TAG, "logEvent: " + event);
synchronized (mLock) {
+ mEventLog.append(event);
final int left = mCapacity - mBuffer.size();
if (event == null) {
return left;
@@ -216,6 +239,23 @@
}
}
+ /**
+ * Prints for bug reports the content of the rolling event log and the
+ * content of Netd event listener.
+ */
+ private void cmdDumpsys(FileDescriptor fd, PrintWriter pw, String[] args) {
+ final ConnectivityMetricsEvent[] events;
+ synchronized (mLock) {
+ events = mEventLog.toArray();
+ }
+ for (ConnectivityMetricsEvent ev : events) {
+ pw.println(ev.toString());
+ }
+ if (mNetdListener != null) {
+ mNetdListener.list(pw);
+ }
+ }
+
private void cmdStats(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mLock) {
pw.println("Buffered events: " + mBuffer.size());
@@ -258,7 +298,8 @@
cmdFlush(fd, pw, args);
return;
case CMD_DUMPSYS:
- // Fallthrough to CMD_LIST when dumpsys.cpp dumps services states (bug reports)
+ cmdDumpsys(fd, pw, args);
+ return;
case CMD_LIST:
cmdList(fd, pw, args);
return;
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index fbbdf00..fceacba 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -152,7 +152,6 @@
* turn ND offload off if on WiFi.
*/
private void enterRunningState() {
- maybeSetIpv6NdOffload(mBaseIface, false);
mState = State.RUNNING;
}
@@ -160,10 +159,6 @@
* Stop clatd, and turn ND offload on if it had been turned off.
*/
private void enterStoppingState() {
- if (isRunning()) {
- maybeSetIpv6NdOffload(mBaseIface, true);
- }
-
try {
mNMService.stopClatd(mBaseIface);
} catch(RemoteException|IllegalStateException e) {
@@ -279,19 +274,6 @@
}
}
- private void maybeSetIpv6NdOffload(String iface, boolean on) {
- // TODO: migrate to NetworkCapabilities.TRANSPORT_*.
- if (mNetwork.networkInfo.getType() != ConnectivityManager.TYPE_WIFI) {
- return;
- }
- try {
- Slog.d(TAG, (on ? "En" : "Dis") + "abling ND offload on " + iface);
- mNMService.setInterfaceIpv6NdOffload(iface, on);
- } catch(RemoteException|IllegalStateException e) {
- Slog.w(TAG, "Changing IPv6 ND offload on " + iface + "failed: " + e);
- }
- }
-
/**
* Adds stacked link on base link and transitions to RUNNING state.
*/
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 25dba35..6206dfc 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -38,6 +38,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.BitUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.RingBuffer;
import com.android.internal.util.TokenBucket;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
import java.io.PrintWriter;
@@ -82,9 +83,8 @@
private final ArrayMap<String, WakeupStats> mWakeupStats = new ArrayMap<>();
// Ring buffer array for storing packet wake up events sent by Netd.
@GuardedBy("this")
- private final WakeupEvent[] mWakeupEvents = new WakeupEvent[WAKEUP_EVENT_BUFFER_LENGTH];
- @GuardedBy("this")
- private long mWakeupEventCursor = 0;
+ private final RingBuffer<WakeupEvent> mWakeupEvents =
+ new RingBuffer(WakeupEvent.class, WAKEUP_EVENT_BUFFER_LENGTH);
private final ConnectivityManager mCm;
@@ -175,13 +175,11 @@
@GuardedBy("this")
private void addWakeupEvent(String iface, long timestampMs, int uid) {
- int index = wakeupEventIndex(mWakeupEventCursor);
- mWakeupEventCursor++;
WakeupEvent event = new WakeupEvent();
event.iface = iface;
event.timestampMs = timestampMs;
event.uid = uid;
- mWakeupEvents[index] = event;
+ mWakeupEvents.append(event);
WakeupStats stats = mWakeupStats.get(iface);
if (stats == null) {
stats = new WakeupStats(iface);
@@ -190,23 +188,6 @@
stats.countEvent(event);
}
- @GuardedBy("this")
- private WakeupEvent[] getWakeupEvents() {
- int length = (int) Math.min(mWakeupEventCursor, (long) mWakeupEvents.length);
- WakeupEvent[] out = new WakeupEvent[length];
- // Reverse iteration from youngest event to oldest event.
- long inCursor = mWakeupEventCursor - 1;
- int outIdx = out.length - 1;
- while (outIdx >= 0) {
- out[outIdx--] = mWakeupEvents[wakeupEventIndex(inCursor--)];
- }
- return out;
- }
-
- private static int wakeupEventIndex(long cursor) {
- return (int) Math.abs(cursor % WAKEUP_EVENT_BUFFER_LENGTH);
- }
-
public synchronized void flushStatistics(List<IpConnectivityEvent> events) {
flushProtos(events, mConnectEvents, IpConnectivityEventBuilder::toProto);
flushProtos(events, mDnsEvents, IpConnectivityEventBuilder::toProto);
@@ -230,7 +211,7 @@
for (int i = 0; i < mWakeupStats.size(); i++) {
pw.println(mWakeupStats.valueAt(i));
}
- for (WakeupEvent wakeup : getWakeupEvents()) {
+ for (WakeupEvent wakeup : mWakeupEvents.toArray()) {
pw.println(wakeup);
}
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 0e1252e..1df9c86 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -63,6 +63,8 @@
import android.service.fingerprint.FingerprintServiceDumpProto;
import android.service.fingerprint.FingerprintUserStatsProto;
import android.util.Slog;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
@@ -81,7 +83,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -89,18 +90,19 @@
/**
* A service to manage multiple clients that want to access the fingerprint HAL API.
* The service is responsible for maintaining a list of clients and dispatching all
- * fingerprint -related events.
+ * fingerprint-related events.
*
* @hide
*/
public class FingerprintService extends SystemService implements IHwBinder.DeathRecipient {
static final String TAG = "FingerprintService";
static final boolean DEBUG = true;
- private static final boolean CLEANUP_UNUSED_FP = false;
+ private static final boolean CLEANUP_UNUSED_FP = true;
private static final String FP_DATA_DIR = "fpdata";
private static final int MSG_USER_SWITCHING = 10;
private static final String ACTION_LOCKOUT_RESET =
"com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
+ private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
private class PerformanceStats {
int accept; // number of accepted fingerprints
@@ -128,8 +130,8 @@
private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance();
private Context mContext;
private long mHalDeviceId;
- private boolean mTimedLockoutCleared;
- private int mFailedAttempts;
+ private SparseBooleanArray mTimedLockoutCleared;
+ private SparseIntArray mFailedAttempts;
@GuardedBy("this")
private IBiometricsFingerprint mDaemon;
private final PowerManager mPowerManager;
@@ -139,10 +141,8 @@
private ClientMonitor mPendingClient;
private PerformanceStats mPerformanceStats;
-
private IBinder mToken = new Binder(); // used for internal FingerprintService enumeration
- private LinkedList<Integer> mEnumeratingUserIds = new LinkedList<>();
- private ArrayList<UserFingerprint> mUnknownFingerprints = new ArrayList<>(); // hw finterprints
+ private ArrayList<UserFingerprint> mUnknownFingerprints = new ArrayList<>(); // hw fingerprints
private class UserFingerprint {
Fingerprint f;
@@ -177,15 +177,17 @@
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) {
- resetFailedAttempts(false /* clearAttemptCounter */);
+ final int user = intent.getIntExtra(KEY_LOCKOUT_RESET_USER, 0);
+ resetFailedAttemptsForUser(false /* clearAttemptCounter */, user);
}
}
};
- private final Runnable mResetFailedAttemptsRunnable = new Runnable() {
+ private final Runnable mResetFailedAttemptsForCurrentUserRunnable = new Runnable() {
@Override
public void run() {
- resetFailedAttempts(true /* clearAttemptCounter */);
+ resetFailedAttemptsForUser(true /* clearAttemptCounter */,
+ ActivityManager.getCurrentUser());
}
};
@@ -221,6 +223,8 @@
mContext.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
RESET_FINGERPRINT_LOCKOUT, null /* handler */);
mUserManager = UserManager.get(mContext);
+ mTimedLockoutCleared = new SparseBooleanArray();
+ mFailedAttempts = new SparseIntArray();
}
@Override
@@ -233,7 +237,7 @@
public synchronized IBiometricsFingerprint getFingerprintDaemon() {
if (mDaemon == null) {
- Slog.v(TAG, "mDeamon was null, reconnect to fingerprint");
+ Slog.v(TAG, "mDaemon was null, reconnect to fingerprint");
try {
mDaemon = IBiometricsFingerprint.getService();
} catch (java.util.NoSuchElementException e) {
@@ -259,7 +263,7 @@
if (mHalDeviceId != 0) {
loadAuthenticatorIds();
updateActiveGroup(ActivityManager.getCurrentUser(), null);
- doFingerprintCleanup(ActivityManager.getCurrentUser());
+ doFingerprintCleanupForUser(ActivityManager.getCurrentUser());
} else {
Slog.w(TAG, "Failed to open Fingerprint HAL!");
MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1);
@@ -288,52 +292,41 @@
}
}
- private void doFingerprintCleanup(int userId) {
+ /**
+ * This method should be called upon connection to the daemon, and when user switches.
+ * @param userId
+ */
+ private void doFingerprintCleanupForUser(int userId) {
if (CLEANUP_UNUSED_FP) {
- resetEnumerateState();
- mEnumeratingUserIds.push(userId);
- enumerateNextUser();
+ enumerateUser(userId);
}
}
- private void resetEnumerateState() {
- if (DEBUG) Slog.v(TAG, "Enumerate cleaning up");
- mEnumeratingUserIds.clear();
+ private void clearEnumerateState() {
+ if (DEBUG) Slog.v(TAG, "clearEnumerateState()");
mUnknownFingerprints.clear();
}
- private void enumerateNextUser() {
- int nextUser = mEnumeratingUserIds.getFirst();
- updateActiveGroup(nextUser, null);
+ private void enumerateUser(int userId) {
+ if (DEBUG) Slog.v(TAG, "Enumerating user(" + userId + ")");
boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
-
- if (DEBUG) Slog.v(TAG, "Enumerating user id " + nextUser + " of "
- + mEnumeratingUserIds.size() + " remaining users");
-
- startEnumerate(mToken, nextUser, null, restricted, true /* internal */);
+ startEnumerate(mToken, userId, null, restricted, true /* internal */);
}
// Remove unknown fingerprints from hardware
private void cleanupUnknownFingerprints() {
if (!mUnknownFingerprints.isEmpty()) {
- Slog.w(TAG, "unknown fingerprint size: " + mUnknownFingerprints.size());
UserFingerprint uf = mUnknownFingerprints.get(0);
mUnknownFingerprints.remove(uf);
boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
- updateActiveGroup(uf.userId, null);
startRemove(mToken, uf.f.getFingerId(), uf.f.getGroupId(), uf.userId, null,
restricted, true /* internal */);
} else {
- resetEnumerateState();
+ clearEnumerateState();
}
}
protected void handleEnumerate(long deviceId, int fingerId, int groupId, int remaining) {
- if (DEBUG) Slog.w(TAG, "Enumerate: fid=" + fingerId
- + ", gid=" + groupId
- + ", dev=" + deviceId
- + ", rem=" + remaining);
-
ClientMonitor client = mCurrentClient;
if ( !(client instanceof InternalRemovalClient) && !(client instanceof EnumerateClient) ) {
@@ -343,24 +336,21 @@
// All fingerprints in hardware for this user were enumerated
if (remaining == 0) {
- mEnumeratingUserIds.poll();
-
if (client instanceof InternalEnumerateClient) {
- List<Fingerprint> enrolled = ((InternalEnumerateClient) client).getEnumeratedList();
- Slog.w(TAG, "Added " + enrolled.size() + " enumerated fingerprints for deletion");
- for (Fingerprint f : enrolled) {
+ List<Fingerprint> unknownFingerprints =
+ ((InternalEnumerateClient) client).getUnknownFingerprints();
+
+ if (!unknownFingerprints.isEmpty()) {
+ Slog.w(TAG, "Adding " + unknownFingerprints.size() +
+ " fingerprints for deletion");
+ }
+ for (Fingerprint f : unknownFingerprints) {
mUnknownFingerprints.add(new UserFingerprint(f, client.getTargetUserId()));
}
- }
-
- removeClient(client);
-
- if (!mEnumeratingUserIds.isEmpty()) {
- enumerateNextUser();
- } else if (client instanceof InternalEnumerateClient) {
- if (DEBUG) Slog.v(TAG, "Finished enumerating all users");
- // This will start a chain of InternalRemovalClients
+ removeClient(client);
cleanupUnknownFingerprints();
+ } else {
+ removeClient(client);
}
}
}
@@ -368,7 +358,7 @@
protected void handleError(long deviceId, int error, int vendorCode) {
ClientMonitor client = mCurrentClient;
if (client instanceof InternalRemovalClient || client instanceof InternalEnumerateClient) {
- resetEnumerateState();
+ clearEnumerateState();
}
if (client != null && client.onError(error, vendorCode)) {
removeClient(client);
@@ -412,7 +402,7 @@
if (client instanceof InternalRemovalClient && !mUnknownFingerprints.isEmpty()) {
cleanupUnknownFingerprints();
} else if (client instanceof InternalRemovalClient){
- resetEnumerateState();
+ clearEnumerateState();
}
}
@@ -466,8 +456,14 @@
}
void handleUserSwitching(int userId) {
+ if (mCurrentClient instanceof InternalRemovalClient
+ || mCurrentClient instanceof InternalEnumerateClient) {
+ Slog.w(TAG, "User switched while performing cleanup");
+ removeClient(mCurrentClient);
+ clearEnumerateState();
+ }
updateActiveGroup(userId, null);
- doFingerprintCleanup(userId);
+ doFingerprintCleanupForUser(userId);
}
private void removeClient(ClientMonitor client) {
@@ -488,27 +484,32 @@
}
private int getLockoutMode() {
- if (mFailedAttempts >= MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT) {
+ final int currentUser = ActivityManager.getCurrentUser();
+ final int failedAttempts = mFailedAttempts.get(currentUser, 0);
+ if (failedAttempts >= MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT) {
return AuthenticationClient.LOCKOUT_PERMANENT;
- } else if (mFailedAttempts > 0 && mTimedLockoutCleared == false &&
- (mFailedAttempts % MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED == 0)) {
+ } else if (failedAttempts > 0 &&
+ mTimedLockoutCleared.get(currentUser, false) == false
+ && (failedAttempts % MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED == 0)) {
return AuthenticationClient.LOCKOUT_TIMED;
}
return AuthenticationClient.LOCKOUT_NONE;
}
- private void scheduleLockoutReset() {
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS, getLockoutResetIntent());
+ private void scheduleLockoutResetForUser(int userId) {
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
+ getLockoutResetIntentForUser(userId));
}
- private void cancelLockoutReset() {
- mAlarmManager.cancel(getLockoutResetIntent());
+ private void cancelLockoutResetForUser(int userId) {
+ mAlarmManager.cancel(getLockoutResetIntentForUser(userId));
}
- private PendingIntent getLockoutResetIntent() {
- return PendingIntent.getBroadcast(mContext, 0,
- new Intent(ACTION_LOCKOUT_RESET), PendingIntent.FLAG_UPDATE_CURRENT);
+ private PendingIntent getLockoutResetIntentForUser(int userId) {
+ return PendingIntent.getBroadcast(mContext, userId,
+ new Intent(ACTION_LOCKOUT_RESET).putExtra(KEY_LOCKOUT_RESET_USER, userId),
+ PendingIntent.FLAG_UPDATE_CURRENT);
}
public long startPreEnroll(IBinder token) {
@@ -555,6 +556,12 @@
// This condition means we're currently running internal diagnostics to
// remove extra fingerprints in the hardware and/or the software
// TODO: design an escape hatch in case client never finishes
+ if (newClient != null) {
+ Slog.w(TAG, "Internal cleanup in progress but trying to start client "
+ + newClient.getClass().getSuperclass().getSimpleName()
+ + "(" + newClient.getOwnerString() + ")"
+ + ", initiatedByClient = " + initiatedByClient);
+ }
}
else {
currentClient.stop(initiatedByClient);
@@ -567,7 +574,7 @@
if (DEBUG) Slog.v(TAG, "starting client "
+ newClient.getClass().getSuperclass().getSimpleName()
+ "(" + newClient.getOwnerString() + ")"
- + ", initiatedByClient = " + initiatedByClient + ")");
+ + ", initiatedByClient = " + initiatedByClient);
notifyClientActiveCallbacks(true);
newClient.start();
@@ -813,8 +820,9 @@
receiver, mCurrentUserId, groupId, opId, restricted, opPackageName) {
@Override
public int handleFailedAttempt() {
- mFailedAttempts++;
- mTimedLockoutCleared = false;
+ final int currentUser = ActivityManager.getCurrentUser();
+ mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
+ mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), false);
final int lockoutMode = getLockoutMode();
if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
mPerformanceStats.permanentLockout++;
@@ -824,7 +832,7 @@
// Failing multiple times will continue to push out the lockout time
if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
- scheduleLockoutReset();
+ scheduleLockoutResetForUser(currentUser);
return lockoutMode;
}
return AuthenticationClient.LOCKOUT_NONE;
@@ -832,7 +840,8 @@
@Override
public void resetFailedAttempts() {
- FingerprintService.this.resetFailedAttempts(true /* clearAttemptCounter */);
+ FingerprintService.this.resetFailedAttemptsForUser(true /* clearAttemptCounter */,
+ ActivityManager.getCurrentUser());
}
@Override
@@ -886,17 +895,17 @@
// attempt counter should only be cleared when Keyguard goes away or when
// a fingerprint is successfully authenticated
- protected void resetFailedAttempts(boolean clearAttemptCounter) {
+ protected void resetFailedAttemptsForUser(boolean clearAttemptCounter, int userId) {
if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
Slog.v(TAG, "Reset fingerprint lockout, clearAttemptCounter=" + clearAttemptCounter);
}
if (clearAttemptCounter) {
- mFailedAttempts = 0;
+ mFailedAttempts.put(userId, 0);
}
- mTimedLockoutCleared = true;
+ mTimedLockoutCleared.put(userId, true);
// If we're asked to reset failed attempts externally (i.e. from Keyguard),
// the alarm might still be pending; remove it.
- cancelLockoutReset();
+ cancelLockoutResetForUser(userId);
notifyLockoutResetMonitors();
}
@@ -1277,7 +1286,7 @@
public void resetTimeout(byte [] token) {
checkPermission(RESET_FINGERPRINT_LOCKOUT);
// TODO: confirm security token when we move timeout management into the HAL layer.
- mHandler.post(mResetFailedAttemptsRunnable);
+ mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);
}
@Override
diff --git a/services/core/java/com/android/server/fingerprint/InternalEnumerateClient.java b/services/core/java/com/android/server/fingerprint/InternalEnumerateClient.java
index 88d9ef4..434db98 100644
--- a/services/core/java/com/android/server/fingerprint/InternalEnumerateClient.java
+++ b/services/core/java/com/android/server/fingerprint/InternalEnumerateClient.java
@@ -30,7 +30,7 @@
public abstract class InternalEnumerateClient extends EnumerateClient {
private List<Fingerprint> mEnrolledList;
- private List<Fingerprint> mEnumeratedList = new ArrayList<>(); // list of fp to delete
+ private List<Fingerprint> mUnknownFingerprints = new ArrayList<>(); // list of fp to delete
public InternalEnumerateClient(Context context, long halDeviceId, IBinder token,
IFingerprintServiceReceiver receiver, int groupId, int userId,
@@ -47,7 +47,6 @@
if (mEnrolledList.get(i).getFingerId() == fingerId) {
mEnrolledList.remove(i);
matched = true;
- Slog.e(TAG, "Matched fingerprint fid=" + fingerId);
break;
}
}
@@ -55,7 +54,7 @@
// fingerId 0 means no fingerprints are in hardware
if (!matched && fingerId != 0) {
Fingerprint fingerprint = new Fingerprint("", groupId, fingerId, getHalDeviceId());
- mEnumeratedList.add(fingerprint);
+ mUnknownFingerprints.add(fingerprint);
}
}
@@ -76,8 +75,8 @@
mEnrolledList.clear();
}
- public List<Fingerprint> getEnumeratedList() {
- return mEnumeratedList;
+ public List<Fingerprint> getUnknownFingerprints() {
+ return mUnknownFingerprints;
}
@Override
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 14d9afb..a1a0106 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -376,7 +376,7 @@
}
public SyntheticPasswordManager getSyntheticPasswordManager(LockSettingsStorage storage) {
- return new SyntheticPasswordManager(storage, getUserManager());
+ return new SyntheticPasswordManager(getContext(), storage, getUserManager());
}
public int binderGetCallingUid() {
@@ -763,7 +763,8 @@
private void migrateOldDataAfterSystemReady() {
try {
// Migrate the FRP credential to the persistent data block
- if (LockPatternUtils.frpCredentialEnabled() && !getBoolean("migrated_frp", false, 0)) {
+ if (LockPatternUtils.frpCredentialEnabled(mContext)
+ && !getBoolean("migrated_frp", false, 0)) {
migrateFrpCredential();
setBoolean("migrated_frp", true, 0);
Slog.i(TAG, "Migrated migrated_frp.");
@@ -784,7 +785,7 @@
return;
}
for (UserInfo userInfo : mUserManager.getUsers()) {
- if (userOwnsFrpCredential(userInfo) && isUserSecure(userInfo.id)) {
+ if (userOwnsFrpCredential(mContext, userInfo) && isUserSecure(userInfo.id)) {
synchronized (mSpManager) {
if (isSyntheticPasswordBasedCredentialLocked(userInfo.id)) {
int actualQuality = (int) getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
@@ -2504,7 +2505,7 @@
}
public void onSystemReady() {
- if (frpCredentialEnabled()) {
+ if (frpCredentialEnabled(mContext)) {
updateRegistration();
} else {
// If we don't intend to use frpCredentials and we're not provisioned yet, send
@@ -2533,7 +2534,7 @@
private void clearFrpCredentialIfOwnerNotSecure() {
List<UserInfo> users = mUserManager.getUsers();
for (UserInfo user : users) {
- if (userOwnsFrpCredential(user)) {
+ if (userOwnsFrpCredential(mContext, user)) {
if (!isUserSecure(user.id)) {
mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, user.id,
0, null);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
index 542b929..c9c9329 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
@@ -27,6 +27,7 @@
import android.app.admin.DevicePolicyManager;
import android.app.trust.IStrongAuthTracker;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Binder;
import android.os.DeadObjectException;
@@ -74,7 +75,10 @@
}
public void systemReady() {
- mFingerprintManager = mContext.getSystemService(FingerprintManager.class);
+ final PackageManager pm = mContext.getPackageManager();
+ if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ mFingerprintManager = mContext.getSystemService(FingerprintManager.class);
+ }
}
private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 33a9a99..9440f17 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.DevicePolicyManager;
+import android.content.Context;
import android.content.pm.UserInfo;
import android.hardware.weaver.V1_0.IWeaver;
import android.hardware.weaver.V1_0.WeaverConfig;
@@ -255,13 +256,16 @@
byte[] aggregatedSecret;
}
+ private final Context mContext;
private LockSettingsStorage mStorage;
private IWeaver mWeaver;
private WeaverConfig mWeaverConfig;
private final UserManager mUserManager;
- public SyntheticPasswordManager(LockSettingsStorage storage, UserManager userManager) {
+ public SyntheticPasswordManager(Context context, LockSettingsStorage storage,
+ UserManager userManager) {
+ mContext = context;
mStorage = storage;
mUserManager = userManager;
}
@@ -645,7 +649,7 @@
public void migrateFrpPasswordLocked(long handle, UserInfo userInfo, int requestedQuality) {
if (mStorage.getPersistentDataBlock() != null
- && LockPatternUtils.userOwnsFrpCredential(userInfo)) {
+ && LockPatternUtils.userOwnsFrpCredential(mContext, userInfo)) {
PasswordData pwd = PasswordData.fromBytes(loadState(PASSWORD_DATA_NAME, handle,
userInfo.id));
if (pwd.passwordType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
@@ -662,7 +666,8 @@
private void synchronizeFrpPassword(PasswordData pwd,
int requestedQuality, int userId) {
if (mStorage.getPersistentDataBlock() != null
- && LockPatternUtils.userOwnsFrpCredential(mUserManager.getUserInfo(userId))) {
+ && LockPatternUtils.userOwnsFrpCredential(mContext,
+ mUserManager.getUserInfo(userId))) {
if (pwd.passwordType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
mStorage.writePersistentDataBlock(PersistentData.TYPE_SP, userId, requestedQuality,
pwd.toBytes());
@@ -675,7 +680,8 @@
private void synchronizeWeaverFrpPassword(PasswordData pwd, int requestedQuality, int userId,
int weaverSlot) {
if (mStorage.getPersistentDataBlock() != null
- && LockPatternUtils.userOwnsFrpCredential(mUserManager.getUserInfo(userId))) {
+ && LockPatternUtils.userOwnsFrpCredential(mContext,
+ mUserManager.getUserInfo(userId))) {
if (pwd.passwordType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
mStorage.writePersistentDataBlock(PersistentData.TYPE_SP_WEAVER, weaverSlot,
requestedQuality, pwd.toBytes());
diff --git a/services/core/java/com/android/server/notification/ImportanceExtractor.java b/services/core/java/com/android/server/notification/ImportanceExtractor.java
index 46ec92b..452121c 100644
--- a/services/core/java/com/android/server/notification/ImportanceExtractor.java
+++ b/services/core/java/com/android/server/notification/ImportanceExtractor.java
@@ -22,7 +22,7 @@
* Determines the importance of the given notification.
*/
public class ImportanceExtractor implements NotificationSignalExtractor {
- private static final String TAG = "ImportantTopicExtractor";
+ private static final String TAG = "ImportanceExtractor";
private static final boolean DBG = false;
private RankingConfig mConfig;
diff --git a/services/core/java/com/android/server/notification/NotificationAdjustmentExtractor.java b/services/core/java/com/android/server/notification/NotificationAdjustmentExtractor.java
index 7c82845..ce11268 100644
--- a/services/core/java/com/android/server/notification/NotificationAdjustmentExtractor.java
+++ b/services/core/java/com/android/server/notification/NotificationAdjustmentExtractor.java
@@ -22,7 +22,7 @@
* Applies adjustments from the group helper and notification assistant
*/
public class NotificationAdjustmentExtractor implements NotificationSignalExtractor {
- private static final String TAG = "BadgeExtractor";
+ private static final String TAG = "AdjustmentExtractor";
private static final boolean DBG = false;
diff --git a/services/core/java/com/android/server/notification/NotificationChannelExtractor.java b/services/core/java/com/android/server/notification/NotificationChannelExtractor.java
index 46ab556..11c7ab7 100644
--- a/services/core/java/com/android/server/notification/NotificationChannelExtractor.java
+++ b/services/core/java/com/android/server/notification/NotificationChannelExtractor.java
@@ -22,7 +22,7 @@
* Stores the latest notification channel information for this notification
*/
public class NotificationChannelExtractor implements NotificationSignalExtractor {
- private static final String TAG = "BadgeExtractor";
+ private static final String TAG = "ChannelExtractor";
private static final boolean DBG = false;
private RankingConfig mConfig;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index aa6b3a3..6e84dd2 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1278,13 +1278,11 @@
R.array.config_notificationFallbackVibePattern,
VIBRATE_PATTERN_MAXLEN,
DEFAULT_VIBRATE_PATTERN);
-
mInCallNotificationUri = Uri.parse("file://" +
resources.getString(R.string.config_inCallNotificationSound));
mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
- .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
.build();
mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
@@ -4085,19 +4083,19 @@
if (mSystemReady && mAudioManager != null) {
Uri soundUri = record.getSound();
hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
-
long[] vibration = record.getVibration();
// Demote sound to vibration if vibration missing & phone in vibration mode.
if (vibration == null
&& hasValidSound
&& (mAudioManager.getRingerModeInternal()
- == AudioManager.RINGER_MODE_VIBRATE)) {
+ == AudioManager.RINGER_MODE_VIBRATE)
+ && mAudioManager.getStreamVolume(
+ AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
vibration = mFallbackVibrationPattern;
}
hasValidVibrate = vibration != null;
boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
-
if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
if (DBG) Slog.v(TAG, "Interrupting!");
if (hasValidSound) {
@@ -4194,8 +4192,9 @@
boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
// do not play notifications if there is a user of exclusive audio focus
// or the device is in vibrate mode
- if (!mAudioManager.isAudioFocusExclusive() && mAudioManager.getRingerModeInternal()
- != AudioManager.RINGER_MODE_VIBRATE) {
+ if (!mAudioManager.isAudioFocusExclusive() && (mAudioManager.getRingerModeInternal()
+ != AudioManager.RINGER_MODE_VIBRATE || mAudioManager.getStreamVolume(
+ AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
final long identity = Binder.clearCallingIdentity();
try {
final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
@@ -5905,8 +5904,8 @@
private class ShellCmd extends ShellCommand {
public static final String USAGE = "help\n"
- + "allow_listener COMPONENT\n"
- + "disallow_listener COMPONENT\n"
+ + "allow_listener COMPONENT [user_id]\n"
+ + "disallow_listener COMPONENT [user_id]\n"
+ "set_assistant COMPONENT\n"
+ "remove_assistant COMPONENT\n"
+ "allow_dnd PACKAGE\n"
@@ -5937,7 +5936,13 @@
pw.println("Invalid listener - must be a ComponentName");
return -1;
}
- getBinderService().setNotificationListenerAccessGranted(cn, true);
+ String userId = getNextArg();
+ if (userId == null) {
+ getBinderService().setNotificationListenerAccessGranted(cn, true);
+ } else {
+ getBinderService().setNotificationListenerAccessGrantedForUser(
+ cn, Integer.parseInt(userId), true);
+ }
}
break;
case "disallow_listener": {
@@ -5946,7 +5951,13 @@
pw.println("Invalid listener - must be a ComponentName");
return -1;
}
- getBinderService().setNotificationListenerAccessGranted(cn, false);
+ String userId = getNextArg();
+ if (userId == null) {
+ getBinderService().setNotificationListenerAccessGranted(cn, false);
+ } else {
+ getBinderService().setNotificationListenerAccessGrantedForUser(
+ cn, Integer.parseInt(userId), false);
+ }
}
break;
case "allow_assistant": {
diff --git a/services/core/java/com/android/server/notification/PriorityExtractor.java b/services/core/java/com/android/server/notification/PriorityExtractor.java
index 5d5d39d..7a287db 100644
--- a/services/core/java/com/android/server/notification/PriorityExtractor.java
+++ b/services/core/java/com/android/server/notification/PriorityExtractor.java
@@ -23,7 +23,7 @@
* Determines if the given notification can bypass Do Not Disturb.
*/
public class PriorityExtractor implements NotificationSignalExtractor {
- private static final String TAG = "ImportantTopicExtractor";
+ private static final String TAG = "PriorityExtractor";
private static final boolean DBG = false;
private RankingConfig mConfig;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index ffdafc5..9fcc67d 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -567,7 +567,7 @@
proto.write(ZenModeProto.ENABLED_ACTIVE_CONDITIONS, rule.toString());
}
}
- proto.write(ZenModeProto.POLICY, mConfig.toNotificationPolicy().toString());
+ mConfig.toNotificationPolicy().toProto(proto, ZenModeProto.POLICY);
proto.write(ZenModeProto.SUPPRESSED_EFFECTS, mSuppressedEffects);
}
}
diff --git a/services/core/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java
deleted file mode 100644
index 30fda1e..0000000
--- a/services/core/java/com/android/server/pm/BasePermission.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import android.content.pm.PackageParser;
-import android.content.pm.PermissionInfo;
-import android.os.UserHandle;
-
-final class BasePermission {
- final static int TYPE_NORMAL = 0;
-
- final static int TYPE_BUILTIN = 1;
-
- final static int TYPE_DYNAMIC = 2;
-
- final String name;
-
- String sourcePackage;
-
- PackageSettingBase packageSetting;
-
- final int type;
-
- int protectionLevel;
-
- PackageParser.Permission perm;
-
- PermissionInfo pendingInfo;
-
- /** UID that owns the definition of this permission */
- int uid;
-
- /** Additional GIDs given to apps granted this permission */
- private int[] gids;
-
- /**
- * Flag indicating that {@link #gids} should be adjusted based on the
- * {@link UserHandle} the granted app is running as.
- */
- private boolean perUser;
-
- BasePermission(String _name, String _sourcePackage, int _type) {
- name = _name;
- sourcePackage = _sourcePackage;
- type = _type;
- // Default to most conservative protection level.
- protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
- }
-
- @Override
- public String toString() {
- return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name
- + "}";
- }
-
- public void setGids(int[] gids, boolean perUser) {
- this.gids = gids;
- this.perUser = perUser;
- }
-
- public int[] computeGids(int userId) {
- if (perUser) {
- final int[] userGids = new int[gids.length];
- for (int i = 0; i < gids.length; i++) {
- userGids[i] = UserHandle.getUid(userId, gids[i]);
- }
- return userGids;
- } else {
- return gids;
- }
- }
-
- public boolean isRuntime() {
- return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
- == PermissionInfo.PROTECTION_DANGEROUS;
- }
-
- public boolean isDevelopment() {
- return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
- == PermissionInfo.PROTECTION_SIGNATURE
- && (protectionLevel & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0;
- }
-
- public boolean isInstant() {
- return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0;
- }
-
- public boolean isRuntimeOnly() {
- return (protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0;
- }
-}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index a3811ba..59e243a 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -52,6 +52,8 @@
import android.util.Slog;
import android.util.Xml;
import com.android.internal.util.XmlUtils;
+import com.android.server.pm.permission.BasePermission;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/DumpState.java b/services/core/java/com/android/server/pm/DumpState.java
new file mode 100644
index 0000000..7ebef83
--- /dev/null
+++ b/services/core/java/com/android/server/pm/DumpState.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm;
+
+public final class DumpState {
+ public static final int DUMP_LIBS = 1 << 0;
+ public static final int DUMP_FEATURES = 1 << 1;
+ public static final int DUMP_ACTIVITY_RESOLVERS = 1 << 2;
+ public static final int DUMP_SERVICE_RESOLVERS = 1 << 3;
+ public static final int DUMP_RECEIVER_RESOLVERS = 1 << 4;
+ public static final int DUMP_CONTENT_RESOLVERS = 1 << 5;
+ public static final int DUMP_PERMISSIONS = 1 << 6;
+ public static final int DUMP_PACKAGES = 1 << 7;
+ public static final int DUMP_SHARED_USERS = 1 << 8;
+ public static final int DUMP_MESSAGES = 1 << 9;
+ public static final int DUMP_PROVIDERS = 1 << 10;
+ public static final int DUMP_VERIFIERS = 1 << 11;
+ public static final int DUMP_PREFERRED = 1 << 12;
+ public static final int DUMP_PREFERRED_XML = 1 << 13;
+ public static final int DUMP_KEYSETS = 1 << 14;
+ public static final int DUMP_VERSION = 1 << 15;
+ public static final int DUMP_INSTALLS = 1 << 16;
+ public static final int DUMP_INTENT_FILTER_VERIFIERS = 1 << 17;
+ public static final int DUMP_DOMAIN_PREFERRED = 1 << 18;
+ public static final int DUMP_FROZEN = 1 << 19;
+ public static final int DUMP_DEXOPT = 1 << 20;
+ public static final int DUMP_COMPILER_STATS = 1 << 21;
+ public static final int DUMP_CHANGES = 1 << 22;
+ public static final int DUMP_VOLUMES = 1 << 23;
+
+ public static final int OPTION_SHOW_FILTERS = 1 << 0;
+
+ private int mTypes;
+
+ private int mOptions;
+
+ private boolean mTitlePrinted;
+
+ private SharedUserSetting mSharedUser;
+
+ public boolean isDumping(int type) {
+ if (mTypes == 0 && type != DUMP_PREFERRED_XML) {
+ return true;
+ }
+
+ return (mTypes & type) != 0;
+ }
+
+ public void setDump(int type) {
+ mTypes |= type;
+ }
+
+ public boolean isOptionEnabled(int option) {
+ return (mOptions & option) != 0;
+ }
+
+ public void setOptionEnabled(int option) {
+ mOptions |= option;
+ }
+
+ public boolean onTitlePrinted() {
+ final boolean printed = mTitlePrinted;
+ mTitlePrinted = true;
+ return printed;
+ }
+
+ public boolean getTitlePrinted() {
+ return mTitlePrinted;
+ }
+
+ public void setTitlePrinted(boolean enabled) {
+ mTitlePrinted = enabled;
+ }
+
+ public SharedUserSetting getSharedUser() {
+ return mSharedUser;
+ }
+
+ public void setSharedUser(SharedUserSetting user) {
+ mSharedUser = user;
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index e1e5b35..37b8ebb 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -49,6 +49,8 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
+import com.android.server.pm.permission.BasePermission;
+
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 49d3c8b..3574466 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -565,7 +565,7 @@
}
public void dumpLPr(PrintWriter pw, String packageName,
- PackageManagerService.DumpState dumpState) {
+ DumpState dumpState) {
boolean printedHeader = false;
for (ArrayMap.Entry<String, PackageSetting> e : mPackages.entrySet()) {
String keySetPackage = e.getKey();
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 4fafe34..925f595 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -23,6 +23,7 @@
import android.os.FileUtils;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.WorkSource;
import android.util.Log;
@@ -103,7 +104,17 @@
}
static boolean canOptimizePackage(PackageParser.Package pkg) {
- return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
+ // We do not dexopt a package with no code.
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
+ return false;
+ }
+
+ // We do not dexopt a priv-app package when pm.dexopt.priv-apps is false.
+ if (pkg.isPrivilegedApp()) {
+ return SystemProperties.getBoolean("pm.dexopt.priv-apps", true);
+ }
+
+ return true;
}
/**
@@ -425,7 +436,7 @@
}
if (useInfo.isUsedByOtherApps(path)) {
- pw.println("used be other apps: " + useInfo.getLoadingPackages(path));
+ pw.println("used by other apps: " + useInfo.getLoadingPackages(path));
}
Map<String, PackageDexUsage.DexUseInfo> dexUseInfoMap = useInfo.getDexUseInfoMap();
@@ -441,7 +452,7 @@
// TODO(calin): get the status of the oat file (needs installd call)
pw.println("class loader context: " + dexUseInfo.getClassLoaderContext());
if (dexUseInfo.isUsedByOtherApps()) {
- pw.println("used be other apps: " + dexUseInfo.getLoadingPackages());
+ pw.println("used by other apps: " + dexUseInfo.getLoadingPackages());
}
pw.decreaseIndent();
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 1fa37b9..a32ed17 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -243,35 +243,6 @@
}
}
- public void onSecureContainersAvailable() {
- synchronized (mSessions) {
- final ArraySet<String> unclaimed = new ArraySet<>();
- for (String cid : PackageHelper.getSecureContainerList()) {
- if (isStageName(cid)) {
- unclaimed.add(cid);
- }
- }
-
- // Ignore stages claimed by active sessions
- for (int i = 0; i < mSessions.size(); i++) {
- final PackageInstallerSession session = mSessions.valueAt(i);
- final String cid = session.stageCid;
-
- if (unclaimed.remove(cid)) {
- // Claimed by active session, mount it
- PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
- Process.SYSTEM_UID);
- }
- }
-
- // Clean up orphaned staging containers
- for (String cid : unclaimed) {
- Slog.w(TAG, "Deleting orphan container " + cid);
- PackageHelper.destroySdDir(cid);
- }
- }
- }
-
public static boolean isStageName(String name) {
final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
@@ -671,13 +642,6 @@
return "smdl" + sessionId + ".tmp";
}
- static void prepareExternalStageCid(String stageCid, long sizeBytes) throws IOException {
- if (PackageHelper.createSdDir(sizeBytes, stageCid, PackageManagerService.getEncryptKey(),
- Process.SYSTEM_UID, true) == null) {
- throw new IOException("Failed to create session cid: " + stageCid);
- }
- }
-
@Override
public SessionInfo getSessionInfo(int sessionId) {
synchronized (mSessions) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index ff6e5b3..d62f093 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -36,7 +36,6 @@
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
import static com.android.internal.util.XmlUtils.writeUriAttribute;
-import static com.android.server.pm.PackageInstallerService.prepareExternalStageCid;
import static com.android.server.pm.PackageInstallerService.prepareStageDir;
import android.Manifest;
@@ -481,12 +480,7 @@
if (stageDir != null) {
mResolvedStageDir = stageDir;
} else {
- final String path = PackageHelper.getSdDir(stageCid);
- if (path != null) {
- mResolvedStageDir = new File(path);
- } else {
- throw new IOException("Failed to resolve path to container " + stageCid);
- }
+ throw new IOException("Missing stageDir");
}
}
return mResolvedStageDir;
@@ -880,14 +874,6 @@
return;
}
- if (stageCid != null) {
- // Figure out the final installed size and resize the container once
- // and for all. Internally the parser handles straddling between two
- // locations when inheriting.
- final long finalSize = calculateInstalledSize();
- resizeContainer(stageCid, finalSize);
- }
-
// Inherit any packages and native libraries from existing install that
// haven't been overridden.
if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
@@ -924,11 +910,6 @@
// Unpack native libraries
extractNativeLibraries(mResolvedStageDir, params.abiOverride);
- // Container is ready to go, let's seal it up!
- if (stageCid != null) {
- finalizeAndFixContainer(stageCid);
- }
-
// We've reached point of no return; call into PMS to install the stage.
// Regardless of success or failure we always destroy session.
final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
@@ -953,7 +934,7 @@
}
mRelinquished = true;
- mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
+ mPm.installStage(mPackageName, stageDir, localObserver, params,
mInstallerPackageName, mInstallerUid, user, mCertificates);
}
@@ -1212,11 +1193,9 @@
// straddled between the inherited and staged APKs.
final PackageLite pkg = new PackageLite(null, baseApk, null, null, null, null,
splitPaths.toArray(new String[splitPaths.size()]), null);
- final boolean isForwardLocked =
- (params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
try {
- return PackageHelper.calculateInstalledSize(pkg, isForwardLocked, params.abiOverride);
+ return PackageHelper.calculateInstalledSize(pkg, params.abiOverride);
} catch (IOException e) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Failed to calculate install size", e);
@@ -1345,52 +1324,6 @@
}
}
- private static void resizeContainer(String cid, long targetSize)
- throws PackageManagerException {
- String path = PackageHelper.getSdDir(cid);
- if (path == null) {
- throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
- "Failed to find mounted " + cid);
- }
-
- final long currentSize = new File(path).getTotalSpace();
- if (currentSize > targetSize) {
- Slog.w(TAG, "Current size " + currentSize + " is larger than target size "
- + targetSize + "; skipping resize");
- return;
- }
-
- if (!PackageHelper.unMountSdDir(cid)) {
- throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
- "Failed to unmount " + cid + " before resize");
- }
-
- if (!PackageHelper.resizeSdDir(targetSize, cid,
- PackageManagerService.getEncryptKey())) {
- throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
- "Failed to resize " + cid + " to " + targetSize + " bytes");
- }
-
- path = PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
- Process.SYSTEM_UID, false);
- if (path == null) {
- throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
- "Failed to mount " + cid + " after resize");
- }
- }
-
- private void finalizeAndFixContainer(String cid) throws PackageManagerException {
- if (!PackageHelper.finalizeSdDir(cid)) {
- throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
- "Failed to finalize container " + cid);
- }
-
- if (!PackageHelper.fixSdPermissions(cid, defaultContainerGid, null)) {
- throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
- "Failed to fix permissions on container " + cid);
- }
- }
-
void setPermissionsResult(boolean accepted) {
if (!mSealed) {
throw new SecurityException("Must be sealed to accept permissions");
@@ -1419,20 +1352,8 @@
if (!mPrepared) {
if (stageDir != null) {
prepareStageDir(stageDir);
- } else if (stageCid != null) {
- 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;
- computeProgressLocked(true);
} else {
- throw new IllegalArgumentException(
- "Exactly one of stageDir or stageCid stage must be set");
+ throw new IllegalArgumentException("stageDir must be set");
}
mPrepared = true;
@@ -1534,9 +1455,6 @@
} catch (InstallerException ignored) {
}
}
- if (stageCid != null) {
- PackageHelper.destroySdDir(stageCid);
- }
}
void dump(IndentingPrintWriter pw) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d54ed61..d05c95f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -55,7 +55,6 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_USER_RESTRICTED;
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
-import static android.content.pm.PackageManager.INSTALL_FORWARD_LOCK;
import static android.content.pm.PackageManager.INSTALL_INTERNAL;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
@@ -230,7 +229,6 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Base64;
-import android.util.TimingsTraceLog;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.ExceptionUtils;
@@ -244,6 +242,7 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+import android.util.TimingsTraceLog;
import android.util.Xml;
import android.util.jar.StrictJarFile;
import android.util.proto.ProtoOutputStream;
@@ -289,6 +288,7 @@
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.PackageDexUsage;
+import com.android.server.pm.permission.BasePermission;
import com.android.server.storage.DeviceStorageMonitorInternal;
import dalvik.system.CloseGuard;
@@ -385,7 +385,7 @@
public class PackageManagerService extends IPackageManager.Stub
implements PackageSender {
static final String TAG = "PackageManager";
- static final boolean DEBUG_SETTINGS = false;
+ public static final boolean DEBUG_SETTINGS = false;
static final boolean DEBUG_PREFERRED = false;
static final boolean DEBUG_UPGRADE = false;
static final boolean DEBUG_DOMAIN_VERIFICATION = false;
@@ -396,7 +396,7 @@
private static final boolean DEBUG_SHOW_INFO = false;
private static final boolean DEBUG_PACKAGE_INFO = false;
private static final boolean DEBUG_INTENT_MATCHING = false;
- private static final boolean DEBUG_PACKAGE_SCANNING = false;
+ public static final boolean DEBUG_PACKAGE_SCANNING = false;
private static final boolean DEBUG_VERIFY = false;
private static final boolean DEBUG_FILTERS = false;
private static final boolean DEBUG_PERMISSIONS = false;
@@ -655,9 +655,6 @@
@GuardedBy("mPackages")
private boolean mDexOptDialogShown;
- /** The location for ASEC container files on internal storage. */
- final String mAsecInternalPath;
-
// Used for privilege escalation. MUST NOT BE CALLED WITH mPackages
// LOCK HELD. Can be called with mInstallLock held.
@GuardedBy("mInstallLock")
@@ -1316,7 +1313,6 @@
static final int POST_INSTALL = 9;
static final int MCS_RECONNECT = 10;
static final int MCS_GIVE_UP = 11;
- static final int UPDATED_MEDIA_STATUS = 12;
static final int WRITE_SETTINGS = 13;
static final int WRITE_PACKAGE_RESTRICTIONS = 14;
static final int PACKAGE_VERIFIED = 15;
@@ -1715,32 +1711,6 @@
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
} break;
- case UPDATED_MEDIA_STATUS: {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Got message UPDATED_MEDIA_STATUS");
- boolean reportStatus = msg.arg1 == 1;
- boolean doGc = msg.arg2 == 1;
- if (DEBUG_SD_INSTALL) Log.i(TAG, "reportStatus=" + reportStatus + ", doGc = " + doGc);
- if (doGc) {
- // Force a gc to clear up stale containers.
- Runtime.getRuntime().gc();
- }
- if (msg.obj != null) {
- @SuppressWarnings("unchecked")
- Set<AsecInstallArgs> args = (Set<AsecInstallArgs>) msg.obj;
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading all containers");
- // Unload containers
- unloadAllContainers(args);
- }
- if (reportStatus) {
- try {
- if (DEBUG_SD_INSTALL) Log.i(TAG,
- "Invoking StorageManagerService call back");
- PackageHelper.getStorageManager().finishMediaUpdate();
- } catch (RemoteException e) {
- Log.e(TAG, "StorageManagerService not running?");
- }
- }
- } break;
case WRITE_SETTINGS: {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPackages) {
@@ -2165,14 +2135,6 @@
unloadPrivatePackages(vol);
}
}
-
- if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.isPrimary()) {
- if (vol.state == VolumeInfo.STATE_MOUNTED) {
- updateExternalMediaStatus(true, false);
- } else if (vol.state == VolumeInfo.STATE_EJECTING) {
- updateExternalMediaStatus(false, false);
- }
- }
}
@Override
@@ -2490,7 +2452,6 @@
File dataDir = Environment.getDataDirectory();
mAppInstallDir = new File(dataDir, "app");
mAppLib32InstallDir = new File(dataDir, "app-lib");
- mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
sUserManager = new UserManagerService(context, this,
new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
@@ -4290,18 +4251,6 @@
return null;
}
- static PermissionInfo generatePermissionInfo(BasePermission bp, int flags) {
- if (bp.perm != null) {
- return PackageParser.generatePermissionInfo(bp.perm, flags);
- }
- PermissionInfo pi = new PermissionInfo();
- pi.name = bp.name;
- pi.packageName = bp.sourcePackage;
- pi.nonLocalizedLabel = bp.name;
- pi.protectionLevel = bp.protectionLevel;
- return pi;
- }
-
@Override
public PermissionInfo getPermissionInfo(String name, String packageName, int flags) {
final int callingUid = Binder.getCallingUid();
@@ -4310,24 +4259,13 @@
}
// reader
synchronized (mPackages) {
- final BasePermission p = mSettings.mPermissions.get(name);
- if (p == null) {
+ final BasePermission bp = mSettings.mPermissions.get(name);
+ if (bp == null) {
return null;
}
- // If the caller is an app that targets pre 26 SDK drop protection flags.
- PermissionInfo permissionInfo = generatePermissionInfo(p, flags);
- if (permissionInfo != null) {
- final int protectionLevel = adjustPermissionProtectionFlagsLPr(
- permissionInfo.protectionLevel, packageName, callingUid);
- if (permissionInfo.protectionLevel != protectionLevel) {
- // If we return different protection level, don't use the cached info
- if (p.perm != null && p.perm.info == permissionInfo) {
- permissionInfo = new PermissionInfo(permissionInfo);
- }
- permissionInfo.protectionLevel = protectionLevel;
- }
- }
- return permissionInfo;
+ final int adjustedProtectionLevel = adjustPermissionProtectionFlagsLPr(
+ bp.getProtectionLevel(), packageName, callingUid);
+ return bp.generatePermissionInfo(adjustedProtectionLevel, flags);
}
}
@@ -4374,28 +4312,23 @@
}
@Override
- public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String group,
+ public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String groupName,
int flags) {
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return null;
}
// reader
synchronized (mPackages) {
- if (group != null && !mPermissionGroups.containsKey(group)) {
+ if (groupName != null && !mPermissionGroups.containsKey(groupName)) {
// This is thrown as NameNotFoundException
return null;
}
ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
- for (BasePermission p : mSettings.mPermissions.values()) {
- if (group == null) {
- if (p.perm == null || p.perm.info.group == null) {
- out.add(generatePermissionInfo(p, flags));
- }
- } else {
- if (p.perm != null && group.equals(p.perm.info.group)) {
- out.add(PackageParser.generatePermissionInfo(p.perm, flags));
- }
+ for (BasePermission bp : mSettings.mPermissions.values()) {
+ final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags);
+ if (pi != null) {
+ out.add(pi);
}
}
return new ParceledListSlice<>(out);
@@ -5472,75 +5405,10 @@
}
}
- private BasePermission findPermissionTreeLP(String permName) {
- for(BasePermission bp : mSettings.mPermissionTrees.values()) {
- if (permName.startsWith(bp.name) &&
- permName.length() > bp.name.length() &&
- permName.charAt(bp.name.length()) == '.') {
- return bp;
- }
- }
- return null;
- }
-
- private BasePermission checkPermissionTreeLP(String permName) {
- if (permName != null) {
- BasePermission bp = findPermissionTreeLP(permName);
- if (bp != null) {
- if (bp.uid == UserHandle.getAppId(Binder.getCallingUid())) {
- return bp;
- }
- throw new SecurityException("Calling uid "
- + Binder.getCallingUid()
- + " is not allowed to add to permission tree "
- + bp.name + " owned by uid " + bp.uid);
- }
- }
- throw new SecurityException("No permission tree found for " + permName);
- }
-
- static boolean compareStrings(CharSequence s1, CharSequence s2) {
- if (s1 == null) {
- return s2 == null;
- }
- if (s2 == null) {
- return false;
- }
- if (s1.getClass() != s2.getClass()) {
- return false;
- }
- return s1.equals(s2);
- }
-
- static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) {
- if (pi1.icon != pi2.icon) return false;
- if (pi1.logo != pi2.logo) return false;
- if (pi1.protectionLevel != pi2.protectionLevel) return false;
- if (!compareStrings(pi1.name, pi2.name)) return false;
- if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
- // We'll take care of setting this one.
- if (!compareStrings(pi1.packageName, pi2.packageName)) return false;
- // These are not currently stored in settings.
- //if (!compareStrings(pi1.group, pi2.group)) return false;
- //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
- //if (pi1.labelRes != pi2.labelRes) return false;
- //if (pi1.descriptionRes != pi2.descriptionRes) return false;
- return true;
- }
-
- int permissionInfoFootprint(PermissionInfo info) {
- int size = info.name.length();
- if (info.nonLocalizedLabel != null) size += info.nonLocalizedLabel.length();
- if (info.nonLocalizedDescription != null) size += info.nonLocalizedDescription.length();
- return size;
- }
-
int calculateCurrentPermissionFootprintLocked(BasePermission tree) {
int size = 0;
for (BasePermission perm : mSettings.mPermissions.values()) {
- if (perm.uid == tree.uid) {
- size += perm.name.length() + permissionInfoFootprint(perm.perm.info);
- }
+ size += tree.calculateFootprint(perm);
}
return size;
}
@@ -5548,9 +5416,9 @@
void enforcePermissionCapLocked(PermissionInfo info, BasePermission tree) {
// We calculate the max size of permissions defined by this uid and throw
// if that plus the size of 'info' would exceed our stated maximum.
- if (tree.uid != Process.SYSTEM_UID) {
+ if (tree.getUid() != Process.SYSTEM_UID) {
final int curTreeSize = calculateCurrentPermissionFootprintLocked(tree);
- if (curTreeSize + permissionInfoFootprint(info) > MAX_PERMISSION_TREE_FOOTPRINT) {
+ if (curTreeSize + info.calculateFootprint() > MAX_PERMISSION_TREE_FOOTPRINT) {
throw new SecurityException("Permission tree size cap exceeded");
}
}
@@ -5563,33 +5431,21 @@
if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
throw new SecurityException("Label must be specified in permission");
}
- BasePermission tree = checkPermissionTreeLP(info.name);
+ BasePermission tree = BasePermission.enforcePermissionTreeLP(
+ mSettings.mPermissionTrees, info.name, Binder.getCallingUid());
BasePermission bp = mSettings.mPermissions.get(info.name);
boolean added = bp == null;
- boolean changed = true;
int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);
if (added) {
enforcePermissionCapLocked(info, tree);
- bp = new BasePermission(info.name, tree.sourcePackage,
+ bp = new BasePermission(info.name, tree.getSourcePackageName(),
BasePermission.TYPE_DYNAMIC);
- } else if (bp.type != BasePermission.TYPE_DYNAMIC) {
+ } else if (bp.isDynamic()) {
throw new SecurityException(
"Not allowed to modify non-dynamic permission "
+ info.name);
- } else {
- if (bp.protectionLevel == fixedLevel
- && bp.perm.owner.equals(tree.perm.owner)
- && bp.uid == tree.uid
- && comparePermissionInfos(bp.perm.info, info)) {
- changed = false;
- }
}
- bp.protectionLevel = fixedLevel;
- info = new PermissionInfo(info);
- info.protectionLevel = fixedLevel;
- bp.perm = new PackageParser.Permission(tree.perm.owner, info);
- bp.perm.info.packageName = tree.perm.info.packageName;
- bp.uid = tree.uid;
+ final boolean changed = bp.addToTree(fixedLevel, info, tree);
if (added) {
mSettings.mPermissions.put(info.name, bp);
}
@@ -5623,10 +5479,11 @@
throw new SecurityException("Instant applications don't have access to this method");
}
synchronized (mPackages) {
- checkPermissionTreeLP(name);
+ BasePermission.enforcePermissionTreeLP(
+ mSettings.mPermissionTrees, name, Binder.getCallingUid());
BasePermission bp = mSettings.mPermissions.get(name);
if (bp != null) {
- if (bp.type != BasePermission.TYPE_DYNAMIC) {
+ if (bp.isDynamic()) {
throw new SecurityException(
"Not allowed to modify non-dynamic permission "
+ name);
@@ -5637,19 +5494,6 @@
}
}
- private static void enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(
- PackageParser.Package pkg, BasePermission bp) {
- int index = pkg.requestedPermissions.indexOf(bp.name);
- if (index == -1) {
- throw new SecurityException("Package " + pkg.packageName
- + " has not requested permission " + bp.name);
- }
- if (!bp.isRuntime() && !bp.isDevelopment()) {
- throw new SecurityException("Permission " + bp.name
- + " is not a changeable permission type");
- }
- }
-
@Override
public void grantRuntimePermission(String packageName, String name, final int userId) {
grantRuntimePermission(packageName, name, userId, false /* Only if not fixed by policy */);
@@ -5689,7 +5533,7 @@
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
@@ -5818,7 +5662,7 @@
throw new IllegalArgumentException("Unknown permission: " + name);
}
- enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
@@ -9124,7 +8968,7 @@
return fname;
}
- static void reportSettingsProblem(int priority, String msg) {
+ public static void reportSettingsProblem(int priority, String msg) {
logCriticalInfo(priority, msg);
}
@@ -9784,7 +9628,9 @@
pkg.applicationInfo.uid, pkg.packageName)) {
Log.e(TAG, "Installer failed to copy system profile!");
} else {
- useProfileForDexopt = true;
+ // Disabled as this causes speed-profile compilation during first boot
+ // even if things are already compiled.
+ // useProfileForDexopt = true;
}
} catch (Exception e) {
Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ",
@@ -9841,18 +9687,6 @@
PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
PackageManagerService.REASON_BACKGROUND_DEXOPT);
}
- // If the OTA updates a system app which was previously preopted to a non-preopted state
- // the app might end up being verified at runtime. That's because by default the apps
- // are verify-profile but for preopted apps there's no profile.
- // Do a hacky check to ensure that if we have no profiles (a reasonable indication
- // that before the OTA the app was preopted) the app gets compiled with a non-profile
- // filter (by default 'quicken').
- // Note that at this stage unused apps are already filtered.
- if (isSystemApp(pkg) &&
- DexFile.isProfileGuidedCompilerFilter(pkgCompilerFilter) &&
- !Environment.getReferenceProfile(pkg.packageName).exists()) {
- pkgCompilerFilter = getNonProfileGuidedCompilerFilter(pkgCompilerFilter);
- }
// checkProfiles is false to avoid merging profiles during boot which
// might interfere with background compilation (b/28612421).
@@ -10736,6 +10570,12 @@
assertPackageIsValid(pkg, policyFlags, scanFlags);
+ if (Build.IS_DEBUGGABLE &&
+ pkg.isPrivilegedApp() &&
+ !SystemProperties.getBoolean("pm.dexopt.priv-apps", true)) {
+ PackageManagerServiceUtils.logPackageHasUncompressedCode(pkg);
+ }
+
// Initialize package source and resource directories
final File scanFile = new File(pkg.codePath);
final File destCodeFile = new File(pkg.applicationInfo.getCodePath());
@@ -11899,84 +11739,12 @@
}
}
- ArrayMap<String, BasePermission> permissionMap =
+ final ArrayMap<String, BasePermission> permissionMap =
p.tree ? mSettings.mPermissionTrees
: mSettings.mPermissions;
- BasePermission bp = permissionMap.get(p.info.name);
-
- // Allow system apps to redefine non-system permissions
- if (bp != null && !Objects.equals(bp.sourcePackage, p.info.packageName)) {
- final boolean currentOwnerIsSystem = (bp.perm != null
- && isSystemApp(bp.perm.owner));
- if (isSystemApp(p.owner)) {
- if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
- // It's a built-in permission and no owner, take ownership now
- bp.packageSetting = pkgSetting;
- bp.perm = p;
- bp.uid = pkg.applicationInfo.uid;
- bp.sourcePackage = p.info.packageName;
- p.info.flags |= PermissionInfo.FLAG_INSTALLED;
- } else if (!currentOwnerIsSystem) {
- String msg = "New decl " + p.owner + " of permission "
- + p.info.name + " is system; overriding " + bp.sourcePackage;
- reportSettingsProblem(Log.WARN, msg);
- bp = null;
- }
- }
- }
-
- if (bp == null) {
- bp = new BasePermission(p.info.name, p.info.packageName,
- BasePermission.TYPE_NORMAL);
- permissionMap.put(p.info.name, bp);
- }
-
- if (bp.perm == null) {
- if (bp.sourcePackage == null
- || bp.sourcePackage.equals(p.info.packageName)) {
- BasePermission tree = findPermissionTreeLP(p.info.name);
- if (tree == null
- || tree.sourcePackage.equals(p.info.packageName)) {
- bp.packageSetting = pkgSetting;
- bp.perm = p;
- bp.uid = pkg.applicationInfo.uid;
- bp.sourcePackage = p.info.packageName;
- p.info.flags |= PermissionInfo.FLAG_INSTALLED;
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(p.info.name);
- }
- } else {
- Slog.w(TAG, "Permission " + p.info.name + " from package "
- + p.info.packageName + " ignored: base tree "
- + tree.name + " is from package "
- + tree.sourcePackage);
- }
- } else {
- Slog.w(TAG, "Permission " + p.info.name + " from package "
- + p.info.packageName + " ignored: original from "
- + bp.sourcePackage);
- }
- } else if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append("DUP:");
- r.append(p.info.name);
- }
- if (bp.perm == p) {
- bp.protectionLevel = p.info.protectionLevel;
- }
- }
-
- if (r != null) {
- if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permissions: " + r);
+ final BasePermission bp = BasePermission.createOrUpdate(
+ permissionMap.get(p.info.name), p, pkg, mSettings.mPermissionTrees, chatty);
+ permissionMap.put(p.info.name, bp);
}
N = pkg.instrumentation.size();
@@ -12710,8 +12478,8 @@
if (bp == null) {
bp = mSettings.mPermissionTrees.get(p.info.name);
}
- if (bp != null && bp.perm == p) {
- bp.perm = null;
+ if (bp != null && bp.isPermission(p)) {
+ bp.setPermission(null);
if (DEBUG_REMOVE && chatty) {
if (r == null) {
r = new StringBuilder(256);
@@ -12737,7 +12505,7 @@
for (i=0; i<N; i++) {
String perm = pkg.requestedPermissions.get(i);
BasePermission bp = mSettings.mPermissions.get(perm);
- if (bp != null && (bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
+ if (bp != null && bp.isAppOp()) {
ArraySet<String> appOpPkgs = mAppOpPermissionPackages.get(perm);
if (appOpPkgs != null) {
appOpPkgs.remove(pkg.packageName);
@@ -12842,23 +12610,32 @@
private void updatePermissionsLPw(String changingPkg,
PackageParser.Package pkgInfo, String replaceVolumeUuid, int flags) {
+ // TODO: Most of the methods exposing BasePermission internals [source package name,
+ // etc..] shouldn't be needed. Instead, when we've parsed a permission that doesn't
+ // have package settings, we should make note of it elsewhere [map between
+ // source package name and BasePermission] and cycle through that here. Then we
+ // define a single method on BasePermission that takes a PackageSetting, changing
+ // package name and a package.
+ // NOTE: With this approach, we also don't need to tree trees differently than
+ // normal permissions. Today, we need two separate loops because these BasePermission
+ // objects are stored separately.
// Make sure there are no dangling permission trees.
Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator();
while (it.hasNext()) {
final BasePermission bp = it.next();
- if (bp.packageSetting == null) {
+ if (bp.getSourcePackageSetting() == null) {
// We may not yet have parsed the package, so just see if
// we still know about its settings.
- bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
+ bp.setSourcePackageSetting(mSettings.mPackages.get(bp.getSourcePackageName()));
}
- if (bp.packageSetting == null) {
- Slog.w(TAG, "Removing dangling permission tree: " + bp.name
- + " from package " + bp.sourcePackage);
+ if (bp.getSourcePackageSetting() == null) {
+ Slog.w(TAG, "Removing dangling permission tree: " + bp.getName()
+ + " from package " + bp.getSourcePackageName());
it.remove();
- } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
- if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
- Slog.i(TAG, "Removing old permission tree: " + bp.name
- + " from package " + bp.sourcePackage);
+ } else if (changingPkg != null && changingPkg.equals(bp.getSourcePackageName())) {
+ if (pkgInfo == null || !hasPermission(pkgInfo, bp.getName())) {
+ Slog.i(TAG, "Removing old permission tree: " + bp.getName()
+ + " from package " + bp.getSourcePackageName());
flags |= UPDATE_PERMISSIONS_ALL;
it.remove();
}
@@ -12870,35 +12647,22 @@
it = mSettings.mPermissions.values().iterator();
while (it.hasNext()) {
final BasePermission bp = it.next();
- if (bp.type == BasePermission.TYPE_DYNAMIC) {
- if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
- + bp.name + " pkg=" + bp.sourcePackage
- + " info=" + bp.pendingInfo);
- if (bp.packageSetting == null && bp.pendingInfo != null) {
- final BasePermission tree = findPermissionTreeLP(bp.name);
- if (tree != null && tree.perm != null) {
- bp.packageSetting = tree.packageSetting;
- bp.perm = new PackageParser.Permission(tree.perm.owner,
- new PermissionInfo(bp.pendingInfo));
- bp.perm.info.packageName = tree.perm.info.packageName;
- bp.perm.info.name = bp.name;
- bp.uid = tree.uid;
- }
- }
+ if (bp.isDynamic()) {
+ bp.updateDynamicPermission(mSettings.mPermissionTrees);
}
- if (bp.packageSetting == null) {
+ if (bp.getSourcePackageSetting() == null) {
// We may not yet have parsed the package, so just see if
// we still know about its settings.
- bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
+ bp.setSourcePackageSetting(mSettings.mPackages.get(bp.getSourcePackageName()));
}
- if (bp.packageSetting == null) {
- Slog.w(TAG, "Removing dangling permission: " + bp.name
- + " from package " + bp.sourcePackage);
+ if (bp.getSourcePackageSetting() == null) {
+ Slog.w(TAG, "Removing dangling permission: " + bp.getName()
+ + " from package " + bp.getSourcePackageName());
it.remove();
- } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
- if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
- Slog.i(TAG, "Removing old permission: " + bp.name
- + " from package " + bp.sourcePackage);
+ } else if (changingPkg != null && changingPkg.equals(bp.getSourcePackageName())) {
+ if (pkgInfo == null || !hasPermission(pkgInfo, bp.getName())) {
+ Slog.i(TAG, "Removing old permission: " + bp.getName()
+ + " from package " + bp.getSourcePackageName());
flags |= UPDATE_PERMISSIONS_ALL;
it.remove();
}
@@ -12990,7 +12754,7 @@
Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
}
- if (bp == null || bp.packageSetting == null) {
+ if (bp == null || bp.getSourcePackageSetting() == null) {
if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
if (DEBUG_PERMISSIONS) {
Slog.i(TAG, "Unknown permission " + name
@@ -13004,7 +12768,7 @@
// Limit ephemeral apps to ephemeral allowed permissions.
if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {
if (DEBUG_PERMISSIONS) {
- Log.i(TAG, "Denying non-ephemeral permission " + bp.name + " for package "
+ Log.i(TAG, "Denying non-ephemeral permission " + bp.getName() + " for package "
+ pkg.packageName);
}
continue;
@@ -13012,64 +12776,57 @@
if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
if (DEBUG_PERMISSIONS) {
- Log.i(TAG, "Denying runtime-only permission " + bp.name + " for package "
+ Log.i(TAG, "Denying runtime-only permission " + bp.getName() + " for package "
+ pkg.packageName);
}
continue;
}
- final String perm = bp.name;
+ final String perm = bp.getName();
boolean allowedSig = false;
int grant = GRANT_DENIED;
// Keep track of app op permissions.
- if ((bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
- ArraySet<String> pkgs = mAppOpPermissionPackages.get(bp.name);
+ if (bp.isAppOp()) {
+ ArraySet<String> pkgs = mAppOpPermissionPackages.get(perm);
if (pkgs == null) {
pkgs = new ArraySet<>();
- mAppOpPermissionPackages.put(bp.name, pkgs);
+ mAppOpPermissionPackages.put(perm, pkgs);
}
pkgs.add(pkg.packageName);
}
- final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
- switch (level) {
- case PermissionInfo.PROTECTION_NORMAL: {
- // For all apps normal permissions are install time ones.
+ if (bp.isNormal()) {
+ // For all apps normal permissions are install time ones.
+ grant = GRANT_INSTALL;
+ } else if (bp.isRuntime()) {
+ // If a permission review is required for legacy apps we represent
+ // their permissions as always granted runtime ones since we need
+ // to keep the review required permission flag per user while an
+ // install permission's state is shared across all users.
+ if (!appSupportsRuntimePermissions && !mPermissionReviewRequired) {
+ // For legacy apps dangerous permissions are install time ones.
grant = GRANT_INSTALL;
- } break;
-
- case PermissionInfo.PROTECTION_DANGEROUS: {
- // If a permission review is required for legacy apps we represent
- // their permissions as always granted runtime ones since we need
- // to keep the review required permission flag per user while an
- // install permission's state is shared across all users.
- if (!appSupportsRuntimePermissions && !mPermissionReviewRequired) {
- // For legacy apps dangerous permissions are install time ones.
- grant = GRANT_INSTALL;
- } else if (origPermissions.hasInstallPermission(bp.name)) {
- // For legacy apps that became modern, install becomes runtime.
- grant = GRANT_UPGRADE;
- } else if (mPromoteSystemApps
- && isSystemApp(ps)
- && mExistingSystemPackages.contains(ps.name)) {
- // For legacy system apps, install becomes runtime.
- // We cannot check hasInstallPermission() for system apps since those
- // permissions were granted implicitly and not persisted pre-M.
- grant = GRANT_UPGRADE;
- } else {
- // For modern apps keep runtime permissions unchanged.
- grant = GRANT_RUNTIME;
- }
- } break;
-
- case PermissionInfo.PROTECTION_SIGNATURE: {
- // For all apps signature permissions are install time ones.
- allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
- if (allowedSig) {
- grant = GRANT_INSTALL;
- }
- } break;
+ } else if (origPermissions.hasInstallPermission(bp.getName())) {
+ // For legacy apps that became modern, install becomes runtime.
+ grant = GRANT_UPGRADE;
+ } else if (mPromoteSystemApps
+ && isSystemApp(ps)
+ && mExistingSystemPackages.contains(ps.name)) {
+ // For legacy system apps, install becomes runtime.
+ // We cannot check hasInstallPermission() for system apps since those
+ // permissions were granted implicitly and not persisted pre-M.
+ grant = GRANT_UPGRADE;
+ } else {
+ // For modern apps keep runtime permissions unchanged.
+ grant = GRANT_RUNTIME;
+ }
+ } else if (bp.isSignature()) {
+ // For all apps signature permissions are install time ones.
+ allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
+ if (allowedSig) {
+ grant = GRANT_INSTALL;
+ }
}
if (DEBUG_PERMISSIONS) {
@@ -13098,7 +12855,7 @@
// for legacy apps
for (int userId : UserManagerService.getInstance().getUserIds()) {
if (origPermissions.getRuntimePermissionState(
- bp.name, userId) != null) {
+ perm, userId) != null) {
// Revoke the runtime permission and clear the flags.
origPermissions.revokeRuntimePermission(bp, userId);
origPermissions.updatePermissionFlags(bp, userId,
@@ -13119,10 +12876,10 @@
// Grant previously granted runtime permissions.
for (int userId : UserManagerService.getInstance().getUserIds()) {
PermissionState permissionState = origPermissions
- .getRuntimePermissionState(bp.name, userId);
+ .getRuntimePermissionState(perm, userId);
int flags = permissionState != null
? permissionState.getFlags() : 0;
- if (origPermissions.hasRuntimePermission(bp.name, userId)) {
+ if (origPermissions.hasRuntimePermission(perm, userId)) {
// Don't propagate the permission in a permission review mode if
// the former was revoked, i.e. marked to not propagate on upgrade.
// Note that in a permission review mode install permissions are
@@ -13165,7 +12922,7 @@
// permissions as these are the only ones the platform knows
// how to disable the API to simulate revocation as legacy
// apps don't expect to run with revoked permissions.
- if (PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage)) {
+ if (PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName())) {
if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
// We changed the flags, hence have to write.
@@ -13188,7 +12945,7 @@
case GRANT_UPGRADE: {
// Grant runtime permissions for a previously held install permission.
PermissionState permissionState = origPermissions
- .getInstallPermissionState(bp.name);
+ .getInstallPermissionState(perm);
final int flags = permissionState != null ? permissionState.getFlags() : 0;
if (origPermissions.revokeInstallPermission(bp)
@@ -13236,10 +12993,10 @@
changedInstallPermission = true;
Slog.i(TAG, "Un-granting permission " + perm
+ " from package " + pkg.packageName
- + " (protectionLevel=" + bp.protectionLevel
+ + " (protectionLevel=" + bp.getProtectionLevel()
+ " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+ ")");
- } else if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) == 0) {
+ } else if (bp.isAppOp()) {
// Don't print warning for app op permissions, since it is fine for them
// not to be granted, there is a UI for the user to decide.
if (DEBUG_PERMISSIONS
@@ -13247,7 +13004,7 @@
|| packageOfInterest.equals(pkg.packageName))) {
Slog.i(TAG, "Not granting permission " + perm
+ " to package " + pkg.packageName
- + " (protectionLevel=" + bp.protectionLevel
+ + " (protectionLevel=" + bp.getProtectionLevel()
+ " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+ ")");
}
@@ -13307,13 +13064,11 @@
private boolean grantSignaturePermission(String perm, PackageParser.Package pkg,
BasePermission bp, PermissionsState origPermissions) {
- boolean oemPermission = (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_OEM) != 0;
- boolean privilegedPermission = (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0;
+ boolean oemPermission = bp.isOEM();
+ boolean privilegedPermission = bp.isPrivileged();
boolean privappPermissionsDisable =
RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE;
- boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage);
+ boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName());
boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName);
if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivilegedApp()
&& !platformPackage && platformPermission) {
@@ -13342,7 +13097,7 @@
}
}
boolean allowed = (compareSignatures(
- bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
+ bp.getSourcePackageSetting().signatures.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH)
|| (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
@@ -13419,39 +13174,37 @@
}
}
if (!allowed) {
- if (!allowed && (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_PRE23) != 0
+ if (!allowed
+ && bp.isPre23()
&& pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
// If this was a previously normal/dangerous permission that got moved
// to a system permission as part of the runtime permission redesign, then
// we still want to blindly grant it to old apps.
allowed = true;
}
- if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0
+ if (!allowed && bp.isInstaller()
&& pkg.packageName.equals(mRequiredInstallerPackage)) {
// If this permission is to be granted to the system installer and
// this app is an installer, then it gets the permission.
allowed = true;
}
- if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0
+ if (!allowed && bp.isVerifier()
&& pkg.packageName.equals(mRequiredVerifierPackage)) {
// If this permission is to be granted to the system verifier and
// this app is a verifier, then it gets the permission.
allowed = true;
}
- if (!allowed && (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0
+ if (!allowed && bp.isPreInstalled()
&& isSystemApp(pkg)) {
// Any pre-installed system app is allowed to get this permission.
allowed = true;
}
- if (!allowed && (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
+ if (!allowed && bp.isDevelopment()) {
// For development permissions, a development permission
// is granted only if it was already granted.
allowed = origPermissions.hasInstallPermission(perm);
}
- if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_SETUP) != 0
+ if (!allowed && bp.isSetup()
&& pkg.packageName.equals(mSetupWizardPackage)) {
// If this permission is to be granted to the system setup wizard and
// this app is a setup wizard, then it gets the permission.
@@ -14880,7 +14633,7 @@
return installReason;
}
- void installStage(String packageName, File stagedDir, String stagedCid,
+ void installStage(String packageName, File stagedDir,
IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
String installerPackageName, int installerUid, UserHandle user,
Certificate[][] certificates) {
@@ -14893,12 +14646,7 @@
sessionParams.originatingUri, sessionParams.referrerUri,
sessionParams.originatingUid, installerUid);
- final OriginInfo origin;
- if (stagedDir != null) {
- origin = OriginInfo.fromStagedFile(stagedDir);
- } else {
- origin = OriginInfo.fromStagedContainer(stagedCid);
- }
+ final OriginInfo origin = OriginInfo.fromStagedFile(stagedDir);
final Message msg = mHandler.obtainMessage(INIT_COPY);
final int installReason = fixUpInstallReason(installerPackageName, installerUid,
@@ -16098,7 +15846,6 @@
* file, or a cluster directory. This location may be untrusted.
*/
final File file;
- final String cid;
/**
* Flag indicating that {@link #file} or {@link #cid} has already been
@@ -16117,35 +15864,27 @@
final File resolvedFile;
static OriginInfo fromNothing() {
- return new OriginInfo(null, null, false, false);
+ return new OriginInfo(null, false, false);
}
static OriginInfo fromUntrustedFile(File file) {
- return new OriginInfo(file, null, false, false);
+ return new OriginInfo(file, false, false);
}
static OriginInfo fromExistingFile(File file) {
- return new OriginInfo(file, null, false, true);
+ return new OriginInfo(file, false, true);
}
static OriginInfo fromStagedFile(File file) {
- return new OriginInfo(file, null, true, false);
+ return new OriginInfo(file, true, false);
}
- static OriginInfo fromStagedContainer(String cid) {
- return new OriginInfo(null, cid, true, false);
- }
-
- private OriginInfo(File file, String cid, boolean staged, boolean existing) {
+ private OriginInfo(File file, boolean staged, boolean existing) {
this.file = file;
- this.cid = cid;
this.staged = staged;
this.existing = existing;
- if (cid != null) {
- resolvedPath = PackageHelper.getSdDir(cid);
- resolvedFile = new File(resolvedPath);
- } else if (file != null) {
+ if (file != null) {
resolvedPath = file.getAbsolutePath();
resolvedFile = file;
} else {
@@ -16238,7 +15977,7 @@
@Override
public String toString() {
return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
- + " file=" + origin.file + " cid=" + origin.cid + "}";
+ + " file=" + origin.file + "}";
}
private int installLocationPolicy(PackageInfoLite pkgLite) {
@@ -16349,9 +16088,6 @@
if (origin.file != null) {
installFlags |= PackageManager.INSTALL_INTERNAL;
installFlags &= ~PackageManager.INSTALL_EXTERNAL;
- } else if (origin.cid != null) {
- installFlags |= PackageManager.INSTALL_EXTERNAL;
- installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else {
throw new IllegalStateException("Invalid stage location");
}
@@ -16389,7 +16125,7 @@
Environment.getDataDirectory());
final long sizeBytes = mContainerService.calculateInstalledSize(
- origin.resolvedPath, isForwardLocked(), packageAbiOverride);
+ origin.resolvedPath, packageAbiOverride);
try {
mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
@@ -16626,43 +16362,11 @@
mArgs = createInstallArgs(this);
mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
}
-
- public boolean isForwardLocked() {
- return (installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
- }
- }
-
- /**
- * Used during creation of InstallArgs
- *
- * @param installFlags package installation flags
- * @return true if should be installed on external storage
- */
- private static boolean installOnExternalAsec(int installFlags) {
- if ((installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
- return false;
- }
- if ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
- return true;
- }
- return false;
- }
-
- /**
- * Used during creation of InstallArgs
- *
- * @param installFlags package installation flags
- * @return true if should be installed as forward locked
- */
- private static boolean installForwardLocked(int installFlags) {
- return (installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
}
private InstallArgs createInstallArgs(InstallParams params) {
if (params.move != null) {
return new MoveInstallArgs(params);
- } else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
- return new AsecInstallArgs(params);
} else {
return new FileInstallArgs(params);
}
@@ -16674,27 +16378,7 @@
*/
private InstallArgs createInstallArgsForExisting(int installFlags, String codePath,
String resourcePath, String[] instructionSets) {
- final boolean isInAsec;
- if (installOnExternalAsec(installFlags)) {
- /* Apps on SD card are always in ASEC containers. */
- isInAsec = true;
- } else if (installForwardLocked(installFlags)
- && !codePath.startsWith(mDrmAppPrivateInstallDir.getAbsolutePath())) {
- /*
- * Forward-locked apps are only in ASEC containers if they're the
- * new style
- */
- isInAsec = true;
- } else {
- isInAsec = false;
- }
-
- if (isInAsec) {
- return new AsecInstallArgs(codePath, instructionSets,
- installOnExternalAsec(installFlags), installForwardLocked(installFlags));
- } else {
- return new FileInstallArgs(codePath, resourcePath, instructionSets);
- }
+ return new FileInstallArgs(codePath, resourcePath, instructionSets);
}
static abstract class InstallArgs {
@@ -17028,11 +16712,6 @@
}
}
- private boolean isAsecExternal(String cid) {
- final String asecPath = PackageHelper.getSdFilesystem(cid);
- return !asecPath.startsWith(mAsecInternalPath);
- }
-
private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
PackageManagerException {
if (copyRet < 0) {
@@ -17055,308 +16734,6 @@
}
/**
- * Logic to handle installation of ASEC applications, including copying and
- * renaming logic.
- */
- class AsecInstallArgs extends InstallArgs {
- static final String RES_FILE_NAME = "pkg.apk";
- static final String PUBLIC_RES_FILE_NAME = "res.zip";
-
- String cid;
- String packagePath;
- String resourcePath;
-
- /** New install */
- AsecInstallArgs(InstallParams params) {
- super(params.origin, params.move, params.observer, params.installFlags,
- params.installerPackageName, params.volumeUuid,
- params.getUser(), null /* instruction sets */, params.packageAbiOverride,
- params.grantedRuntimePermissions,
- params.traceMethod, params.traceCookie, params.certificates,
- params.installReason);
- }
-
- /** Existing install */
- AsecInstallArgs(String fullCodePath, String[] instructionSets,
- boolean isExternal, boolean isForwardLocked) {
- super(OriginInfo.fromNothing(), null, null, (isExternal ? INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
- instructionSets, null, null, null, 0, null /*certificates*/,
- PackageManager.INSTALL_REASON_UNKNOWN);
- // Hackily pretend we're still looking at a full code path
- if (!fullCodePath.endsWith(RES_FILE_NAME)) {
- fullCodePath = new File(fullCodePath, RES_FILE_NAME).getAbsolutePath();
- }
-
- // Extract cid from fullCodePath
- int eidx = fullCodePath.lastIndexOf("/");
- String subStr1 = fullCodePath.substring(0, eidx);
- int sidx = subStr1.lastIndexOf("/");
- cid = subStr1.substring(sidx+1, eidx);
- setMountPath(subStr1);
- }
-
- AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
- super(OriginInfo.fromNothing(), null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
- instructionSets, null, null, null, 0, null /*certificates*/,
- PackageManager.INSTALL_REASON_UNKNOWN);
- this.cid = cid;
- setMountPath(PackageHelper.getSdDir(cid));
- }
-
- void createCopyFile() {
- cid = mInstallerService.allocateExternalStageCidLegacy();
- }
-
- int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
- if (origin.staged && origin.cid != null) {
- if (DEBUG_INSTALL) Slog.d(TAG, origin.cid + " already staged; skipping copy");
- cid = origin.cid;
- setMountPath(PackageHelper.getSdDir(cid));
- return PackageManager.INSTALL_SUCCEEDED;
- }
-
- if (temp) {
- createCopyFile();
- } else {
- /*
- * Pre-emptively destroy the container since it's destroyed if
- * copying fails due to it existing anyway.
- */
- PackageHelper.destroySdDir(cid);
- }
-
- final String newMountPath = imcs.copyPackageToContainer(
- origin.file.getAbsolutePath(), cid, getEncryptKey(), isExternalAsec(),
- isFwdLocked(), deriveAbiOverride(abiOverride, null /* settings */));
-
- if (newMountPath != null) {
- setMountPath(newMountPath);
- return PackageManager.INSTALL_SUCCEEDED;
- } else {
- return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- }
- }
-
- @Override
- String getCodePath() {
- return packagePath;
- }
-
- @Override
- String getResourcePath() {
- return resourcePath;
- }
-
- int doPreInstall(int status) {
- if (status != PackageManager.INSTALL_SUCCEEDED) {
- // Destroy container
- PackageHelper.destroySdDir(cid);
- } else {
- boolean mounted = PackageHelper.isContainerMounted(cid);
- if (!mounted) {
- String newMountPath = PackageHelper.mountSdDir(cid, getEncryptKey(),
- Process.SYSTEM_UID);
- if (newMountPath != null) {
- setMountPath(newMountPath);
- } else {
- return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- }
- }
- }
- return status;
- }
-
- boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) {
- String newCacheId = getNextCodePath(oldCodePath, pkg.packageName, "/" + RES_FILE_NAME);
- String newMountPath = null;
- if (PackageHelper.isContainerMounted(cid)) {
- // Unmount the container
- if (!PackageHelper.unMountSdDir(cid)) {
- Slog.i(TAG, "Failed to unmount " + cid + " before renaming");
- return false;
- }
- }
- if (!PackageHelper.renameSdDir(cid, newCacheId)) {
- Slog.e(TAG, "Failed to rename " + cid + " to " + newCacheId +
- " which might be stale. Will try to clean up.");
- // Clean up the stale container and proceed to recreate.
- if (!PackageHelper.destroySdDir(newCacheId)) {
- Slog.e(TAG, "Very strange. Cannot clean up stale container " + newCacheId);
- return false;
- }
- // Successfully cleaned up stale container. Try to rename again.
- if (!PackageHelper.renameSdDir(cid, newCacheId)) {
- Slog.e(TAG, "Failed to rename " + cid + " to " + newCacheId
- + " inspite of cleaning it up.");
- return false;
- }
- }
- if (!PackageHelper.isContainerMounted(newCacheId)) {
- Slog.w(TAG, "Mounting container " + newCacheId);
- newMountPath = PackageHelper.mountSdDir(newCacheId,
- getEncryptKey(), Process.SYSTEM_UID);
- } else {
- newMountPath = PackageHelper.getSdDir(newCacheId);
- }
- if (newMountPath == null) {
- Slog.w(TAG, "Failed to get cache path for " + newCacheId);
- return false;
- }
- Log.i(TAG, "Succesfully renamed " + cid +
- " to " + newCacheId +
- " at new path: " + newMountPath);
- cid = newCacheId;
-
- final File beforeCodeFile = new File(packagePath);
- setMountPath(newMountPath);
- final File afterCodeFile = new File(packagePath);
-
- // Reflect the rename in scanned details
- pkg.setCodePath(afterCodeFile.getAbsolutePath());
- pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
- afterCodeFile, pkg.baseCodePath));
- pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
- afterCodeFile, pkg.splitCodePaths));
-
- // Reflect the rename in app info
- pkg.setApplicationVolumeUuid(pkg.volumeUuid);
- pkg.setApplicationInfoCodePath(pkg.codePath);
- pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
- pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
- pkg.setApplicationInfoResourcePath(pkg.codePath);
- pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
- pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
-
- return true;
- }
-
- private void setMountPath(String mountPath) {
- final File mountFile = new File(mountPath);
-
- final File monolithicFile = new File(mountFile, RES_FILE_NAME);
- if (monolithicFile.exists()) {
- packagePath = monolithicFile.getAbsolutePath();
- if (isFwdLocked()) {
- resourcePath = new File(mountFile, PUBLIC_RES_FILE_NAME).getAbsolutePath();
- } else {
- resourcePath = packagePath;
- }
- } else {
- packagePath = mountFile.getAbsolutePath();
- resourcePath = packagePath;
- }
- }
-
- int doPostInstall(int status, int uid) {
- if (status != PackageManager.INSTALL_SUCCEEDED) {
- cleanUp();
- } else {
- final int groupOwner;
- final String protectedFile;
- if (isFwdLocked()) {
- groupOwner = UserHandle.getSharedAppGid(uid);
- protectedFile = RES_FILE_NAME;
- } else {
- groupOwner = -1;
- protectedFile = null;
- }
-
- if (uid < Process.FIRST_APPLICATION_UID
- || !PackageHelper.fixSdPermissions(cid, groupOwner, protectedFile)) {
- Slog.e(TAG, "Failed to finalize " + cid);
- PackageHelper.destroySdDir(cid);
- return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- }
-
- boolean mounted = PackageHelper.isContainerMounted(cid);
- if (!mounted) {
- PackageHelper.mountSdDir(cid, getEncryptKey(), Process.myUid());
- }
- }
- return status;
- }
-
- private void cleanUp() {
- if (DEBUG_SD_INSTALL) Slog.i(TAG, "cleanUp");
-
- // Destroy secure container
- PackageHelper.destroySdDir(cid);
- }
-
- private List<String> getAllCodePaths() {
- final File codeFile = new File(getCodePath());
- if (codeFile != null && codeFile.exists()) {
- try {
- final PackageLite pkg = PackageParser.parsePackageLite(codeFile, 0);
- return pkg.getAllCodePaths();
- } catch (PackageParserException e) {
- // Ignored; we tried our best
- }
- }
- return Collections.EMPTY_LIST;
- }
-
- void cleanUpResourcesLI() {
- // Enumerate all code paths before deleting
- cleanUpResourcesLI(getAllCodePaths());
- }
-
- private void cleanUpResourcesLI(List<String> allCodePaths) {
- cleanUp();
- removeDexFiles(allCodePaths, instructionSets);
- }
-
- String getPackageName() {
- return getAsecPackageName(cid);
- }
-
- boolean doPostDeleteLI(boolean delete) {
- if (DEBUG_SD_INSTALL) Slog.i(TAG, "doPostDeleteLI() del=" + delete);
- final List<String> allCodePaths = getAllCodePaths();
- boolean mounted = PackageHelper.isContainerMounted(cid);
- if (mounted) {
- // Unmount first
- if (PackageHelper.unMountSdDir(cid)) {
- mounted = false;
- }
- }
- if (!mounted && delete) {
- cleanUpResourcesLI(allCodePaths);
- }
- return !mounted;
- }
-
- @Override
- int doPreCopy() {
- if (isFwdLocked()) {
- if (!PackageHelper.fixSdPermissions(cid, getPackageUid(DEFAULT_CONTAINER_PACKAGE,
- MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM), RES_FILE_NAME)) {
- return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- }
- }
-
- return PackageManager.INSTALL_SUCCEEDED;
- }
-
- @Override
- int doPostCopy(int uid) {
- if (isFwdLocked()) {
- if (uid < Process.FIRST_APPLICATION_UID
- || !PackageHelper.fixSdPermissions(cid, UserHandle.getSharedAppGid(uid),
- RES_FILE_NAME)) {
- Slog.e(TAG, "Failed to finalize " + cid);
- PackageHelper.destroySdDir(cid);
- return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- }
- }
-
- return PackageManager.INSTALL_SUCCEEDED;
- }
- }
-
- /**
* Logic to handle movement of existing installed applications.
*/
class MoveInstallArgs extends InstallArgs {
@@ -17660,9 +17037,9 @@
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- private boolean shouldCheckUpgradeKeySetLP(PackageSetting oldPs, int scanFlags) {
+ private boolean shouldCheckUpgradeKeySetLP(PackageSettingBase oldPs, int scanFlags) {
// Can't rotate keys during boot or if sharedUser.
- if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.sharedUser != null
+ if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.isSharedUser()
|| !oldPs.keySetData.isUsingUpgradeKeySets()) {
return false;
}
@@ -17682,7 +17059,7 @@
return true;
}
- private boolean checkUpgradeKeySetLP(PackageSetting oldPS, PackageParser.Package newPkg) {
+ private boolean checkUpgradeKeySetLP(PackageSettingBase oldPS, PackageParser.Package newPkg) {
// Upgrade keysets are being used. Determine if new package has a superset of the
// required keys.
long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
@@ -18736,25 +18113,26 @@
// also includes the "updating the same package" case, of course.
// "updating same package" could also involve key-rotation.
final boolean sigsOk;
- if (bp.sourcePackage.equals(pkg.packageName)
- && (bp.packageSetting instanceof PackageSetting)
- && (shouldCheckUpgradeKeySetLP((PackageSetting) bp.packageSetting,
+ final String sourcePackageName = bp.getSourcePackageName();
+ final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
+ if (sourcePackageName.equals(pkg.packageName)
+ && (shouldCheckUpgradeKeySetLP(sourcePackageSetting,
scanFlags))) {
- sigsOk = checkUpgradeKeySetLP((PackageSetting) bp.packageSetting, pkg);
+ sigsOk = checkUpgradeKeySetLP(sourcePackageSetting, pkg);
} else {
- sigsOk = compareSignatures(bp.packageSetting.signatures.mSignatures,
+ sigsOk = compareSignatures(sourcePackageSetting.signatures.mSignatures,
pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
}
if (!sigsOk) {
// If the owning package is the system itself, we log but allow
// install to proceed; we fail the install on all other permission
// redefinitions.
- if (!bp.sourcePackage.equals("android")) {
+ if (!sourcePackageName.equals("android")) {
res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
+ pkg.packageName + " attempting to redeclare permission "
- + perm.info.name + " already owned by " + bp.sourcePackage);
+ + perm.info.name + " already owned by " + sourcePackageName);
res.origPermission = perm.info.name;
- res.origPackage = bp.sourcePackage;
+ res.origPackage = sourcePackageName;
return;
} else {
Slog.w(TAG, "Package " + pkg.packageName
@@ -18773,7 +18151,7 @@
Slog.w(TAG, "Package " + pkg.packageName + " trying to change a "
+ "non-runtime permission " + perm.info.name
+ " to runtime; keeping old protection level");
- perm.info.protectionLevel = bp.protectionLevel;
+ perm.info.protectionLevel = bp.getProtectionLevel();
}
}
}
@@ -20612,9 +19990,8 @@
final int permissionCount = ps.pkg.requestedPermissions.size();
for (int i = 0; i < permissionCount; i++) {
- String permission = ps.pkg.requestedPermissions.get(i);
-
- BasePermission bp = mSettings.mPermissions.get(permission);
+ final String permissionName = ps.pkg.requestedPermissions.get(i);
+ final BasePermission bp = mSettings.mPermissions.get(permissionName);
if (bp == null) {
continue;
}
@@ -20626,7 +20003,7 @@
for (int j = 0; j < packageCount; j++) {
PackageSetting pkg = ps.sharedUser.packages.valueAt(j);
if (pkg.pkg != null && !pkg.pkg.packageName.equals(ps.pkg.packageName)
- && pkg.pkg.requestedPermissions.contains(permission)) {
+ && pkg.pkg.requestedPermissions.contains(permissionName)) {
used = true;
break;
}
@@ -20636,13 +20013,13 @@
}
}
- PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = ps.getPermissionsState();
- final int oldFlags = permissionsState.getPermissionFlags(bp.name, userId);
+ final int oldFlags = permissionsState.getPermissionFlags(permissionName, userId);
// Always clear the user settable flags.
- final boolean hasInstallState = permissionsState.getInstallPermissionState(
- bp.name) != null;
+ final boolean hasInstallState =
+ permissionsState.getInstallPermissionState(permissionName) != null;
// If permission review is enabled and this is a legacy app, mark the
// permission as requiring a review as this is the initial state.
int flags = 0;
@@ -22498,85 +21875,6 @@
return buf.toString();
}
- static class DumpState {
- public static final int DUMP_LIBS = 1 << 0;
- public static final int DUMP_FEATURES = 1 << 1;
- public static final int DUMP_ACTIVITY_RESOLVERS = 1 << 2;
- public static final int DUMP_SERVICE_RESOLVERS = 1 << 3;
- public static final int DUMP_RECEIVER_RESOLVERS = 1 << 4;
- public static final int DUMP_CONTENT_RESOLVERS = 1 << 5;
- public static final int DUMP_PERMISSIONS = 1 << 6;
- public static final int DUMP_PACKAGES = 1 << 7;
- public static final int DUMP_SHARED_USERS = 1 << 8;
- public static final int DUMP_MESSAGES = 1 << 9;
- public static final int DUMP_PROVIDERS = 1 << 10;
- public static final int DUMP_VERIFIERS = 1 << 11;
- public static final int DUMP_PREFERRED = 1 << 12;
- public static final int DUMP_PREFERRED_XML = 1 << 13;
- public static final int DUMP_KEYSETS = 1 << 14;
- public static final int DUMP_VERSION = 1 << 15;
- public static final int DUMP_INSTALLS = 1 << 16;
- public static final int DUMP_INTENT_FILTER_VERIFIERS = 1 << 17;
- public static final int DUMP_DOMAIN_PREFERRED = 1 << 18;
- public static final int DUMP_FROZEN = 1 << 19;
- public static final int DUMP_DEXOPT = 1 << 20;
- public static final int DUMP_COMPILER_STATS = 1 << 21;
- public static final int DUMP_CHANGES = 1 << 22;
- public static final int DUMP_VOLUMES = 1 << 23;
-
- public static final int OPTION_SHOW_FILTERS = 1 << 0;
-
- private int mTypes;
-
- private int mOptions;
-
- private boolean mTitlePrinted;
-
- private SharedUserSetting mSharedUser;
-
- public boolean isDumping(int type) {
- if (mTypes == 0 && type != DUMP_PREFERRED_XML) {
- return true;
- }
-
- return (mTypes & type) != 0;
- }
-
- public void setDump(int type) {
- mTypes |= type;
- }
-
- public boolean isOptionEnabled(int option) {
- return (mOptions & option) != 0;
- }
-
- public void setOptionEnabled(int option) {
- mOptions |= option;
- }
-
- public boolean onTitlePrinted() {
- final boolean printed = mTitlePrinted;
- mTitlePrinted = true;
- return printed;
- }
-
- public boolean getTitlePrinted() {
- return mTitlePrinted;
- }
-
- public void setTitlePrinted(boolean enabled) {
- mTitlePrinted = enabled;
- }
-
- public SharedUserSetting getSharedUser() {
- return mSharedUser;
- }
-
- public void setSharedUser(SharedUserSetting user) {
- mSharedUser = user;
- }
- }
-
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
@@ -23434,135 +22732,6 @@
}
}
- /*
- * Update media status on PackageManager.
- */
- @Override
- public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
- enforceSystemOrRoot("Media status can only be updated by the system");
- // reader; this apparently protects mMediaMounted, but should probably
- // be a different lock in that case.
- synchronized (mPackages) {
- Log.i(TAG, "Updating external media status from "
- + (mMediaMounted ? "mounted" : "unmounted") + " to "
- + (mediaStatus ? "mounted" : "unmounted"));
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" + mediaStatus
- + ", mMediaMounted=" + mMediaMounted);
- if (mediaStatus == mMediaMounted) {
- final Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, reportStatus ? 1
- : 0, -1);
- mHandler.sendMessage(msg);
- return;
- }
- mMediaMounted = mediaStatus;
- }
- // Queue up an async operation since the package installation may take a
- // little while.
- mHandler.post(new Runnable() {
- public void run() {
- updateExternalMediaStatusInner(mediaStatus, reportStatus, true);
- }
- });
- }
-
- /**
- * Called by StorageManagerService when the initial ASECs to scan are available.
- * Should block until all the ASEC containers are finished being scanned.
- */
- public void scanAvailableAsecs() {
- updateExternalMediaStatusInner(true, false, false);
- }
-
- /*
- * Collect information of applications on external media, map them against
- * existing containers and update information based on current mount status.
- * Please note that we always have to report status if reportStatus has been
- * set to true especially when unloading packages.
- */
- private void updateExternalMediaStatusInner(boolean isMounted, boolean reportStatus,
- boolean externalStorage) {
- ArrayMap<AsecInstallArgs, String> processCids = new ArrayMap<>();
- int[] uidArr = EmptyArray.INT;
-
- final String[] list = PackageHelper.getSecureContainerList();
- if (ArrayUtils.isEmpty(list)) {
- Log.i(TAG, "No secure containers found");
- } else {
- // Process list of secure containers and categorize them
- // as active or stale based on their package internal state.
-
- // reader
- synchronized (mPackages) {
- for (String cid : list) {
- // Leave stages untouched for now; installer service owns them
- if (PackageInstallerService.isStageName(cid)) continue;
-
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "Processing container " + cid);
- String pkgName = getAsecPackageName(cid);
- if (pkgName == null) {
- Slog.i(TAG, "Found stale container " + cid + " with no package name");
- continue;
- }
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "Looking for pkg : " + pkgName);
-
- final PackageSetting ps = mSettings.mPackages.get(pkgName);
- if (ps == null) {
- Slog.i(TAG, "Found stale container " + cid + " with no matching settings");
- continue;
- }
-
- /*
- * Skip packages that are not external if we're unmounting
- * external storage.
- */
- if (externalStorage && !isMounted && !isExternal(ps)) {
- continue;
- }
-
- final AsecInstallArgs args = new AsecInstallArgs(cid,
- getAppDexInstructionSets(ps), ps.isForwardLocked());
- // The package status is changed only if the code path
- // matches between settings and the container id.
- if (ps.codePathString != null
- && ps.codePathString.startsWith(args.getCodePath())) {
- if (DEBUG_SD_INSTALL) {
- Log.i(TAG, "Container : " + cid + " corresponds to pkg : " + pkgName
- + " at code path: " + ps.codePathString);
- }
-
- // We do have a valid package installed on sdcard
- processCids.put(args, ps.codePathString);
- final int uid = ps.appId;
- if (uid != -1) {
- uidArr = ArrayUtils.appendInt(uidArr, uid);
- }
- } else {
- Slog.i(TAG, "Found stale container " + cid + ": expected codePath="
- + ps.codePathString);
- }
- }
- }
-
- Arrays.sort(uidArr);
- }
-
- // Process packages with valid entries.
- if (isMounted) {
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "Loading packages");
- loadMediaPackages(processCids, uidArr, externalStorage);
- startCleaningPackages();
- mInstallerService.onSecureContainersAvailable();
- } else {
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "Unloading packages");
- unloadMediaPackages(processCids, uidArr, reportStatus);
- }
- }
-
private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
ArrayList<ApplicationInfo> infos, IIntentReceiver finishedReceiver) {
final int size = infos.size();
@@ -23602,193 +22771,6 @@
}
}
- /*
- * Look at potentially valid container ids from processCids If package
- * information doesn't match the one on record or package scanning fails,
- * the cid is added to list of removeCids. We currently don't delete stale
- * containers.
- */
- private void loadMediaPackages(ArrayMap<AsecInstallArgs, String> processCids, int[] uidArr,
- boolean externalStorage) {
- ArrayList<String> pkgList = new ArrayList<String>();
- Set<AsecInstallArgs> keys = processCids.keySet();
-
- for (AsecInstallArgs args : keys) {
- String codePath = processCids.get(args);
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "Loading container : " + args.cid);
- int retCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- try {
- // Make sure there are no container errors first.
- if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) != PackageManager.INSTALL_SUCCEEDED) {
- Slog.e(TAG, "Failed to mount cid : " + args.cid
- + " when installing from sdcard");
- continue;
- }
- // Check code path here.
- if (codePath == null || !codePath.startsWith(args.getCodePath())) {
- Slog.e(TAG, "Container " + args.cid + " cachepath " + args.getCodePath()
- + " does not match one in settings " + codePath);
- continue;
- }
- // Parse package
- int parseFlags = mDefParseFlags;
- if (args.isExternalAsec()) {
- parseFlags |= PackageParser.PARSE_EXTERNAL_STORAGE;
- }
- if (args.isFwdLocked()) {
- parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
- }
-
- synchronized (mInstallLock) {
- PackageParser.Package pkg = null;
- try {
- // Sadly we don't know the package name yet to freeze it
- pkg = scanPackageTracedLI(new File(codePath), parseFlags,
- SCAN_IGNORE_FROZEN, 0, null);
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to scan " + codePath + ": " + e.getMessage());
- }
- // Scan the package
- if (pkg != null) {
- /*
- * TODO why is the lock being held? doPostInstall is
- * called in other places without the lock. This needs
- * to be straightened out.
- */
- // writer
- synchronized (mPackages) {
- retCode = PackageManager.INSTALL_SUCCEEDED;
- pkgList.add(pkg.packageName);
- // Post process args
- args.doPostInstall(PackageManager.INSTALL_SUCCEEDED,
- pkg.applicationInfo.uid);
- }
- } else {
- Slog.i(TAG, "Failed to install pkg from " + codePath + " from sdcard");
- }
- }
-
- } finally {
- if (retCode != PackageManager.INSTALL_SUCCEEDED) {
- Log.w(TAG, "Container " + args.cid + " is stale, retCode=" + retCode);
- }
- }
- }
- // writer
- synchronized (mPackages) {
- // If the platform SDK has changed since the last time we booted,
- // we need to re-grant app permission to catch any new ones that
- // appear. This is really a hack, and means that apps can in some
- // cases get permissions that the user didn't initially explicitly
- // allow... it would be nice to have some better way to handle
- // this situation.
- final VersionInfo ver = externalStorage ? mSettings.getExternalVersion()
- : mSettings.getInternalVersion();
- final String volumeUuid = externalStorage ? StorageManager.UUID_PRIMARY_PHYSICAL
- : StorageManager.UUID_PRIVATE_INTERNAL;
-
- int updateFlags = UPDATE_PERMISSIONS_ALL;
- if (ver.sdkVersion != mSdkVersion) {
- logCriticalInfo(Log.INFO, "Platform changed from " + ver.sdkVersion + " to "
- + mSdkVersion + "; regranting permissions for external");
- updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
- }
- updatePermissionsLPw(null, null, volumeUuid, updateFlags);
-
- // Yay, everything is now upgraded
- ver.forceCurrent();
-
- // can downgrade to reader
- // Persist settings
- mSettings.writeLPr();
- }
- // Send a broadcast to let everyone know we are done processing
- if (pkgList.size() > 0) {
- sendResourcesChangedBroadcast(true, false, pkgList, uidArr, null);
- }
- }
-
- /*
- * Utility method to unload a list of specified containers
- */
- private void unloadAllContainers(Set<AsecInstallArgs> cidArgs) {
- // Just unmount all valid containers.
- for (AsecInstallArgs arg : cidArgs) {
- synchronized (mInstallLock) {
- arg.doPostDeleteLI(false);
- }
- }
- }
-
- /*
- * Unload packages mounted on external media. This involves deleting package
- * data from internal structures, sending broadcasts about disabled packages,
- * gc'ing to free up references, unmounting all secure containers
- * corresponding to packages on external media, and posting a
- * UPDATED_MEDIA_STATUS message if status has been requested. Please note
- * that we always have to post this message if status has been requested no
- * matter what.
- */
- private void unloadMediaPackages(ArrayMap<AsecInstallArgs, String> processCids, int uidArr[],
- final boolean reportStatus) {
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "unloading media packages");
- ArrayList<String> pkgList = new ArrayList<String>();
- ArrayList<AsecInstallArgs> failedList = new ArrayList<AsecInstallArgs>();
- final Set<AsecInstallArgs> keys = processCids.keySet();
- for (AsecInstallArgs args : keys) {
- String pkgName = args.getPackageName();
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "Trying to unload pkg : " + pkgName);
- // Delete package internally
- PackageRemovedInfo outInfo = new PackageRemovedInfo(this);
- synchronized (mInstallLock) {
- final int deleteFlags = PackageManager.DELETE_KEEP_DATA;
- final boolean res;
- try (PackageFreezer freezer = freezePackageForDelete(pkgName, deleteFlags,
- "unloadMediaPackages")) {
- res = deletePackageLIF(pkgName, null, false, null, deleteFlags, outInfo, false,
- null);
- }
- if (res) {
- pkgList.add(pkgName);
- } else {
- Slog.e(TAG, "Failed to delete pkg from sdcard : " + pkgName);
- failedList.add(args);
- }
- }
- }
-
- // reader
- synchronized (mPackages) {
- // We didn't update the settings after removing each package;
- // write them now for all packages.
- mSettings.writeLPr();
- }
-
- // We have to absolutely send UPDATED_MEDIA_STATUS only
- // after confirming that all the receivers processed the ordered
- // broadcast when packages get disabled, force a gc to clean things up.
- // and unload all the containers.
- if (pkgList.size() > 0) {
- sendResourcesChangedBroadcast(false, false, pkgList, uidArr,
- new IIntentReceiver.Stub() {
- public void performReceive(Intent intent, int resultCode, String data,
- Bundle extras, boolean ordered, boolean sticky,
- int sendingUser) throws RemoteException {
- Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
- reportStatus ? 1 : 0, 1, keys);
- mHandler.sendMessage(msg);
- }
- });
- } else {
- Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, reportStatus ? 1 : 0, -1,
- keys);
- mHandler.sendMessage(msg);
- }
- }
-
private void loadPrivatePackages(final VolumeInfo vol) {
mHandler.post(new Runnable() {
@Override
@@ -24906,7 +23888,8 @@
synchronized (mPackages) {
if (mSettings.mReadExternalStorageEnforced == null
|| mSettings.mReadExternalStorageEnforced != enforced) {
- mSettings.mReadExternalStorageEnforced = enforced;
+ mSettings.mReadExternalStorageEnforced =
+ enforced ? Boolean.TRUE : Boolean.FALSE;
mSettings.writeLPr();
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 25fef0a..48ddf5e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -22,6 +22,8 @@
import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
import static com.android.server.pm.PackageManagerService.TAG;
+import com.android.internal.util.ArrayUtils;
+
import android.annotation.NonNull;
import android.app.AppGlobals;
import android.content.Intent;
@@ -33,6 +35,8 @@
import android.system.ErrnoException;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Slog;
+import android.util.jar.StrictJarFile;
import dalvik.system.VMRuntime;
import libcore.io.Libcore;
@@ -41,9 +45,11 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
+import java.util.zip.ZipEntry;
/**
* Class containing helper methods for the PackageManagerService.
@@ -253,4 +259,59 @@
}
return false;
}
+
+ /**
+ * Checks that the archive located at {@code fileName} has uncompressed dex file and so
+ * files that can be direclty mapped.
+ */
+ public static void logApkHasUncompressedCode(String fileName) {
+ StrictJarFile jarFile = null;
+ try {
+ jarFile = new StrictJarFile(fileName,
+ false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/);
+ Iterator<ZipEntry> it = jarFile.iterator();
+ while (it.hasNext()) {
+ ZipEntry entry = it.next();
+ if (entry.getName().endsWith(".dex")) {
+ if (entry.getMethod() != ZipEntry.STORED) {
+ Slog.wtf(TAG, "APK " + fileName + " has compressed dex code " +
+ entry.getName());
+ } else if ((entry.getDataOffset() & 0x3) != 0) {
+ Slog.wtf(TAG, "APK " + fileName + " has unaligned dex code " +
+ entry.getName());
+ }
+ } else if (entry.getName().endsWith(".so")) {
+ if (entry.getMethod() != ZipEntry.STORED) {
+ Slog.wtf(TAG, "APK " + fileName + " has compressed native code " +
+ entry.getName());
+ } else if ((entry.getDataOffset() & (0x1000 - 1)) != 0) {
+ Slog.wtf(TAG, "APK " + fileName + " has unaligned native code " +
+ entry.getName());
+ }
+ }
+ }
+ } catch (IOException ignore) {
+ Slog.wtf(TAG, "Error when parsing APK " + fileName);
+ } finally {
+ try {
+ if (jarFile != null) {
+ jarFile.close();
+ }
+ } catch (IOException ignore) {}
+ }
+ return;
+ }
+
+ /**
+ * Checks that the APKs in the given package have uncompressed dex file and so
+ * files that can be direclty mapped.
+ */
+ public static void logPackageHasUncompressedCode(PackageParser.Package pkg) {
+ logApkHasUncompressedCode(pkg.baseCodePath);
+ if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+ for (int i = 0; i < pkg.splitCodePaths.length; i++) {
+ logApkHasUncompressedCode(pkg.splitCodePaths[i]);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 1f03e66..1fea003 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -183,7 +183,7 @@
PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
null, null);
params.sessionParams.setSize(PackageHelper.calculateInstalledSize(
- pkgLite, false, params.sessionParams.abiOverride));
+ pkgLite, params.sessionParams.abiOverride));
} catch (PackageParserException | IOException e) {
pw.println("Error: Failed to parse APK file: " + file);
throw new IllegalArgumentException(
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 52bf641..88fe3c1 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -103,6 +103,7 @@
sharedUserId = orig.sharedUserId;
}
+ @Override
public PermissionsState getPermissionsState() {
return (sharedUser != null)
? sharedUser.getPermissionsState()
@@ -125,6 +126,7 @@
return (pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
+ @Override
public boolean isSharedUser() {
return sharedUser != null;
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index d3ca1fd..0d4878f 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -24,14 +24,12 @@
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageUserState;
-import android.os.storage.VolumeInfo;
import android.service.pm.PackageProto;
import android.util.ArraySet;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
-import com.google.android.collect.Lists;
import java.io.File;
import java.util.ArrayList;
@@ -42,7 +40,7 @@
/**
* Settings base class for pending and resolved classes.
*/
-abstract class PackageSettingBase extends SettingBase {
+public abstract class PackageSettingBase extends SettingBase {
private static final int[] EMPTY_INT_ARRAY = new int[0];
@@ -230,6 +228,9 @@
return updateAvailable;
}
+ public boolean isSharedUser() {
+ return false;
+ }
/**
* Makes a shallow copy of the given package settings.
*
diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java
index f4d2ad2..8b42a99 100644
--- a/services/core/java/com/android/server/pm/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/PermissionsState.java
@@ -24,6 +24,7 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.permission.BasePermission;
import java.util.ArrayList;
import java.util.Arrays;
@@ -406,7 +407,7 @@
ensurePermissionData(permission);
}
- PermissionData permissionData = mPermissions.get(permission.name);
+ PermissionData permissionData = mPermissions.get(permission.getName());
if (permissionData == null) {
if (!mayChangeFlags) {
return false;
@@ -557,7 +558,7 @@
}
private int grantPermission(BasePermission permission, int userId) {
- if (hasPermission(permission.name, userId)) {
+ if (hasPermission(permission.getName(), userId)) {
return PERMISSION_OPERATION_FAILURE;
}
@@ -581,21 +582,22 @@
}
private int revokePermission(BasePermission permission, int userId) {
- if (!hasPermission(permission.name, userId)) {
+ final String permName = permission.getName();
+ if (!hasPermission(permName, userId)) {
return PERMISSION_OPERATION_FAILURE;
}
final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
- PermissionData permissionData = mPermissions.get(permission.name);
+ PermissionData permissionData = mPermissions.get(permName);
if (!permissionData.revoke(userId)) {
return PERMISSION_OPERATION_FAILURE;
}
if (permissionData.isDefault()) {
- ensureNoPermissionData(permission.name);
+ ensureNoPermissionData(permName);
}
if (hasGids) {
@@ -625,13 +627,14 @@
}
private PermissionData ensurePermissionData(BasePermission permission) {
+ final String permName = permission.getName();
if (mPermissions == null) {
mPermissions = new ArrayMap<>();
}
- PermissionData permissionData = mPermissions.get(permission.name);
+ PermissionData permissionData = mPermissions.get(permName);
if (permissionData == null) {
permissionData = new PermissionData(permission);
- mPermissions.put(permission.name, permissionData);
+ mPermissions.put(permName, permissionData);
}
return permissionData;
}
@@ -692,7 +695,7 @@
PermissionState userState = mUserStates.get(userId);
if (userState == null) {
- userState = new PermissionState(mPerm.name);
+ userState = new PermissionState(mPerm.getName());
mUserStates.put(userId, userState);
}
@@ -760,7 +763,7 @@
}
return userState.mFlags != oldFlags;
} else if (newFlags != 0) {
- userState = new PermissionState(mPerm.name);
+ userState = new PermissionState(mPerm.getName());
userState.mFlags = newFlags;
mUserStates.put(userId, userState);
return true;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 51d3e10..06cf79a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -16,7 +16,6 @@
package com.android.server.pm;
-import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
@@ -64,7 +63,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
-import android.os.storage.VolumeInfo;
import android.service.pm.PackageServiceDumpProto;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -87,10 +85,9 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
-import com.android.server.backup.PreferredActivityBackupHelper;
import com.android.server.pm.Installer.InstallerException;
-import com.android.server.pm.PackageManagerService.DumpState;
import com.android.server.pm.PermissionsState.PermissionState;
+import com.android.server.pm.permission.BasePermission;
import libcore.io.IoUtils;
@@ -127,7 +124,7 @@
/**
* Holds information about dynamic settings.
*/
-final class Settings {
+public final class Settings {
private static final String TAG = "PackageSettings";
/**
@@ -176,7 +173,7 @@
private static final String TAG_READ_EXTERNAL_STORAGE = "read-external-storage";
private static final String ATTR_ENFORCEMENT = "enforcement";
- private static final String TAG_ITEM = "item";
+ public static final String TAG_ITEM = "item";
private static final String TAG_DISABLED_COMPONENTS = "disabled-components";
private static final String TAG_ENABLED_COMPONENTS = "enabled-components";
private static final String TAG_PACKAGE_RESTRICTIONS = "package-restrictions";
@@ -201,7 +198,8 @@
private static final String TAG_DEFAULT_DIALER = "default-dialer";
private static final String TAG_VERSION = "version";
- private static final String ATTR_NAME = "name";
+ public static final String ATTR_NAME = "name";
+ public static final String ATTR_PACKAGE = "package";
private static final String ATTR_USER = "user";
private static final String ATTR_CODE = "code";
private static final String ATTR_GRANTED = "granted";
@@ -233,7 +231,6 @@
private static final String ATTR_VOLUME_UUID = "volumeUuid";
private static final String ATTR_SDK_VERSION = "sdkVersion";
private static final String ATTR_DATABASE_VERSION = "databaseVersion";
- private static final String ATTR_DONE = "done";
// Bookkeeping for restored permission grants
private static final String TAG_RESTORED_RUNTIME_PERMISSIONS = "restored-perms";
@@ -665,26 +662,13 @@
}
// Transfer ownership of permissions from one package to another.
- void transferPermissionsLPw(String origPkg, String newPkg) {
+ void transferPermissionsLPw(String origPackageName, String newPackageName) {
// Transfer ownership of permissions to the new package.
for (int i=0; i<2; i++) {
ArrayMap<String, BasePermission> permissions =
i == 0 ? mPermissionTrees : mPermissions;
for (BasePermission bp : permissions.values()) {
- if (origPkg.equals(bp.sourcePackage)) {
- if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG,
- "Moving permission " + bp.name
- + " from pkg " + bp.sourcePackage
- + " to " + newPkg);
- bp.sourcePackage = newPkg;
- bp.packageSetting = null;
- bp.perm = null;
- if (bp.pendingInfo != null) {
- bp.pendingInfo.packageName = newPkg;
- }
- bp.uid = 0;
- bp.setGids(null, false);
- }
+ bp.transfer(origPackageName, newPackageName);
}
}
}
@@ -2022,8 +2006,7 @@
// Specifically for backup/restore
public void processRestoredPermissionGrantLPr(String pkgName, String permission,
- boolean isGranted, int restoredFlagSet, int userId)
- throws IOException, XmlPullParserException {
+ boolean isGranted, int restoredFlagSet, int userId) {
mRuntimePermissionsPersistence.rememberRestoredUserGrantLPr(
pkgName, permission, isGranted, restoredFlagSet, userId);
}
@@ -2605,9 +2588,6 @@
writeAllRuntimePermissionsLPr();
return;
- } catch(XmlPullParserException e) {
- Slog.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
- + "current changes will be lost at reboot", e);
} catch(java.io.IOException e) {
Slog.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
+ "current changes will be lost at reboot", e);
@@ -2951,7 +2931,6 @@
void writeUpgradeKeySetsLPr(XmlSerializer serializer,
PackageKeySetData data) throws IOException {
- long properSigning = data.getProperSigningKeySet();
if (data.isUsingUpgradeKeySets()) {
for (long id : data.getUpgradeKeySets()) {
serializer.startTag(null, "upgrade-keyset");
@@ -2971,32 +2950,8 @@
}
}
- void writePermissionLPr(XmlSerializer serializer, BasePermission bp)
- throws XmlPullParserException, java.io.IOException {
- if (bp.sourcePackage != null) {
- serializer.startTag(null, TAG_ITEM);
- serializer.attribute(null, ATTR_NAME, bp.name);
- serializer.attribute(null, "package", bp.sourcePackage);
- if (bp.protectionLevel != PermissionInfo.PROTECTION_NORMAL) {
- serializer.attribute(null, "protection", Integer.toString(bp.protectionLevel));
- }
- if (PackageManagerService.DEBUG_SETTINGS)
- Log.v(PackageManagerService.TAG, "Writing perm: name=" + bp.name + " type="
- + bp.type);
- if (bp.type == BasePermission.TYPE_DYNAMIC) {
- final PermissionInfo pi = bp.perm != null ? bp.perm.info : bp.pendingInfo;
- if (pi != null) {
- serializer.attribute(null, "type", "dynamic");
- if (pi.icon != 0) {
- serializer.attribute(null, "icon", Integer.toString(pi.icon));
- }
- if (pi.nonLocalizedLabel != null) {
- serializer.attribute(null, "label", pi.nonLocalizedLabel.toString());
- }
- }
- }
- serializer.endTag(null, TAG_ITEM);
- }
+ void writePermissionLPr(XmlSerializer serializer, BasePermission bp) throws IOException {
+ bp.writeLPr(serializer);
}
ArrayList<PackageSetting> getListOfIncompleteInstallPackagesLPr() {
@@ -3169,7 +3124,8 @@
}
} else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
final String enforcement = parser.getAttributeValue(null, ATTR_ENFORCEMENT);
- mReadExternalStorageEnforced = "1".equals(enforcement);
+ mReadExternalStorageEnforced =
+ "1".equals(enforcement) ? Boolean.TRUE : Boolean.FALSE;
} else if (tagName.equals("keyset-settings")) {
mKeySetManagerService.readKeySetsLPw(parser, mKeySetRefs);
} else if (TAG_VERSION.equals(tagName)) {
@@ -3593,22 +3549,6 @@
}
}
- private int readInt(XmlPullParser parser, String ns, String name, int defValue) {
- String v = parser.getAttributeValue(ns, name);
- try {
- if (v == null) {
- return defValue;
- }
- return Integer.parseInt(v);
- } catch (NumberFormatException e) {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Error in package manager settings: attribute " + name
- + " has bad integer value " + v + " at "
- + parser.getPositionDescription());
- }
- return defValue;
- }
-
private void readPermissionsLPw(ArrayMap<String, BasePermission> out, XmlPullParser parser)
throws IOException, XmlPullParserException {
int outerDepth = parser.getDepth();
@@ -3619,38 +3559,7 @@
continue;
}
- final String tagName = parser.getName();
- if (tagName.equals(TAG_ITEM)) {
- final String name = parser.getAttributeValue(null, ATTR_NAME);
- final String sourcePackage = parser.getAttributeValue(null, "package");
- final String ptype = parser.getAttributeValue(null, "type");
- if (name != null && sourcePackage != null) {
- final boolean dynamic = "dynamic".equals(ptype);
- BasePermission bp = out.get(name);
- // If the permission is builtin, do not clobber it.
- if (bp == null || bp.type != BasePermission.TYPE_BUILTIN) {
- bp = new BasePermission(name.intern(), sourcePackage,
- dynamic ? BasePermission.TYPE_DYNAMIC : BasePermission.TYPE_NORMAL);
- }
- bp.protectionLevel = readInt(parser, null, "protection",
- PermissionInfo.PROTECTION_NORMAL);
- bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel);
- if (dynamic) {
- PermissionInfo pi = new PermissionInfo();
- pi.packageName = sourcePackage.intern();
- pi.name = name.intern();
- pi.icon = readInt(parser, null, "icon", 0);
- pi.nonLocalizedLabel = parser.getAttributeValue(null, "label");
- pi.protectionLevel = bp.protectionLevel;
- bp.pendingInfo = pi;
- }
- out.put(bp.name, bp);
- } else {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Error in package manager settings: permissions has" + " no name at "
- + parser.getPositionDescription());
- }
- } else {
+ if (!BasePermission.readLPw(out, parser)) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Unknown element reading permissions: " + parser.getName() + " at "
+ parser.getPositionDescription());
@@ -4385,10 +4294,6 @@
return ps;
}
- private String compToString(ArraySet<String> cmp) {
- return cmp != null ? Arrays.toString(cmp.toArray()) : "[]";
- }
-
boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
final PackageSetting ps = mPackages.get(componentInfo.packageName);
if (ps == null) return false;
@@ -5002,43 +4907,9 @@
void dumpPermissionsLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
DumpState dumpState) {
boolean printedSomething = false;
- for (BasePermission p : mPermissions.values()) {
- if (packageName != null && !packageName.equals(p.sourcePackage)) {
- continue;
- }
- if (permissionNames != null && !permissionNames.contains(p.name)) {
- continue;
- }
- if (!printedSomething) {
- if (dumpState.onTitlePrinted())
- pw.println();
- pw.println("Permissions:");
- printedSomething = true;
- }
- pw.print(" Permission ["); pw.print(p.name); pw.print("] (");
- pw.print(Integer.toHexString(System.identityHashCode(p)));
- pw.println("):");
- pw.print(" sourcePackage="); pw.println(p.sourcePackage);
- pw.print(" uid="); pw.print(p.uid);
- pw.print(" gids="); pw.print(Arrays.toString(
- p.computeGids(UserHandle.USER_SYSTEM)));
- pw.print(" type="); pw.print(p.type);
- pw.print(" prot=");
- pw.println(PermissionInfo.protectionToString(p.protectionLevel));
- if (p.perm != null) {
- pw.print(" perm="); pw.println(p.perm);
- if ((p.perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0
- || (p.perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) {
- pw.print(" flags=0x"); pw.println(Integer.toHexString(p.perm.info.flags));
- }
- }
- if (p.packageSetting != null) {
- pw.print(" packageSetting="); pw.println(p.packageSetting);
- }
- if (READ_EXTERNAL_STORAGE.equals(p.name)) {
- pw.print(" enforced=");
- pw.println(mReadExternalStorageEnforced);
- }
+ for (BasePermission bp : mPermissions.values()) {
+ printedSomething = bp.dumpPermissionsLPr(pw, packageName, permissionNames,
+ mReadExternalStorageEnforced == Boolean.TRUE, printedSomething, dumpState);
}
}
@@ -5248,7 +5119,7 @@
private final Handler mHandler = new MyHandler();
- private final Object mLock;
+ private final Object mPersistenceLock;
@GuardedBy("mLock")
private final SparseBooleanArray mWriteScheduled = new SparseBooleanArray();
@@ -5265,8 +5136,8 @@
// The mapping keys are user ids.
private final SparseBooleanArray mDefaultPermissionsGranted = new SparseBooleanArray();
- public RuntimePermissionPersistence(Object lock) {
- mLock = lock;
+ public RuntimePermissionPersistence(Object persistenceLock) {
+ mPersistenceLock = persistenceLock;
}
public boolean areDefaultRuntimPermissionsGrantedLPr(int userId) {
@@ -5321,7 +5192,7 @@
ArrayMap<String, List<PermissionState>> permissionsForPackage = new ArrayMap<>();
ArrayMap<String, List<PermissionState>> permissionsForSharedUser = new ArrayMap<>();
- synchronized (mLock) {
+ synchronized (mPersistenceLock) {
mWriteScheduled.delete(userId);
final int packageCount = mPackages.size();
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 0e572d8..15d2071 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -484,12 +484,13 @@
final private IUidObserver mUidObserver = new IUidObserver.Stub() {
@Override
public void onUidStateChanged(int uid, int procState, long procStateSeq) {
- handleOnUidStateChanged(uid, procState);
+ injectPostToHandler(() -> handleOnUidStateChanged(uid, procState));
}
@Override
public void onUidGone(int uid, boolean disabled) {
- handleOnUidStateChanged(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
+ injectPostToHandler(() ->
+ handleOnUidStateChanged(uid, ActivityManager.PROCESS_STATE_NONEXISTENT));
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
new file mode 100644
index 0000000..09a6e9c
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.permission;
+
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
+import static android.content.pm.PermissionInfo.PROTECTION_NORMAL;
+import static android.content.pm.PermissionInfo.PROTECTION_SIGNATURE;
+import static android.content.pm.PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM;
+
+import static com.android.server.pm.Settings.ATTR_NAME;
+import static com.android.server.pm.Settings.ATTR_PACKAGE;
+import static com.android.server.pm.Settings.TAG_ITEM;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.Permission;
+import android.content.pm.PermissionInfo;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.server.pm.DumpState;
+import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.PackageSettingBase;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+public final class BasePermission {
+ static final String TAG = "PackageManager";
+
+ public static final int TYPE_NORMAL = 0;
+ public static final int TYPE_BUILTIN = 1;
+ public static final int TYPE_DYNAMIC = 2;
+ @IntDef(value = {
+ TYPE_NORMAL,
+ TYPE_BUILTIN,
+ TYPE_DYNAMIC,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PermissionType {}
+
+ @IntDef(value = {
+ PROTECTION_DANGEROUS,
+ PROTECTION_NORMAL,
+ PROTECTION_SIGNATURE,
+ PROTECTION_SIGNATURE_OR_SYSTEM,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ProtectionLevel {}
+
+ final String name;
+
+ @PermissionType final int type;
+
+ String sourcePackageName;
+
+ // TODO: Can we get rid of this? Seems we only use some signature info from the setting
+ PackageSettingBase sourcePackageSetting;
+
+ int protectionLevel;
+
+ PackageParser.Permission perm;
+
+ PermissionInfo pendingPermissionInfo;
+
+ /** UID that owns the definition of this permission */
+ int uid;
+
+ /** Additional GIDs given to apps granted this permission */
+ private int[] gids;
+
+ /**
+ * Flag indicating that {@link #gids} should be adjusted based on the
+ * {@link UserHandle} the granted app is running as.
+ */
+ private boolean perUser;
+
+ public BasePermission(String _name, String _sourcePackageName, @PermissionType int _type) {
+ name = _name;
+ sourcePackageName = _sourcePackageName;
+ type = _type;
+ // Default to most conservative protection level.
+ protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
+ }
+
+ @Override
+ public String toString() {
+ return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name
+ + "}";
+ }
+
+ public String getName() {
+ return name;
+ }
+ public int getProtectionLevel() {
+ return protectionLevel;
+ }
+ public String getSourcePackageName() {
+ return sourcePackageName;
+ }
+ public PackageSettingBase getSourcePackageSetting() {
+ return sourcePackageSetting;
+ }
+ public int getType() {
+ return type;
+ }
+ public int getUid() {
+ return uid;
+ }
+ public void setGids(int[] gids, boolean perUser) {
+ this.gids = gids;
+ this.perUser = perUser;
+ }
+ public void setPermission(@Nullable Permission perm) {
+ this.perm = perm;
+ }
+ public void setSourcePackageSetting(PackageSettingBase sourcePackageSetting) {
+ this.sourcePackageSetting = sourcePackageSetting;
+ }
+
+ public int[] computeGids(int userId) {
+ if (perUser) {
+ final int[] userGids = new int[gids.length];
+ for (int i = 0; i < gids.length; i++) {
+ userGids[i] = UserHandle.getUid(userId, gids[i]);
+ }
+ return userGids;
+ } else {
+ return gids;
+ }
+ }
+
+ public int calculateFootprint(BasePermission perm) {
+ if (uid == perm.uid) {
+ return perm.name.length() + perm.perm.info.calculateFootprint();
+ }
+ return 0;
+ }
+
+ public boolean isPermission(Permission perm) {
+ return this.perm == perm;
+ }
+
+ public boolean isDynamic() {
+ return type == TYPE_DYNAMIC;
+ }
+
+
+ public boolean isNormal() {
+ return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+ == PermissionInfo.PROTECTION_NORMAL;
+ }
+ public boolean isRuntime() {
+ return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+ == PermissionInfo.PROTECTION_DANGEROUS;
+ }
+ public boolean isSignature() {
+ return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) ==
+ PermissionInfo.PROTECTION_SIGNATURE;
+ }
+
+ public boolean isAppOp() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0;
+ }
+ public boolean isDevelopment() {
+ return isSignature()
+ && (protectionLevel & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0;
+ }
+ public boolean isInstaller() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0;
+ }
+ public boolean isInstant() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0;
+ }
+ public boolean isOEM() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_OEM) != 0;
+ }
+ public boolean isPre23() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PRE23) != 0;
+ }
+ public boolean isPreInstalled() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0;
+ }
+ public boolean isPrivileged() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0;
+ }
+ public boolean isRuntimeOnly() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0;
+ }
+ public boolean isSetup() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_SETUP) != 0;
+ }
+ public boolean isVerifier() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0;
+ }
+
+ public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
+ if (!origPackageName.equals(sourcePackageName)) {
+ return;
+ }
+ sourcePackageName = newPackageName;
+ sourcePackageSetting = null;
+ perm = null;
+ if (pendingPermissionInfo != null) {
+ pendingPermissionInfo.packageName = newPackageName;
+ }
+ uid = 0;
+ setGids(null, false);
+ }
+
+ public boolean addToTree(@ProtectionLevel int protectionLevel,
+ @NonNull PermissionInfo info, @NonNull BasePermission tree) {
+ final boolean changed =
+ (this.protectionLevel != protectionLevel
+ || perm == null
+ || uid != tree.uid
+ || !perm.owner.equals(tree.perm.owner)
+ || !comparePermissionInfos(perm.info, info));
+ this.protectionLevel = protectionLevel;
+ info = new PermissionInfo(info);
+ info.protectionLevel = protectionLevel;
+ perm = new PackageParser.Permission(tree.perm.owner, info);
+ perm.info.packageName = tree.perm.info.packageName;
+ uid = tree.uid;
+ return changed;
+ }
+
+ public void updateDynamicPermission(Map<String, BasePermission> permissionTrees) {
+ if (PackageManagerService.DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
+ + getName() + " pkg=" + getSourcePackageName()
+ + " info=" + pendingPermissionInfo);
+ if (sourcePackageSetting == null && pendingPermissionInfo != null) {
+ final BasePermission tree = findPermissionTreeLP(permissionTrees, name);
+ if (tree != null && tree.perm != null) {
+ sourcePackageSetting = tree.sourcePackageSetting;
+ perm = new PackageParser.Permission(tree.perm.owner,
+ new PermissionInfo(pendingPermissionInfo));
+ perm.info.packageName = tree.perm.info.packageName;
+ perm.info.name = name;
+ uid = tree.uid;
+ }
+ }
+ }
+
+ public static BasePermission createOrUpdate(@Nullable BasePermission bp, @NonNull Permission p,
+ @NonNull PackageParser.Package pkg, Map<String, BasePermission> permissionTrees,
+ boolean chatty) {
+ final PackageSettingBase pkgSetting = (PackageSettingBase) pkg.mExtras;
+ // Allow system apps to redefine non-system permissions
+ if (bp != null && !Objects.equals(bp.sourcePackageName, p.info.packageName)) {
+ final boolean currentOwnerIsSystem = (bp.perm != null
+ && bp.perm.owner.isSystemApp());
+ if (p.owner.isSystemApp()) {
+ if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
+ // It's a built-in permission and no owner, take ownership now
+ bp.sourcePackageSetting = pkgSetting;
+ bp.perm = p;
+ bp.uid = pkg.applicationInfo.uid;
+ bp.sourcePackageName = p.info.packageName;
+ p.info.flags |= PermissionInfo.FLAG_INSTALLED;
+ } else if (!currentOwnerIsSystem) {
+ String msg = "New decl " + p.owner + " of permission "
+ + p.info.name + " is system; overriding " + bp.sourcePackageName;
+ PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+ bp = null;
+ }
+ }
+ }
+ if (bp == null) {
+ bp = new BasePermission(p.info.name, p.info.packageName, TYPE_NORMAL);
+ }
+ StringBuilder r = null;
+ if (bp.perm == null) {
+ if (bp.sourcePackageName == null
+ || bp.sourcePackageName.equals(p.info.packageName)) {
+ final BasePermission tree = findPermissionTreeLP(permissionTrees, p.info.name);
+ if (tree == null
+ || tree.sourcePackageName.equals(p.info.packageName)) {
+ bp.sourcePackageSetting = pkgSetting;
+ bp.perm = p;
+ bp.uid = pkg.applicationInfo.uid;
+ bp.sourcePackageName = p.info.packageName;
+ p.info.flags |= PermissionInfo.FLAG_INSTALLED;
+ if (chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
+ }
+ r.append(p.info.name);
+ }
+ } else {
+ Slog.w(TAG, "Permission " + p.info.name + " from package "
+ + p.info.packageName + " ignored: base tree "
+ + tree.name + " is from package "
+ + tree.sourcePackageName);
+ }
+ } else {
+ Slog.w(TAG, "Permission " + p.info.name + " from package "
+ + p.info.packageName + " ignored: original from "
+ + bp.sourcePackageName);
+ }
+ } else if (chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
+ }
+ r.append("DUP:");
+ r.append(p.info.name);
+ }
+ if (bp.perm == p) {
+ bp.protectionLevel = p.info.protectionLevel;
+ }
+ if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
+ Log.d(TAG, " Permissions: " + r);
+ }
+ return bp;
+ }
+
+ public static BasePermission enforcePermissionTreeLP(
+ Map<String, BasePermission> permissionTrees, String permName, int callingUid) {
+ if (permName != null) {
+ BasePermission bp = findPermissionTreeLP(permissionTrees, permName);
+ if (bp != null) {
+ if (bp.uid == UserHandle.getAppId(callingUid)) {//UserHandle.getAppId(Binder.getCallingUid())) {
+ return bp;
+ }
+ throw new SecurityException("Calling uid " + callingUid
+ + " is not allowed to add to permission tree "
+ + bp.name + " owned by uid " + bp.uid);
+ }
+ }
+ throw new SecurityException("No permission tree found for " + permName);
+ }
+
+ public void enforceDeclaredUsedAndRuntimeOrDevelopment(PackageParser.Package pkg) {
+ int index = pkg.requestedPermissions.indexOf(name);
+ if (index == -1) {
+ throw new SecurityException("Package " + pkg.packageName
+ + " has not requested permission " + name);
+ }
+ if (!isRuntime() && !isDevelopment()) {
+ throw new SecurityException("Permission " + name
+ + " is not a changeable permission type");
+ }
+ }
+
+ private static BasePermission findPermissionTreeLP(
+ Map<String, BasePermission> permissionTrees, String permName) {
+ for (BasePermission bp : permissionTrees.values()) {
+ if (permName.startsWith(bp.name) &&
+ permName.length() > bp.name.length() &&
+ permName.charAt(bp.name.length()) == '.') {
+ return bp;
+ }
+ }
+ return null;
+ }
+
+ public @Nullable PermissionInfo generatePermissionInfo(@NonNull String groupName, int flags) {
+ if (groupName == null) {
+ if (perm == null || perm.info.group == null) {
+ return generatePermissionInfo(protectionLevel, flags);
+ }
+ } else {
+ if (perm != null && groupName.equals(perm.info.group)) {
+ return PackageParser.generatePermissionInfo(perm, flags);
+ }
+ }
+ return null;
+ }
+
+ public @NonNull PermissionInfo generatePermissionInfo(int adjustedProtectionLevel, int flags) {
+ final boolean protectionLevelChanged = protectionLevel != adjustedProtectionLevel;
+ // if we return different protection level, don't use the cached info
+ if (perm != null && !protectionLevelChanged) {
+ return PackageParser.generatePermissionInfo(perm, flags);
+ }
+ final PermissionInfo pi = new PermissionInfo();
+ pi.name = name;
+ pi.packageName = sourcePackageName;
+ pi.nonLocalizedLabel = name;
+ pi.protectionLevel = protectionLevelChanged ? adjustedProtectionLevel : protectionLevel;
+ return pi;
+ }
+
+ public static boolean readLPw(@NonNull Map<String, BasePermission> out,
+ @NonNull XmlPullParser parser) {
+ final String tagName = parser.getName();
+ if (!tagName.equals(TAG_ITEM)) {
+ return false;
+ }
+ final String name = parser.getAttributeValue(null, ATTR_NAME);
+ final String sourcePackage = parser.getAttributeValue(null, ATTR_PACKAGE);
+ final String ptype = parser.getAttributeValue(null, "type");
+ if (name == null || sourcePackage == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: permissions has" + " no name at "
+ + parser.getPositionDescription());
+ return false;
+ }
+ final boolean dynamic = "dynamic".equals(ptype);
+ BasePermission bp = out.get(name);
+ // If the permission is builtin, do not clobber it.
+ if (bp == null || bp.type != TYPE_BUILTIN) {
+ bp = new BasePermission(name.intern(), sourcePackage,
+ dynamic ? TYPE_DYNAMIC : TYPE_NORMAL);
+ }
+ bp.protectionLevel = readInt(parser, null, "protection",
+ PermissionInfo.PROTECTION_NORMAL);
+ bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel);
+ if (dynamic) {
+ final PermissionInfo pi = new PermissionInfo();
+ pi.packageName = sourcePackage.intern();
+ pi.name = name.intern();
+ pi.icon = readInt(parser, null, "icon", 0);
+ pi.nonLocalizedLabel = parser.getAttributeValue(null, "label");
+ pi.protectionLevel = bp.protectionLevel;
+ bp.pendingPermissionInfo = pi;
+ }
+ out.put(bp.name, bp);
+ return true;
+ }
+
+ private static int readInt(XmlPullParser parser, String ns, String name, int defValue) {
+ String v = parser.getAttributeValue(ns, name);
+ try {
+ if (v == null) {
+ return defValue;
+ }
+ return Integer.parseInt(v);
+ } catch (NumberFormatException e) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: attribute " + name
+ + " has bad integer value " + v + " at "
+ + parser.getPositionDescription());
+ }
+ return defValue;
+ }
+
+ public void writeLPr(@NonNull XmlSerializer serializer) throws IOException {
+ if (sourcePackageName == null) {
+ return;
+ }
+ serializer.startTag(null, TAG_ITEM);
+ serializer.attribute(null, ATTR_NAME, name);
+ serializer.attribute(null, ATTR_PACKAGE, sourcePackageName);
+ if (protectionLevel != PermissionInfo.PROTECTION_NORMAL) {
+ serializer.attribute(null, "protection", Integer.toString(protectionLevel));
+ }
+ if (type == BasePermission.TYPE_DYNAMIC) {
+ final PermissionInfo pi = perm != null ? perm.info : pendingPermissionInfo;
+ if (pi != null) {
+ serializer.attribute(null, "type", "dynamic");
+ if (pi.icon != 0) {
+ serializer.attribute(null, "icon", Integer.toString(pi.icon));
+ }
+ if (pi.nonLocalizedLabel != null) {
+ serializer.attribute(null, "label", pi.nonLocalizedLabel.toString());
+ }
+ }
+ }
+ serializer.endTag(null, TAG_ITEM);
+ }
+
+ private static boolean compareStrings(CharSequence s1, CharSequence s2) {
+ if (s1 == null) {
+ return s2 == null;
+ }
+ if (s2 == null) {
+ return false;
+ }
+ if (s1.getClass() != s2.getClass()) {
+ return false;
+ }
+ return s1.equals(s2);
+ }
+
+ private static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) {
+ if (pi1.icon != pi2.icon) return false;
+ if (pi1.logo != pi2.logo) return false;
+ if (pi1.protectionLevel != pi2.protectionLevel) return false;
+ if (!compareStrings(pi1.name, pi2.name)) return false;
+ if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
+ // We'll take care of setting this one.
+ if (!compareStrings(pi1.packageName, pi2.packageName)) return false;
+ // These are not currently stored in settings.
+ //if (!compareStrings(pi1.group, pi2.group)) return false;
+ //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
+ //if (pi1.labelRes != pi2.labelRes) return false;
+ //if (pi1.descriptionRes != pi2.descriptionRes) return false;
+ return true;
+ }
+
+ public boolean dumpPermissionsLPr(@NonNull PrintWriter pw, @NonNull String packageName,
+ @NonNull Set<String> permissionNames, boolean readEnforced,
+ boolean printedSomething, @NonNull DumpState dumpState) {
+ if (packageName != null && !packageName.equals(sourcePackageName)) {
+ return false;
+ }
+ if (permissionNames != null && !permissionNames.contains(name)) {
+ return false;
+ }
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println();
+ pw.println("Permissions:");
+ printedSomething = true;
+ }
+ pw.print(" Permission ["); pw.print(name); pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(this)));
+ pw.println("):");
+ pw.print(" sourcePackage="); pw.println(sourcePackageName);
+ pw.print(" uid="); pw.print(uid);
+ pw.print(" gids="); pw.print(Arrays.toString(
+ computeGids(UserHandle.USER_SYSTEM)));
+ pw.print(" type="); pw.print(type);
+ pw.print(" prot=");
+ pw.println(PermissionInfo.protectionToString(protectionLevel));
+ if (perm != null) {
+ pw.print(" perm="); pw.println(perm);
+ if ((perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0
+ || (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) {
+ pw.print(" flags=0x"); pw.println(Integer.toHexString(perm.info.flags));
+ }
+ }
+ if (sourcePackageSetting != null) {
+ pw.print(" packageSetting="); pw.println(sourcePackageSetting);
+ }
+ if (READ_EXTERNAL_STORAGE.equals(name)) {
+ pw.print(" enforced=");
+ pw.println(readEnforced);
+ }
+ return true;
+ }
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 578429a..db7817e 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -20,9 +20,12 @@
import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
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.HOME_STACK_ID;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.AppOpsManager.OP_TOAST_WINDOW;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Context.CONTEXT_RESTRICTED;
import static android.content.Context.DISPLAY_SERVICE;
import static android.content.Context.WINDOW_SERVICE;
@@ -7917,8 +7920,10 @@
mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
- mWindowManagerFuncs.getStackBounds(HOME_STACK_ID, mNonDockedStackBounds);
- mWindowManagerFuncs.getStackBounds(DOCKED_STACK_ID, mDockedStackBounds);
+ mWindowManagerFuncs.getStackBounds(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mNonDockedStackBounds);
+ mWindowManagerFuncs.getStackBounds(
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);
final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
final int diff = visibility ^ mLastSystemUiFlags;
final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 338ad2a..b917dae 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -206,6 +206,8 @@
private static final String REASON_REBOOT = "reboot";
private static final String REASON_USERREQUESTED = "shutdown,userrequested";
private static final String REASON_THERMAL_SHUTDOWN = "shutdown,thermal";
+ private static final String REASON_LOW_BATTERY = "shutdown,battery";
+ private static final String REASON_BATTERY_THERMAL_STATE = "shutdown,thermal,battery";
private static final String TRACE_SCREEN_ON = "Screen turning on";
@@ -4651,6 +4653,10 @@
return PowerManager.SHUTDOWN_REASON_USER_REQUESTED;
case REASON_THERMAL_SHUTDOWN:
return PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN;
+ case REASON_LOW_BATTERY:
+ return PowerManager.SHUTDOWN_REASON_LOW_BATTERY;
+ case REASON_BATTERY_THERMAL_STATE:
+ return PowerManager.SHUTDOWN_REASON_BATTERY_THERMAL;
default:
return PowerManager.SHUTDOWN_REASON_UNKNOWN;
}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 4294f15..05fd248 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -39,6 +39,7 @@
/**
* Helper service for statsd (the native stats management service in cmds/statsd/).
* Used for registering and receiving alarms on behalf of statsd.
+ * @hide
*/
public class StatsCompanionService extends IStatsCompanionService.Stub {
static final String TAG = "StatsCompanionService";
diff --git a/services/core/java/com/android/server/storage/AppCollector.java b/services/core/java/com/android/server/storage/AppCollector.java
index 03b754f..0b51f9c 100644
--- a/services/core/java/com/android/server/storage/AppCollector.java
+++ b/services/core/java/com/android/server/storage/AppCollector.java
@@ -135,7 +135,7 @@
PackageStats packageStats = new PackageStats(app.packageName,
user.id);
packageStats.cacheSize = storageStats.getCacheBytes();
- packageStats.codeSize = storageStats.getCodeBytes();
+ packageStats.codeSize = storageStats.getAppBytes();
packageStats.dataSize = storageStats.getDataBytes();
stats.add(packageStats);
} catch (NameNotFoundException | IOException e) {
diff --git a/services/core/java/com/android/server/storage/DiskStatsFileLogger.java b/services/core/java/com/android/server/storage/DiskStatsFileLogger.java
index 0094ab5..1db3ec4 100644
--- a/services/core/java/com/android/server/storage/DiskStatsFileLogger.java
+++ b/services/core/java/com/android/server/storage/DiskStatsFileLogger.java
@@ -56,10 +56,12 @@
public static final String SYSTEM_KEY = "systemSize";
public static final String MISC_KEY = "otherSize";
public static final String APP_SIZE_AGG_KEY = "appSize";
+ public static final String APP_DATA_SIZE_AGG_KEY = "appDataSize";
public static final String APP_CACHE_AGG_KEY = "cacheSize";
public static final String PACKAGE_NAMES_KEY = "packageNames";
public static final String APP_SIZES_KEY = "appSizes";
public static final String APP_CACHES_KEY = "cacheSizes";
+ public static final String APP_DATA_KEY = "appDataSizes";
public static final String LAST_QUERY_TIMESTAMP_KEY = "queryTime";
private MeasurementResult mResult;
@@ -114,31 +116,39 @@
private void addAppsToJson(JSONObject json) throws JSONException {
JSONArray names = new JSONArray();
JSONArray appSizeList = new JSONArray();
+ JSONArray appDataSizeList = new JSONArray();
JSONArray cacheSizeList = new JSONArray();
long appSizeSum = 0L;
+ long appDataSizeSum = 0L;
long cacheSizeSum = 0L;
boolean isExternal = Environment.isExternalStorageEmulated();
for (Map.Entry<String, PackageStats> entry : filterOnlyPrimaryUser().entrySet()) {
PackageStats stat = entry.getValue();
- long appSize = stat.codeSize + stat.dataSize;
+ long appSize = stat.codeSize;
+ long appDataSize = stat.dataSize;
long cacheSize = stat.cacheSize;
if (isExternal) {
- appSize += stat.externalCodeSize + stat.externalDataSize;
+ appSize += stat.externalCodeSize;
+ appDataSize += stat.externalDataSize;
cacheSize += stat.externalCacheSize;
}
appSizeSum += appSize;
+ appDataSizeSum += appDataSize;
cacheSizeSum += cacheSize;
names.put(stat.packageName);
appSizeList.put(appSize);
+ appDataSizeList.put(appDataSize);
cacheSizeList.put(cacheSize);
}
json.put(PACKAGE_NAMES_KEY, names);
json.put(APP_SIZES_KEY, appSizeList);
json.put(APP_CACHES_KEY, cacheSizeList);
+ json.put(APP_DATA_KEY, appDataSizeList);
json.put(APP_SIZE_AGG_KEY, appSizeSum);
json.put(APP_CACHE_AGG_KEY, cacheSizeSum);
+ json.put(APP_DATA_SIZE_AGG_KEY, appDataSizeSum);
}
/**
diff --git a/services/core/java/com/android/server/timezone/IntentHelperImpl.java b/services/core/java/com/android/server/timezone/IntentHelperImpl.java
index bc0f6e4..6e6259d 100644
--- a/services/core/java/com/android/server/timezone/IntentHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/IntentHelperImpl.java
@@ -24,6 +24,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.PatternMatcher;
+import android.os.UserHandle;
import android.util.Slog;
/**
@@ -76,7 +77,9 @@
// not expected to need local data.
Receiver packageUpdateReceiver = new Receiver(packageTracker);
- mContext.registerReceiver(packageUpdateReceiver, packageIntentFilter);
+ mContext.registerReceiverAsUser(
+ packageUpdateReceiver, UserHandle.SYSTEM, packageIntentFilter,
+ null /* broadcastPermission */, null /* default handler */);
}
/** Sends an intent to trigger an update check. */
diff --git a/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java b/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
index 2e0c21b..b89dd38 100644
--- a/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
@@ -26,6 +26,7 @@
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.util.Slog;
import java.util.List;
@@ -114,8 +115,8 @@
@Override
public boolean contentProviderRegistered(String authority, String requiredPackageName) {
int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
- ProviderInfo providerInfo =
- mPackageManager.resolveContentProvider(authority, flags);
+ ProviderInfo providerInfo = mPackageManager.resolveContentProviderAsUser(
+ authority, flags, UserHandle.SYSTEM.getIdentifier());
if (providerInfo == null) {
Slog.i(TAG, "contentProviderRegistered: No content provider registered with authority="
+ authority);
@@ -136,7 +137,8 @@
throws PackageManager.NameNotFoundException {
int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
- List<ResolveInfo> resolveInfo = mPackageManager.queryBroadcastReceivers(intent, flags);
+ List<ResolveInfo> resolveInfo = mPackageManager.queryBroadcastReceiversAsUser(
+ intent, flags, UserHandle.SYSTEM);
if (resolveInfo.size() != 1) {
Slog.i(TAG, "receiverRegistered: Zero or multiple broadcast receiver registered for"
+ " intent=" + intent + ", found=" + resolveInfo);
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index dc5a814..9e028d3 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -21,8 +21,10 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
import static com.android.server.wm.proto.ConfigurationContainerProto.FULL_CONFIGURATION;
import static com.android.server.wm.proto.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION;
@@ -152,6 +154,17 @@
onOverrideConfigurationChanged(mTmpConfig);
}
+ /**
+ * Returns true if this container is currently in multi-window mode. I.e. sharing the screen
+ * with another activity.
+ */
+ public boolean inMultiWindowMode() {
+ /*@WindowConfiguration.WindowingMode*/ int windowingMode =
+ mFullConfiguration.windowConfiguration.getWindowingMode();
+ return windowingMode != WINDOWING_MODE_FULLSCREEN
+ && windowingMode != WINDOWING_MODE_UNDEFINED;
+ }
+
/** Returns true if this container is currently in split-screen windowing mode. */
public boolean inSplitScreenWindowingMode() {
/*@WindowConfiguration.WindowingMode*/ int windowingMode =
@@ -175,7 +188,7 @@
* {@link WindowConfiguration##WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on
* its current state.
*/
- public boolean supportSplitScreenWindowingMode() {
+ public boolean supportsSplitScreenWindowingMode() {
return mFullConfiguration.windowConfiguration.supportSplitScreenWindowingMode();
}
@@ -238,6 +251,16 @@
/**
* Returns true if this container is compatible with the input windowing mode and activity type.
+ * The container is compatible:
+ * - If {@param activityType} and {@param windowingMode} match this container activity type and
+ * windowing mode.
+ * - If {@param activityType} is {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or
+ * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} and this containers activity type is also
+ * standard or undefined and its windowing mode matches {@param windowingMode}.
+ * - If {@param activityType} isn't {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or
+ * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} or this containers activity type isn't
+ * also standard or undefined and its activity type matches {@param activityType} regardless of
+ * if {@param windowingMode} matches the containers windowing mode.
*/
public boolean isCompatible(int windowingMode, int activityType) {
final int thisActivityType = getActivityType();
@@ -249,7 +272,8 @@
return true;
}
- if (activityType != ACTIVITY_TYPE_UNDEFINED && activityType != ACTIVITY_TYPE_STANDARD) {
+ if ((activityType != ACTIVITY_TYPE_UNDEFINED && activityType != ACTIVITY_TYPE_STANDARD)
+ || !isActivityTypeStandardOrUndefined()) {
// Only activity type need to match for non-standard activity types that are defined.
return sameActivityType;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7ae5d1a..91cce31 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -18,7 +18,6 @@
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.HOME_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -1470,7 +1469,7 @@
* Returns the topmost stack on the display that is compatible with the input windowing mode and
* activity type. Null is no compatible stack on the display.
*/
- private TaskStack getStack(int windowingMode, int activityType) {
+ TaskStack getStack(int windowingMode, int activityType) {
for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
final TaskStack stack = mTaskStackContainers.get(i);
if (stack.isCompatible(windowingMode, activityType)) {
@@ -1486,10 +1485,10 @@
}
@VisibleForTesting
- int getStackPosById(int stackId) {
+ int getStackPosition(int windowingMode, int activityType) {
for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
final TaskStack stack = mTaskStackContainers.get(i);
- if (stack.mStackId == stackId) {
+ if (stack.isCompatible(windowingMode, activityType)) {
return i;
}
}
@@ -2049,8 +2048,8 @@
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) &&
- StackId.isStackAffectedByDragResizing(stack.mStackId)) {
+ if (stack.isVisible() && (imeOnBottom || isDockedOnBottom)
+ && stack.inSplitScreenWindowingMode()) {
stack.setAdjustedForIme(imeWin, imeOnBottom && imeHeightChanged);
} else {
stack.resetAdjustedForIme(false);
@@ -3379,7 +3378,7 @@
* @see WindowManagerService#addStackToDisplay(int, int, boolean)
*/
void addStackToDisplay(TaskStack stack, boolean onTop) {
- if (stack.mStackId == HOME_STACK_ID) {
+ if (stack.isActivityTypeHome()) {
if (mHomeStack != null) {
throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index e0a4666..6f441b9 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -20,6 +20,7 @@
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Surface.ROTATION_270;
@@ -331,7 +332,7 @@
mLastVisibility = visible;
notifyDockedDividerVisibilityChanged(visible);
if (!visible) {
- setResizeDimLayer(false, INVALID_STACK_ID, 0f);
+ setResizeDimLayer(false, WINDOWING_MODE_UNDEFINED, 0f);
}
}
@@ -519,9 +520,18 @@
}
- void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+ /**
+ * Shows a dim layer with {@param alpha} if {@param visible} is true and
+ * {@param targetWindowingMode} isn't
+ * {@link android.app.WindowConfiguration#WINDOWING_MODE_UNDEFINED} and there is a stack on the
+ * display in that windowing mode.
+ */
+ void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) {
mService.openSurfaceTransaction();
- final TaskStack stack = mDisplayContent.getStackById(targetStackId);
+ // TODO: Maybe only allow split-screen windowing modes?
+ final TaskStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED
+ ? mDisplayContent.getStack(targetWindowingMode)
+ : null;
final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
boolean visibleAndValid = visible && stack != null && dockedStack != null;
if (visibleAndValid) {
diff --git a/services/core/java/com/android/server/wm/DragResizeMode.java b/services/core/java/com/android/server/wm/DragResizeMode.java
index 8ab0406..c0bf1e8 100644
--- a/services/core/java/com/android/server/wm/DragResizeMode.java
+++ b/services/core/java/com/android/server/wm/DragResizeMode.java
@@ -16,11 +16,7 @@
package com.android.server.wm;
-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.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
-import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
/**
* Describes the mode in which a window is drag resizing.
@@ -39,15 +35,12 @@
*/
static final int DRAG_RESIZE_MODE_DOCKED_DIVIDER = 1;
- static boolean isModeAllowedForStack(int stackId, int mode) {
+ static boolean isModeAllowedForStack(TaskStack stack, int mode) {
switch (mode) {
case DRAG_RESIZE_MODE_FREEFORM:
- return stackId == FREEFORM_WORKSPACE_STACK_ID;
+ return stack.getWindowingMode() == WINDOWING_MODE_FREEFORM;
case DRAG_RESIZE_MODE_DOCKED_DIVIDER:
- return stackId == DOCKED_STACK_ID
- || stackId == FULLSCREEN_WORKSPACE_STACK_ID
- || stackId == HOME_STACK_ID
- || stackId == RECENTS_STACK_ID;
+ return stack.inSplitScreenWindowingMode();
default:
return false;
}
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 4c9326db..ef31598 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -16,7 +16,7 @@
package com.android.server.wm;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
@@ -494,7 +494,7 @@
pw.println(prefix + "PinnedStackController");
pw.print(prefix + " defaultBounds="); getDefaultBounds().printShortString(pw);
pw.println();
- mService.getStackBounds(PINNED_STACK_ID, mTmpRect);
+ mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
pw.print(prefix + " movementBounds="); getMovementBounds(mTmpRect).printShortString(pw);
pw.println();
pw.println(prefix + " mIsImeShowing=" + mIsImeShowing);
@@ -515,7 +515,7 @@
void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
getDefaultBounds().writeToProto(proto, DEFAULT_BOUNDS);
- mService.getStackBounds(PINNED_STACK_ID, mTmpRect);
+ mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
getMovementBounds(mTmpRect).writeToProto(proto, MOVEMENT_BOUNDS);
proto.end(token);
}
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
index 590ac6e..2215f20 100644
--- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
@@ -16,19 +16,16 @@
package com.android.server.wm;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState;
import android.app.RemoteAction;
-import android.content.res.Configuration;
import android.graphics.Rect;
-import com.android.server.UiThread;
-
import java.util.List;
/**
@@ -101,7 +98,8 @@
}
schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_START;
- mService.getStackBounds(FULLSCREEN_WORKSPACE_STACK_ID, mTmpToBounds);
+ mService.getStackBounds(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mTmpToBounds);
if (!mTmpToBounds.isEmpty()) {
// If there is a fullscreen bounds, use that
toBounds = new Rect(mTmpToBounds);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 227e4b2..7832f5d 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -422,6 +422,17 @@
return null;
}
+ TaskStack getStack(int windowingMode, int activityType) {
+ for (int i = mChildren.size() - 1; i >= 0; i--) {
+ final DisplayContent dc = mChildren.get(i);
+ final TaskStack stack = dc.getStack(windowingMode, activityType);
+ if (stack != null) {
+ return stack;
+ }
+ }
+ return null;
+ }
+
void setSecureSurfaceState(int userId, boolean disabled) {
forAllWindows((w) -> {
if (w.mHasSurface && userId == UserHandle.getUserId(w.mOwnerUid)) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7464a9b..7e8d130 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -23,6 +23,7 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.res.Configuration.EMPTY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static com.android.server.EventLogTags.WM_TASK_REMOVED;
@@ -37,7 +38,6 @@
import static com.android.server.wm.proto.TaskProto.WINDOW_CONTAINER;
import android.annotation.CallSuper;
-import android.app.ActivityManager.StackId;
import android.app.ActivityManager.TaskDescription;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -280,15 +280,9 @@
// WindowConfiguration long term.
private int setBounds(Rect bounds, Configuration overrideConfig) {
if (overrideConfig == null) {
- overrideConfig = Configuration.EMPTY;
+ overrideConfig = EMPTY;
}
- if (bounds == null && !Configuration.EMPTY.equals(overrideConfig)) {
- throw new IllegalArgumentException("null bounds but non empty configuration: "
- + overrideConfig);
- }
- if (bounds != null && Configuration.EMPTY.equals(overrideConfig)) {
- throw new IllegalArgumentException("non null bounds, but empty configuration");
- }
+
boolean oldFullscreen = mFillsParent;
int rotation = Surface.ROTATION_0;
final DisplayContent displayContent = mStack.getDisplayContent();
@@ -323,7 +317,7 @@
if (displayContent != null) {
displayContent.mDimLayerController.updateDimLayer(this);
}
- onOverrideConfigurationChanged(mFillsParent ? Configuration.EMPTY : overrideConfig);
+ onOverrideConfigurationChanged(overrideConfig);
return boundsChange;
}
@@ -406,7 +400,7 @@
* the adjusted bounds's top.
*/
void alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) {
- if (!isResizeable() || Configuration.EMPTY.equals(getOverrideConfiguration())) {
+ if (!isResizeable() || EMPTY.equals(getOverrideConfiguration())) {
return;
}
@@ -531,7 +525,7 @@
void setDragResizing(boolean dragResizing, int dragResizeMode) {
if (mDragResizing != dragResizing) {
- if (!DragResizeMode.isModeAllowedForStack(mStack.mStackId, dragResizeMode)) {
+ if (!DragResizeMode.isModeAllowedForStack(mStack, dragResizeMode)) {
throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
+ mStack.mStackId + " dragResizeMode=" + dragResizeMode);
}
@@ -554,7 +548,9 @@
return;
}
if (mFillsParent) {
- setBounds(null, Configuration.EMPTY);
+ // TODO: Yeah...not sure if this works with WindowConfiguration, but shouldn't be a
+ // problem once we move mBounds into WindowConfiguration.
+ setBounds(null, getOverrideConfiguration());
return;
}
final int newRotation = displayContent.getDisplayInfo().rotation;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 751769a..bff24f6 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -254,7 +254,7 @@
@VisibleForTesting
int getSnapshotMode(Task task) {
final AppWindowToken topChild = task.getTopChild();
- if (StackId.isHomeOrRecentsStack(task.mStack.mStackId)) {
+ if (!task.isActivityTypeStandardOrUndefined()) {
return SNAPSHOT_MODE_NONE;
} else if (topChild != null && topChild.shouldUseAppThemeSnapshot()) {
return SNAPSHOT_MODE_APP_THEME;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 7cb90de..6527883 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -19,8 +19,11 @@
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -44,7 +47,6 @@
import static com.android.server.wm.proto.StackProto.WINDOW_CONTAINER;
import android.annotation.CallSuper;
-import android.app.ActivityManager.StackId;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
@@ -736,7 +738,7 @@
outTempTaskBounds.setEmpty();
// When the home stack is resizable, should always have the same stack and task bounds
- if (mStackId == HOME_STACK_ID) {
+ if (isActivityTypeHome()) {
final Task homeTask = findHomeTask();
if (homeTask != null && homeTask.isResizeable()) {
// Calculate the home stack bounds when in docked mode and the home stack is
@@ -921,7 +923,9 @@
void resetAnimationBackgroundAnimator() {
mAnimationBackgroundAnimator = null;
- mAnimationBackgroundSurface.hide();
+ if (mAnimationBackgroundSurface != null) {
+ mAnimationBackgroundSurface.hide();
+ }
}
void setAnimationBackground(WindowStateAnimator winAnimator, int color) {
@@ -1008,7 +1012,7 @@
mAdjustImeAmount = 0f;
mAdjustDividerAmount = 0f;
updateAdjustedBounds();
- mService.setResizeDimLayer(false, mStackId, 1.0f);
+ mService.setResizeDimLayer(false, getWindowingMode(), 1.0f);
} else {
mImeGoingAway |= mAdjustedForIme;
}
@@ -1204,7 +1208,7 @@
if (mAdjustedForIme && adjust && !isImeTarget) {
final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount)
* IME_ADJUST_DIM_AMOUNT;
- mService.setResizeDimLayer(true, mStackId, alpha);
+ mService.setResizeDimLayer(true, getWindowingMode(), alpha);
}
}
@@ -1283,7 +1287,7 @@
@Override
public boolean dimFullscreen() {
- return StackId.isHomeOrRecentsStack(mStackId) || fillsParent();
+ return !isActivityTypeStandard() || fillsParent();
}
@Override
@@ -1663,7 +1667,15 @@
@Override
int getOrientation() {
- return (StackId.canSpecifyOrientation(mStackId))
- ? super.getOrientation() : SCREEN_ORIENTATION_UNSET;
+ return (canSpecifyOrientation()) ? super.getOrientation() : SCREEN_ORIENTATION_UNSET;
+ }
+
+ private boolean canSpecifyOrientation() {
+ final int windowingMode = getWindowingMode();
+ final int activityType = getActivityType();
+ return windowingMode == WINDOWING_MODE_FULLSCREEN
+ || activityType == ACTIVITY_TYPE_HOME
+ || activityType == ACTIVITY_TYPE_RECENTS
+ || activityType == ACTIVITY_TYPE_ASSISTANT;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index 857b13d..fdd2ade 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -21,11 +21,8 @@
import java.util.ArrayDeque;
import java.util.function.Consumer;
-import static android.app.ActivityManager.StackId;
-import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
@@ -187,12 +184,13 @@
}
}
- final int stackId = w.getAppToken() != null ? w.getStackId() : INVALID_STACK_ID;
- if (stackId == PINNED_STACK_ID) {
+ final int windowingMode = w.getWindowingMode();
+ if (windowingMode == WINDOWING_MODE_PINNED) {
mPinnedWindows.add(w);
- } else if (stackId == DOCKED_STACK_ID) {
+ } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
mDockedWindows.add(w);
- } else if (stackId == ASSISTANT_STACK_ID) {
+ }
+ if (w.isActivityTypeAssistant()) {
mAssistantWindows.add(w);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6a5f6fa..1fb2188 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2043,10 +2043,14 @@
Slog.i(TAG_WM, "Relayout " + win + ": oldVis=" + oldVisibility
+ " newVis=" + viewVisibility, stack);
}
- if (viewVisibility == View.VISIBLE &&
- (win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
- || !win.mAppToken.isClientHidden())) {
+ // We should only relayout if the view is visible, it is a starting window, or the
+ // associated appToken is not hidden.
+ final boolean shouldRelayout = viewVisibility == View.VISIBLE &&
+ (win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
+ || !win.mAppToken.isClientHidden());
+
+ if (shouldRelayout) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
// We are about to create a surface, but we didn't run a layout yet. So better run
@@ -2193,8 +2197,18 @@
// and needs process it before handling the corresponding window frame. the variable
// {@code mergedConfiguration} is an out parameter that will be passed back to the
// client over IPC and checked there.
- win.getMergedConfiguration(mergedConfiguration);
- win.setReportedConfiguration(mergedConfiguration);
+ // Note: in the cases where the window is tied to an activity, we should not send a
+ // configuration update when the window has requested to be hidden. Doing so can lead
+ // to the client erroneously accepting a configuration that would have otherwise caused
+ // an activity restart. We instead hand back the last reported
+ // {@link MergedConfiguration}.
+ if (shouldRelayout) {
+ win.getMergedConfiguration(mergedConfiguration);
+ } else {
+ win.getLastReportedMergedConfiguration(mergedConfiguration);
+ }
+
+ win.setLastReportedMergedConfiguration(mergedConfiguration);
outFrame.set(win.mCompatFrame);
outOverscanInsets.set(win.mOverscanInsets);
@@ -2895,9 +2909,9 @@
}
@Override
- public void getStackBounds(int stackId, Rect bounds) {
+ public void getStackBounds(int windowingMode, int activityType, Rect bounds) {
synchronized (mWindowMap) {
- final TaskStack stack = mRoot.getStackById(stackId);
+ final TaskStack stack = mRoot.getStack(windowingMode, activityType);
if (stack != null) {
stack.getBounds(bounds);
return;
@@ -7141,10 +7155,10 @@
}
@Override
- public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+ public void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) {
synchronized (mWindowMap) {
getDefaultDisplayContentLocked().getDockedDividerController().setResizeDimLayer(
- visible, targetStackId, alpha);
+ visible, targetWindowingMode, alpha);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index eba7c3a..4ff0f39 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -257,7 +257,7 @@
* 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();
+ private final MergedConfiguration mLastReportedConfiguration = new MergedConfiguration();
/**
* Actual position of the surface shown on-screen (may be modified by animation). These are
@@ -1244,7 +1244,7 @@
// this is not necessarily what the client has processed yet. Find a
// better indicator consistent with the client.
return (mOrientationChanging || (isVisible()
- && getConfiguration().orientation != mLastReportedConfiguration.orientation))
+ && getConfiguration().orientation != getLastReportedConfiguration().orientation))
&& !mSeamlesslyRotated
&& !mOrientationChangeTimedOut;
}
@@ -1758,7 +1758,7 @@
/** Returns true if last applied config was not yet requested by client. */
boolean isConfigChanged() {
- return !mLastReportedConfiguration.equals(getConfiguration());
+ return !getLastReportedConfiguration().equals(getConfiguration());
}
void onWindowReplacementTimeout() {
@@ -2312,8 +2312,16 @@
outConfiguration.setConfiguration(globalConfig, overrideConfig);
}
- void setReportedConfiguration(MergedConfiguration config) {
- mLastReportedConfiguration.setTo(config.getMergedConfiguration());
+ void setLastReportedMergedConfiguration(MergedConfiguration config) {
+ mLastReportedConfiguration.setTo(config);
+ }
+
+ void getLastReportedMergedConfiguration(MergedConfiguration config) {
+ config.setTo(mLastReportedConfiguration);
+ }
+
+ private Configuration getLastReportedConfiguration() {
+ return mLastReportedConfiguration.getMergedConfiguration();
}
void adjustStartingWindowFlags() {
@@ -2853,7 +2861,7 @@
new MergedConfiguration(mService.mRoot.getConfiguration(),
getMergedOverrideConfiguration());
- setReportedConfiguration(mergedConfiguration);
+ setLastReportedMergedConfiguration(mergedConfiguration);
if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == DRAW_PENDING)
Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
@@ -3080,7 +3088,7 @@
if (task == null) {
return false;
}
- if (!StackId.isStackAffectedByDragResizing(getStackId())) {
+ if (!inSplitScreenWindowingMode()) {
return false;
}
if (mAttrs.width != MATCH_PARENT || mAttrs.height != MATCH_PARENT) {
@@ -3254,7 +3262,7 @@
}
pw.print(prefix); pw.print("mFullConfiguration="); pw.println(getConfiguration());
pw.print(prefix); pw.print("mLastReportedConfiguration=");
- pw.println(mLastReportedConfiguration);
+ pw.println(getLastReportedConfiguration());
}
pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
@@ -3314,7 +3322,7 @@
pw.print(prefix); pw.print("mOrientationChanging=");
pw.print(mOrientationChanging);
pw.print(" configOrientationChanging=");
- pw.print(mLastReportedConfiguration.orientation
+ pw.print(getLastReportedConfiguration().orientation
!= getConfiguration().orientation);
pw.print(" mAppFreezing="); pw.print(mAppFreezing);
pw.print(" mTurnOnScreen="); pw.print(mTurnOnScreen);
diff --git a/services/core/jni/com_android_server_UsbDescriptorParser.cpp b/services/core/jni/com_android_server_UsbDescriptorParser.cpp
index 98c5ec1..df85e31 100644
--- a/services/core/jni/com_android_server_UsbDescriptorParser.cpp
+++ b/services/core/jni/com_android_server_UsbDescriptorParser.cpp
@@ -18,7 +18,7 @@
#include "utils/Log.h"
#include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include <usbhost/usbhost.h>
diff --git a/services/core/jni/com_android_server_locksettings_SyntheticPasswordManager.cpp b/services/core/jni/com_android_server_locksettings_SyntheticPasswordManager.cpp
index 248dedb..bc13fde 100644
--- a/services/core/jni/com_android_server_locksettings_SyntheticPasswordManager.cpp
+++ b/services/core/jni/com_android_server_locksettings_SyntheticPasswordManager.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "SyntheticPasswordManager"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include "jni.h"
#include <android_runtime/Log.h>
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 39f90ca..b6c3df7 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -19,7 +19,7 @@
//#define LOG_NDEBUG 0
#include <android/hardware/power/1.1/IPower.h>
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
#include "jni.h"
#include <nativehelper/ScopedUtfChars.h>
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 948c028..d7ec7b6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -152,7 +152,7 @@
* them from the build system somehow.
*/
private static final String BACKUP_MANAGER_SERVICE_CLASS =
- "com.android.server.backup.BackupManagerService$Lifecycle";
+ "com.android.server.backup.RefactoredBackupManagerService$Lifecycle";
private static final String APPWIDGET_SERVICE_CLASS =
"com.android.server.appwidget.AppWidgetService";
private static final String VOICE_RECOGNITION_MANAGER_SERVICE_CLASS =
@@ -682,6 +682,7 @@
VibratorService vibrator = null;
IStorageManager storageManager = null;
NetworkManagementService networkManagement = null;
+ IpSecService ipSecService = null;
NetworkStatsService networkStats = null;
NetworkPolicyManagerService networkPolicy = null;
ConnectivityService connectivity = null;
@@ -1031,6 +1032,15 @@
reportWtf("starting NetworkManagement Service", e);
}
traceEnd();
+
+ traceBeginAndSlog("StartIpSecService");
+ try {
+ ipSecService = IpSecService.create(context);
+ ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService);
+ } catch (Throwable e) {
+ reportWtf("starting IpSec Service", e);
+ }
+ traceEnd();
}
if (!disableNonCoreServices && !disableTextServices) {
@@ -1654,6 +1664,7 @@
final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
final MediaRouterService mediaRouterF = mediaRouter;
final MmsServiceBroker mmsServiceF = mmsService;
+ final IpSecService ipSecServiceF = ipSecService;
final WindowManagerService windowManagerF = wm;
// We now tell the activity manager it is okay to run third party
@@ -1724,6 +1735,13 @@
.networkScoreAndNetworkManagementServiceReady();
}
traceEnd();
+ traceBeginAndSlog("MakeIpSecServiceReady");
+ try {
+ if (ipSecServiceF != null) ipSecServiceF.systemReady();
+ } catch (Throwable e) {
+ reportWtf("making IpSec Service ready", e);
+ }
+ traceEnd();
traceBeginAndSlog("MakeNetworkStatsServiceReady");
try {
if (networkStatsF != null) networkStatsF.systemReady();
diff --git a/services/net/java/android/net/ip/ConnectivityPacketTracker.java b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
index 884a8a7..0230f36 100644
--- a/services/net/java/android/net/ip/ConnectivityPacketTracker.java
+++ b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
@@ -61,11 +61,11 @@
private static final String MARK_STOP = "--- STOP ---";
private final String mTag;
- private final Handler mHandler;
private final LocalLog mLog;
private final BlockingSocketReader mPacketListener;
+ private boolean mRunning;
- public ConnectivityPacketTracker(NetworkInterface netif, LocalLog log) {
+ public ConnectivityPacketTracker(Handler h, NetworkInterface netif, LocalLog log) {
final String ifname;
final int ifindex;
final byte[] hwaddr;
@@ -81,44 +81,40 @@
}
mTag = TAG + "." + ifname;
- mHandler = new Handler();
mLog = log;
- mPacketListener = new PacketListener(ifindex, hwaddr, mtu);
+ mPacketListener = new PacketListener(h, ifindex, hwaddr, mtu);
}
public void start() {
- mLog.log(MARK_START);
+ mRunning = true;
mPacketListener.start();
}
public void stop() {
mPacketListener.stop();
- mLog.log(MARK_STOP);
+ mRunning = false;
}
private final class PacketListener extends BlockingSocketReader {
private final int mIfIndex;
private final byte mHwAddr[];
- PacketListener(int ifindex, byte[] hwaddr, int mtu) {
- super(mtu);
+ PacketListener(Handler h, int ifindex, byte[] hwaddr, int mtu) {
+ super(h, mtu);
mIfIndex = ifindex;
mHwAddr = hwaddr;
}
@Override
- protected FileDescriptor createSocket() {
+ protected FileDescriptor createFd() {
FileDescriptor s = null;
try {
- // TODO: Evaluate switching to SOCK_DGRAM and changing the
- // BlockingSocketReader's read() to recvfrom(), so that this
- // might work on non-ethernet-like links (via SLL).
s = Os.socket(AF_PACKET, SOCK_RAW, 0);
NetworkUtils.attachControlPacketFilter(s, ARPHRD_ETHER);
Os.bind(s, new PacketSocketAddress((short) ETH_P_ALL, mIfIndex));
} catch (ErrnoException | IOException e) {
logError("Failed to create packet tracking socket: ", e);
- closeSocket(s);
+ closeFd(s);
return null;
}
return s;
@@ -136,13 +132,27 @@
}
@Override
+ protected void onStart() {
+ mLog.log(MARK_START);
+ }
+
+ @Override
+ protected void onStop() {
+ if (mRunning) {
+ mLog.log(MARK_STOP);
+ } else {
+ mLog.log(MARK_STOP + " (packet listener stopped unexpectedly)");
+ }
+ }
+
+ @Override
protected void logError(String msg, Exception e) {
Log.e(mTag, msg, e);
addLogEntry(msg + e);
}
private void addLogEntry(String entry) {
- mHandler.post(() -> mLog.log(entry));
+ mLog.log(entry);
}
}
}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index b1eb085..bc07b81 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -1515,7 +1515,8 @@
private ConnectivityPacketTracker createPacketTracker() {
try {
- return new ConnectivityPacketTracker(mNetworkInterface, mConnectivityPacketLog);
+ return new ConnectivityPacketTracker(
+ getHandler(), mNetworkInterface, mConnectivityPacketLog);
} catch (IllegalArgumentException e) {
return null;
}
diff --git a/services/net/java/android/net/util/BlockingSocketReader.java b/services/net/java/android/net/util/BlockingSocketReader.java
index 12fa1e5..99bf469 100644
--- a/services/net/java/android/net/util/BlockingSocketReader.java
+++ b/services/net/java/android/net/util/BlockingSocketReader.java
@@ -16,81 +16,106 @@
package android.net.util;
+import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
+import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
+
import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.os.MessageQueue.OnFileDescriptorEventListener;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
-import libcore.io.IoBridge;
+import libcore.io.IoUtils;
import java.io.FileDescriptor;
-import java.io.InterruptedIOException;
import java.io.IOException;
/**
- * A thread that reads from a socket and passes the received packets to a
- * subclass's handlePacket() method. The packet receive buffer is recycled
- * on every read call, so subclasses should make any copies they would like
- * inside their handlePacket() implementation.
+ * This class encapsulates the mechanics of registering a file descriptor
+ * with a thread's Looper and handling read events (and errors).
*
- * All public methods may be called from any thread.
+ * Subclasses MUST implement createFd() and SHOULD override handlePacket().
+
+ * Subclasses can expect a call life-cycle like the following:
+ *
+ * [1] start() calls createFd() and (if all goes well) onStart()
+ *
+ * [2] yield, waiting for read event or error notification:
+ *
+ * [a] readPacket() && handlePacket()
+ *
+ * [b] if (no error):
+ * goto 2
+ * else:
+ * goto 3
+ *
+ * [3] stop() calls onStop() if not previously stopped
+ *
+ * The packet receive buffer is recycled on every read call, so subclasses
+ * should make any copies they would like inside their handlePacket()
+ * implementation.
+ *
+ * All public methods MUST only be called from the same thread with which
+ * the Handler constructor argument is associated.
+ *
+ * TODO: rename this class to something more correctly descriptive (something
+ * like [or less horrible than] FdReadEventsHandler?).
*
* @hide
*/
public abstract class BlockingSocketReader {
+ private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
+ private static final int UNREGISTER_THIS_FD = 0;
+
public static final int DEFAULT_RECV_BUF_SIZE = 2 * 1024;
+ private final Handler mHandler;
+ private final MessageQueue mQueue;
private final byte[] mPacket;
- private final Thread mThread;
- private volatile FileDescriptor mSocket;
- private volatile boolean mRunning;
- private volatile long mPacketsReceived;
+ private FileDescriptor mFd;
+ private long mPacketsReceived;
- // Make it slightly easier for subclasses to properly close a socket
- // without having to know this incantation.
- public static final void closeSocket(@Nullable FileDescriptor fd) {
- try {
- IoBridge.closeAndSignalBlockedThreads(fd);
- } catch (IOException ignored) {}
+ protected static void closeFd(FileDescriptor fd) {
+ IoUtils.closeQuietly(fd);
}
- protected BlockingSocketReader() {
- this(DEFAULT_RECV_BUF_SIZE);
+ protected BlockingSocketReader(Handler h) {
+ this(h, DEFAULT_RECV_BUF_SIZE);
}
- protected BlockingSocketReader(int recvbufsize) {
- if (recvbufsize < DEFAULT_RECV_BUF_SIZE) {
- recvbufsize = DEFAULT_RECV_BUF_SIZE;
+ protected BlockingSocketReader(Handler h, int recvbufsize) {
+ mHandler = h;
+ mQueue = mHandler.getLooper().getQueue();
+ mPacket = new byte[Math.max(recvbufsize, DEFAULT_RECV_BUF_SIZE)];
+ }
+
+ public final void start() {
+ if (onCorrectThread()) {
+ createAndRegisterFd();
+ } else {
+ mHandler.post(() -> {
+ logError("start() called from off-thread", null);
+ createAndRegisterFd();
+ });
}
- mPacket = new byte[recvbufsize];
- mThread = new Thread(() -> { mainLoop(); });
- }
-
- public final boolean start() {
- if (mSocket != null) return false;
-
- try {
- mSocket = createSocket();
- } catch (Exception e) {
- logError("Failed to create socket: ", e);
- return false;
- }
-
- if (mSocket == null) return false;
-
- mRunning = true;
- mThread.start();
- return true;
}
public final void stop() {
- mRunning = false;
- closeSocket(mSocket);
- mSocket = null;
+ if (onCorrectThread()) {
+ unregisterAndDestroyFd();
+ } else {
+ mHandler.post(() -> {
+ logError("stop() called from off-thread", null);
+ unregisterAndDestroyFd();
+ });
+ }
}
- public final boolean isRunning() { return mRunning; }
+ public final int recvBufSize() { return mPacket.length; }
public final long numPacketsReceived() { return mPacketsReceived; }
@@ -98,11 +123,21 @@
* Subclasses MUST create the listening socket here, including setting
* all desired socket options, interface or address/port binding, etc.
*/
- protected abstract FileDescriptor createSocket();
+ protected abstract FileDescriptor createFd();
+
+ /**
+ * Subclasses MAY override this to change the default read() implementation
+ * in favour of, say, recvfrom().
+ *
+ * Implementations MUST return the bytes read or throw an Exception.
+ */
+ protected int readPacket(FileDescriptor fd, byte[] packetBuffer) throws Exception {
+ return Os.read(fd, packetBuffer, 0, packetBuffer.length);
+ }
/**
* Called by the main loop for every packet. Any desired copies of
- * |recvbuf| should be made in here, and the underlying byte array is
+ * |recvbuf| should be made in here, as the underlying byte array is
* reused across all reads.
*/
protected void handlePacket(byte[] recvbuf, int length) {}
@@ -113,43 +148,102 @@
protected void logError(String msg, Exception e) {}
/**
- * Called by the main loop just prior to exiting.
+ * Called by start(), if successful, just prior to returning.
*/
- protected void onExit() {}
+ protected void onStart() {}
- private final void mainLoop() {
+ /**
+ * Called by stop() just prior to returning.
+ */
+ protected void onStop() {}
+
+ private void createAndRegisterFd() {
+ if (mFd != null) return;
+
+ try {
+ mFd = createFd();
+ if (mFd != null) {
+ // Force the socket to be non-blocking.
+ IoUtils.setBlocking(mFd, false);
+ }
+ } catch (Exception e) {
+ logError("Failed to create socket: ", e);
+ closeFd(mFd);
+ mFd = null;
+ return;
+ }
+
+ if (mFd == null) return;
+
+ mQueue.addOnFileDescriptorEventListener(
+ mFd,
+ FD_EVENTS,
+ new OnFileDescriptorEventListener() {
+ @Override
+ public int onFileDescriptorEvents(FileDescriptor fd, int events) {
+ // Always call handleInput() so read/recvfrom are given
+ // a proper chance to encounter a meaningful errno and
+ // perhaps log a useful error message.
+ if (!isRunning() || !handleInput()) {
+ unregisterAndDestroyFd();
+ return UNREGISTER_THIS_FD;
+ }
+ return FD_EVENTS;
+ }
+ });
+ onStart();
+ }
+
+ private boolean isRunning() { return (mFd != null) && mFd.valid(); }
+
+ // Keep trying to read until we get EAGAIN/EWOULDBLOCK or some fatal error.
+ private boolean handleInput() {
while (isRunning()) {
final int bytesRead;
try {
- // Blocking read.
- // TODO: See if this can be converted to recvfrom.
- bytesRead = Os.read(mSocket, mPacket, 0, mPacket.length);
+ bytesRead = readPacket(mFd, mPacket);
if (bytesRead < 1) {
if (isRunning()) logError("Socket closed, exiting", null);
break;
}
mPacketsReceived++;
} catch (ErrnoException e) {
- if (e.errno != OsConstants.EINTR) {
- if (isRunning()) logError("read error: ", e);
+ if (e.errno == OsConstants.EAGAIN) {
+ // We've read everything there is to read this time around.
+ return true;
+ } else if (e.errno == OsConstants.EINTR) {
+ continue;
+ } else {
+ if (isRunning()) logError("readPacket error: ", e);
break;
}
- continue;
- } catch (IOException ioe) {
- if (isRunning()) logError("read error: ", ioe);
- continue;
+ } catch (Exception e) {
+ if (isRunning()) logError("readPacket error: ", e);
+ break;
}
try {
handlePacket(mPacket, bytesRead);
} catch (Exception e) {
- logError("Unexpected exception: ", e);
+ logError("handlePacket error: ", e);
break;
}
}
- stop();
- onExit();
+ return false;
+ }
+
+ private void unregisterAndDestroyFd() {
+ if (mFd == null) return;
+
+ mQueue.removeOnFileDescriptorEventListener(mFd);
+ closeFd(mFd);
+ mFd = null;
+ onStop();
+ }
+
+ private boolean onCorrectThread() {
+ return (mHandler.getLooper() == Looper.myLooper());
}
}
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 529ac3a..9fa1d68 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -558,6 +558,7 @@
// the phone is quiet
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
mService.buzzBeepBlinkLocked(r);
@@ -568,6 +569,22 @@
}
@Test
+ public void testNoDemoteSoundToVibrateIfNonNotificationStream() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ assertTrue(r.getSound() != null);
+ assertNull(r.getVibration());
+
+ // the phone is quiet
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(1);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverVibrate();
+ verifyBeepLooped();
+ }
+
+ @Test
public void testDemoteSoundToVibrate() throws Exception {
NotificationRecord r = getBeepyNotification();
assertTrue(r.getSound() != null);
@@ -575,6 +592,7 @@
// the phone is quiet
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
mService.buzzBeepBlinkLocked(r);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index 526f815..679be1d 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -16,9 +16,15 @@
package com.android.server.am;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManagerPolicy.NAV_BAR_BOTTOM;
import static android.view.WindowManagerPolicy.NAV_BAR_LEFT;
import static android.view.WindowManagerPolicy.NAV_BAR_RIGHT;
+import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@@ -26,14 +32,13 @@
import static org.mockito.Mockito.when;
import android.content.ComponentName;
-import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.Display;
import org.junit.runner.RunWith;
+import org.junit.Before;
import org.junit.Test;
/**
@@ -46,64 +51,53 @@
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ActivityRecordTests extends ActivityTestsBase {
- private static final int TEST_STACK_ID = 100;
-
private final ComponentName testActivityComponent =
ComponentName.unflattenFromString("com.foo/.BarActivity");
private final ComponentName secondaryActivityComponent =
ComponentName.unflattenFromString("com.foo/.BarActivity2");
+
+ private ActivityManagerService mService;
+ private ActivityStack mStack;
+ private TaskRecord mTask;
+ private ActivityRecord mActivity;
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mService = createActivityManagerService();
+ mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ mTask = createTask(mService.mStackSupervisor, testActivityComponent, mStack);
+ mActivity = createActivity(mService, testActivityComponent, mTask);
+ }
+
@Test
public void testStackCleanupOnClearingTask() throws Exception {
- final ActivityManagerService service = createActivityManagerService();
- final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID);
- final ActivityRecord record = createActivity(service, testActivityComponent, task);
-
- record.setTask(null);
- assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 1);
+ mActivity.setTask(null);
+ assertEquals(getActivityRemovedFromStackCount(), 1);
}
@Test
public void testStackCleanupOnActivityRemoval() throws Exception {
- final ActivityManagerService service = createActivityManagerService();
- final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID);
- final ActivityRecord record = createActivity(service, testActivityComponent, task);
-
- task.removeActivity(record);
- assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 1);
+ mTask.removeActivity(mActivity);
+ assertEquals(getActivityRemovedFromStackCount(), 1);
}
@Test
public void testStackCleanupOnTaskRemoval() throws Exception {
- final ActivityManagerService service = createActivityManagerService();
- final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID);
- final ActivityRecord record = createActivity(service, testActivityComponent, task);
-
- service.mStackSupervisor.getStack(TEST_STACK_ID)
- .removeTask(task, null /*reason*/, ActivityStack.REMOVE_TASK_MODE_MOVING);
-
+ mStack.removeTask(mTask, null /*reason*/, REMOVE_TASK_MODE_MOVING);
// Stack should be gone on task removal.
- assertNull(service.mStackSupervisor.getStack(TEST_STACK_ID));
+ assertNull(mService.mStackSupervisor.getStack(mStack.mStackId));
}
@Test
public void testNoCleanupMovingActivityInSameStack() throws Exception {
- final ActivityManagerService service = createActivityManagerService();
- final TaskRecord oldTask = createTask(service, testActivityComponent, TEST_STACK_ID);
- final ActivityRecord record = createActivity(service, testActivityComponent, oldTask);
- final TaskRecord newTask = createTask(service, testActivityComponent, TEST_STACK_ID);
-
- record.reparent(newTask, 0, null /*reason*/);
- assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 0);
- }
-
- private static int getActivityRemovedFromStackCount(ActivityManagerService service,
- int stackId) {
- final ActivityStack stack = service.mStackSupervisor.getStack(stackId);
- if (stack instanceof ActivityStackReporter) {
- return ((ActivityStackReporter) stack).onActivityRemovedFromStackInvocationCount();
- }
-
- return -1;
+ final TaskRecord newTask =
+ createTask(mService.mStackSupervisor, testActivityComponent, mStack);
+ mActivity.reparent(newTask, 0, null /*reason*/);
+ assertEquals(getActivityRemovedFromStackCount(), 0);
}
@Test
@@ -126,16 +120,21 @@
private void verifyPositionWithLimitedAspectRatio(int navBarPosition, Rect taskBounds,
float aspectRatio, Rect expectedActivityBounds) {
- final ActivityManagerService service = createActivityManagerService();
- final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID);
- final ActivityRecord record = createActivity(service, testActivityComponent, task);
-
// Verify with nav bar on the right.
- when(service.mWindowManager.getNavBarPosition()).thenReturn(navBarPosition);
- task.getConfiguration().windowConfiguration.setAppBounds(taskBounds);
- record.info.maxAspectRatio = aspectRatio;
- record.ensureActivityConfigurationLocked(0 /* globalChanges */, false /* preserveWindow */);
- assertEquals(expectedActivityBounds, record.getBounds());
+ when(mService.mWindowManager.getNavBarPosition()).thenReturn(navBarPosition);
+ mTask.getConfiguration().windowConfiguration.setAppBounds(taskBounds);
+ mActivity.info.maxAspectRatio = aspectRatio;
+ mActivity.ensureActivityConfigurationLocked(
+ 0 /* globalChanges */, false /* preserveWindow */);
+ assertEquals(expectedActivityBounds, mActivity.getBounds());
+ }
+
+ private int getActivityRemovedFromStackCount() {
+ if (mStack instanceof ActivityStackReporter) {
+ return ((ActivityStackReporter) mStack).onActivityRemovedFromStackInvocationCount();
+ }
+
+ return -1;
}
@@ -156,26 +155,22 @@
private void testSupportsLaunchingResizeable(boolean taskPresent, boolean taskResizeable,
boolean activityResizeable, boolean expected) {
- final ActivityManagerService service = createActivityManagerService();
- service.mSupportsMultiWindow = true;
-
+ mService.mSupportsMultiWindow = true;
final TaskRecord task = taskPresent
- ? createTask(service, testActivityComponent, TEST_STACK_ID) : null;
+ ? createTask(mService.mStackSupervisor, testActivityComponent, mStack) : null;
if (task != null) {
- task.setResizeMode(taskResizeable ? ActivityInfo.RESIZE_MODE_RESIZEABLE
- : ActivityInfo.RESIZE_MODE_UNRESIZEABLE);
+ task.setResizeMode(taskResizeable ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE);
}
- final ActivityRecord record = createActivity(service, secondaryActivityComponent,
- task);
- record.info.resizeMode = activityResizeable ? ActivityInfo.RESIZE_MODE_RESIZEABLE
- : ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+ final ActivityRecord record = createActivity(mService, secondaryActivityComponent, task);
+ record.info.resizeMode = activityResizeable
+ ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE;
- record.canBeLaunchedOnDisplay(Display.DEFAULT_DISPLAY);
+ record.canBeLaunchedOnDisplay(DEFAULT_DISPLAY);
- assertEquals(((TestActivityStackSupervisor) service.mStackSupervisor)
+ assertEquals(((TestActivityStackSupervisor) mService.mStackSupervisor)
.getLastResizeableFromCanPlaceEntityOnDisplay(), expected);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index cd1843b..6b93d0e 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -16,11 +16,10 @@
package com.android.server.am;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -33,6 +32,7 @@
import android.support.test.runner.AndroidJUnit4;
import org.junit.runner.RunWith;
+import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
@@ -54,6 +54,21 @@
private final ComponentName testActivityComponent =
ComponentName.unflattenFromString("com.foo/.BarActivity");
+ private ActivityManagerService mService;
+ private ActivityStackSupervisor mSupervisor;
+ private ActivityStack mFullscreenStack;
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mService = createActivityManagerService();
+ mSupervisor = mService.mStackSupervisor;
+ mFullscreenStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ }
+
/**
* This test ensures that we do not try to restore a task based off an invalid task id. The
* stack supervisor is a test version so there will be no tasks present. We should expect
@@ -61,8 +76,7 @@
*/
@Test
public void testRestoringInvalidTask() throws Exception {
- final ActivityManagerService service = createActivityManagerService();
- TaskRecord task = service.mStackSupervisor.anyTaskForIdLocked(0 /*taskId*/,
+ TaskRecord task = mSupervisor.anyTaskForIdLocked(0 /*taskId*/,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null);
assertNull(task);
}
@@ -73,43 +87,44 @@
*/
@Test
public void testReplacingTaskInPinnedStack() throws Exception {
- final ActivityManagerService service = createActivityManagerService();
- final TaskRecord firstTask = createTask(service, testActivityComponent,
- FULLSCREEN_WORKSPACE_STACK_ID);
- final ActivityRecord firstActivity = createActivity(service, testActivityComponent,
+ final TaskRecord firstTask = createTask(
+ mSupervisor, testActivityComponent, mFullscreenStack);
+ final ActivityRecord firstActivity = createActivity(mService, testActivityComponent,
firstTask);
// Create a new task on the full screen stack
- final TaskRecord secondTask = createTask(service, testActivityComponent,
- FULLSCREEN_WORKSPACE_STACK_ID);
- final ActivityRecord secondActivity = createActivity(service, testActivityComponent,
+ final TaskRecord secondTask = createTask(
+ mSupervisor, testActivityComponent, mFullscreenStack);
+ final ActivityRecord secondActivity = createActivity(mService, testActivityComponent,
secondTask);
- service.mStackSupervisor.setFocusStackUnchecked("testReplacingTaskInPinnedStack",
- service.mStackSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID));
+ mSupervisor.setFocusStackUnchecked("testReplacingTaskInPinnedStack", mFullscreenStack);
// Ensure full screen stack has both tasks.
- ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, firstTask,
- secondTask);
+ ensureStackPlacement(mFullscreenStack, firstTask, secondTask);
// Move first activity to pinned stack.
- service.mStackSupervisor.moveActivityToPinnedStackLocked(firstActivity,
- new Rect() /*sourceBounds*/, 0f /*aspectRatio*/, false, "initialMove");
+ final Rect sourceBounds = new Rect();
+ mSupervisor.moveActivityToPinnedStackLocked(firstActivity, sourceBounds,
+ 0f /*aspectRatio*/, false, "initialMove");
+ final ActivityDisplay display = mFullscreenStack.getDisplay();
+ ActivityStack pinnedStack = display.getPinnedStack();
// Ensure a task has moved over.
- ensureStackPlacement(service.mStackSupervisor, PINNED_STACK_ID, firstTask);
- ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, secondTask);
+ ensureStackPlacement(pinnedStack, firstTask);
+ ensureStackPlacement(mFullscreenStack, secondTask);
// Move second activity to pinned stack.
- service.mStackSupervisor.moveActivityToPinnedStackLocked(secondActivity,
- new Rect() /*sourceBounds*/, 0f /*aspectRatio*/ /*destBounds*/, false, "secondMove");
+ mSupervisor.moveActivityToPinnedStackLocked(secondActivity, sourceBounds,
+ 0f /*aspectRatio*/, false, "secondMove");
+
+ // Need to get pinned stack again as a new instance might have been created.
+ pinnedStack = display.getPinnedStack();
// Ensure stacks have swapped tasks.
- ensureStackPlacement(service.mStackSupervisor, PINNED_STACK_ID, secondTask);
- ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, firstTask);
+ ensureStackPlacement(pinnedStack, secondTask);
+ ensureStackPlacement(mFullscreenStack, firstTask);
}
- private static void ensureStackPlacement(ActivityStackSupervisor supervisor, int stackId,
- TaskRecord... tasks) {
- final ActivityStack stack = supervisor.getStack(stackId);
+ private static void ensureStackPlacement(ActivityStack stack, TaskRecord... tasks) {
final ArrayList<TaskRecord> stackTasks = stack.getAllTasks();
assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0);
@@ -127,15 +142,14 @@
*/
@Test
public void testStoppingActivityRemovedWhenResumed() throws Exception {
- final ActivityManagerService service = createActivityManagerService();
- final TaskRecord firstTask = createTask(service, testActivityComponent,
- FULLSCREEN_WORKSPACE_STACK_ID);
- final ActivityRecord firstActivity = createActivity(service, testActivityComponent,
+ final TaskRecord firstTask = createTask(
+ mSupervisor, testActivityComponent, mFullscreenStack);
+ final ActivityRecord firstActivity = createActivity(mService, testActivityComponent,
firstTask);
- service.mStackSupervisor.mStoppingActivities.add(firstActivity);
+ mSupervisor.mStoppingActivities.add(firstActivity);
firstActivity.completeResumeLocked();
- assertFalse(service.mStackSupervisor.mStoppingActivities.contains(firstActivity));
+ assertFalse(mSupervisor.mStoppingActivities.contains(firstActivity));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 02fba08..4ee1f47 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -16,12 +16,14 @@
package com.android.server.am;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.os.UserHandle;
@@ -30,6 +32,7 @@
import android.support.test.runner.AndroidJUnit4;
import org.junit.runner.RunWith;
+import org.junit.Before;
import org.junit.Test;
/**
@@ -48,78 +51,80 @@
private static final ComponentName testOverlayComponent =
ComponentName.unflattenFromString("com.foo/.OverlayActivity");
+ private ActivityManagerService mService;
+ private ActivityStackSupervisor mSupervisor;
+ private ActivityStack mStack;
+ private TaskRecord mTask;
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mService = createActivityManagerService();
+ mSupervisor = mService.mStackSupervisor;
+ mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ mTask = createTask(mSupervisor, testActivityComponent, mStack);
+ }
+
@Test
public void testEmptyTaskCleanupOnRemove() throws Exception {
- final ActivityManagerService service = createActivityManagerService();
- final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID);
- assertNotNull(task.getWindowContainerController());
- service.mStackSupervisor.getStack(TEST_STACK_ID).removeTask(task,
- "testEmptyTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING);
- assertNull(task.getWindowContainerController());
+ assertNotNull(mTask.getWindowContainerController());
+ mStack.removeTask(mTask, "testEmptyTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING);
+ assertNull(mTask.getWindowContainerController());
}
@Test
public void testOccupiedTaskCleanupOnRemove() throws Exception {
- final ActivityManagerService service = createActivityManagerService();
- final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID);
- final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task);
- assertNotNull(task.getWindowContainerController());
- service.mStackSupervisor.getStack(TEST_STACK_ID).removeTask(task,
- "testOccupiedTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING);
- assertNotNull(task.getWindowContainerController());
+ final ActivityRecord r = createActivity(mService, testActivityComponent, mTask);
+ assertNotNull(mTask.getWindowContainerController());
+ mStack.removeTask(mTask, "testOccupiedTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING);
+ assertNotNull(mTask.getWindowContainerController());
}
@Test
public void testNoPauseDuringResumeTopActivity() throws Exception {
- final ActivityManagerService service = createActivityManagerService();
- final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID);
- final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task);
- final ActivityStack testStack = service.mStackSupervisor.getStack(TEST_STACK_ID);
+ final ActivityRecord r = createActivity(mService, testActivityComponent, mTask);
// Simulate the a resumed activity set during
// {@link ActivityStack#resumeTopActivityUncheckedLocked}.
- service.mStackSupervisor.inResumeTopActivity = true;
- testStack.mResumedActivity = activityRecord;
+ mSupervisor.inResumeTopActivity = true;
+ mStack.mResumedActivity = r;
- final boolean waiting = testStack.goToSleepIfPossible(false);
+ final boolean waiting = mStack.goToSleepIfPossible(false);
// Ensure we report not being ready for sleep.
assertFalse(waiting);
// Make sure the resumed activity is untouched.
- assertEquals(testStack.mResumedActivity, activityRecord);
+ assertEquals(mStack.mResumedActivity, r);
}
@Test
public void testStopActivityWhenActivityDestroyed() throws Exception {
- final ActivityManagerService service = createActivityManagerService();
- final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID);
- final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task);
- activityRecord.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
- final ActivityStack testStack = service.mStackSupervisor.getStack(TEST_STACK_ID);
- service.mStackSupervisor.setFocusStackUnchecked("testStopActivityWithDestroy", testStack);
-
- testStack.stopActivityLocked(activityRecord);
+ final ActivityRecord r = createActivity(mService, testActivityComponent, mTask);
+ r.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
+ mSupervisor.setFocusStackUnchecked("testStopActivityWithDestroy", mStack);
+ mStack.stopActivityLocked(r);
+ // Mostly testing to make sure there is a crash in the call part, so if we get here we are
+ // good-to-go!
}
@Test
public void testFindTaskWithOverlay() throws Exception {
- final ActivityManagerService service = createActivityManagerService();
- final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID);
- final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task,
- 0);
+ final ActivityRecord r = createActivity(mService, testActivityComponent, mTask, 0);
// Overlay must be for a different user to prevent recognizing a matching top activity
- final ActivityRecord taskOverlay = createActivity(service, testOverlayComponent, task,
+ final ActivityRecord taskOverlay = createActivity(mService, testOverlayComponent, mTask,
UserHandle.PER_USER_RANGE * 2);
taskOverlay.mTaskOverlay = true;
- final ActivityStack testStack = service.mStackSupervisor.getStack(TEST_STACK_ID);
final ActivityStackSupervisor.FindTaskResult result =
new ActivityStackSupervisor.FindTaskResult();
- testStack.findTaskLocked(activityRecord, result);
+ mStack.findTaskLocked(r, result);
- assertEquals(task.getTopActivity(false /* includeOverlays */), activityRecord);
- assertEquals(task.getTopActivity(true /* includeOverlays */), taskOverlay);
+ assertEquals(mTask.getTopActivity(false /* includeOverlays */), r);
+ assertEquals(mTask.getTopActivity(true /* includeOverlays */), taskOverlay);
assertNotNull(result.r);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 6caa60b..b4bfa62 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -16,7 +16,7 @@
package com.android.server.am;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.Display.DEFAULT_DISPLAY;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.doReturn;
@@ -76,16 +76,6 @@
return service;
}
- protected static ActivityStack createActivityStack(ActivityManagerService service,
- int stackId, int displayId, boolean onTop) {
- if (service.mStackSupervisor instanceof TestActivityStackSupervisor) {
- return ((TestActivityStackSupervisor) service.mStackSupervisor)
- .createTestStack(stackId, onTop);
- }
-
- return null;
- }
-
protected static ActivityRecord createActivity(ActivityManagerService service,
ComponentName component, TaskRecord task) {
return createActivity(service, component, task, 0 /* userId */);
@@ -114,8 +104,8 @@
return activity;
}
- protected static TaskRecord createTask(ActivityManagerService service,
- ComponentName component, int stackId) {
+ protected static TaskRecord createTask(ActivityStackSupervisor supervisor,
+ ComponentName component, ActivityStack stack) {
final ActivityInfo aInfo = new ActivityInfo();
aInfo.applicationInfo = new ApplicationInfo();
aInfo.applicationInfo.packageName = component.getPackageName();
@@ -123,11 +113,9 @@
Intent intent = new Intent();
intent.setComponent(component);
- final TaskRecord task = new TaskRecord(service, 0, aInfo, intent /*intent*/,
+ final TaskRecord task = new TaskRecord(supervisor.mService, 0, aInfo, intent /*intent*/,
null /*_taskDescription*/);
- final ActivityStack stack = service.mStackSupervisor.getStack(stackId,
- true /*createStaticStackIfNeeded*/, true /*onTop*/);
- service.mStackSupervisor.setFocusStackUnchecked("test", stack);
+ supervisor.setFocusStackUnchecked("test", stack);
stack.addTask(task, true, "creating test task");
task.setStack(stack);
task.setWindowContainerController(mock(TaskWindowContainerController.class));
@@ -135,16 +123,18 @@
return task;
}
-
/**
* An {@link ActivityManagerService} subclass which provides a test
* {@link ActivityStackSupervisor}.
*/
protected static class TestActivityManagerService extends ActivityManagerService {
- public TestActivityManagerService(Context context) {
+ TestActivityManagerService(Context context) {
super(context);
mSupportsMultiWindow = true;
mSupportsMultiDisplay = true;
+ mSupportsSplitScreenMultiWindow = true;
+ mSupportsFreeformWindowManagement = true;
+ mSupportsPictureInPicture = true;
mWindowManager = WindowTestUtils.getWindowManagerService(context);
}
@@ -171,10 +161,15 @@
mDisplayManager =
(DisplayManager) mService.mContext.getSystemService(Context.DISPLAY_SERVICE);
mWindowManager = prepareMockWindowManager();
- mDisplay = new ActivityDisplay(this, DEFAULT_DISPLAY);
+ mDisplay = new TestActivityDisplay(this, DEFAULT_DISPLAY);
attachDisplay(mDisplay);
}
+ @Override
+ ActivityDisplay getDefaultDisplay() {
+ return mDisplay;
+ }
+
// TODO: Use Mockito spy instead. Currently not possible due to TestActivityStackSupervisor
// access to ActivityDisplay
@Override
@@ -218,41 +213,36 @@
boolean preserveWindows) {
}
- <T extends ActivityStack> T createTestStack(int stackId, boolean onTop) {
- return (T) createStack(stackId, mDisplay, onTop);
+ // Always keep things awake
+ @Override
+ boolean hasAwakeDisplay() {
+ return true;
+ }
+ }
+
+ private static class TestActivityDisplay extends ActivityDisplay {
+
+ private final ActivityStackSupervisor mSupervisor;
+ TestActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
+ super(supervisor, displayId);
+ mSupervisor = supervisor;
}
@Override
- ActivityStack createStack(int stackId, ActivityDisplay display, boolean onTop) {
- if (stackId == PINNED_STACK_ID) {
- return new PinnedActivityStack(display, stackId, this, onTop) {
+ <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
+ int stackId, boolean onTop) {
+ if (windowingMode == WINDOWING_MODE_PINNED) {
+ return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop) {
@Override
Rect getDefaultPictureInPictureBounds(float aspectRatio) {
return new Rect(50, 50, 100, 100);
}
};
} else {
- return new TestActivityStack(display, stackId, this, onTop);
+ return (T) new TestActivityStack(
+ this, stackId, mSupervisor, windowingMode, activityType, onTop);
}
}
-
- @Override
- protected <T extends ActivityStack> T getStack(int stackId,
- boolean createStaticStackIfNeeded, boolean createOnTop) {
- final T stack = super.getStack(stackId, createStaticStackIfNeeded, createOnTop);
-
- if (stack != null || !createStaticStackIfNeeded) {
- return stack;
- }
-
- return createTestStack(stackId, createOnTop);
- }
-
- // Always keep things awake
- @Override
- boolean hasAwakeDisplay() {
- return true;
- }
}
private static WindowManagerService prepareMockWindowManager() {
@@ -282,9 +272,10 @@
extends ActivityStack<T> implements ActivityStackReporter {
private int mOnActivityRemovedFromStackCount = 0;
private T mContainerController;
+
TestActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
- boolean onTop) {
- super(display, stackId, supervisor, onTop);
+ int windowingMode, int activityType, boolean onTop) {
+ super(display, stackId, supervisor, windowingMode, activityType, onTop);
}
@Override
@@ -310,36 +301,4 @@
return mContainerController;
}
}
-
-
- protected static class ActivityStackBuilder {
- private boolean mOnTop = true;
- private int mStackId = 0;
- private int mDisplayId = 1;
-
- private final ActivityManagerService mService;
-
- public ActivityStackBuilder(ActivityManagerService ams) {
- mService = ams;
- }
-
- public ActivityStackBuilder setOnTop(boolean onTop) {
- mOnTop = onTop;
- return this;
- }
-
- public ActivityStackBuilder setStackId(int id) {
- mStackId = id;
- return this;
- }
-
- public ActivityStackBuilder setDisplayId(int id) {
- mDisplayId = id;
- return this;
- }
-
- public ActivityStack build() {
- return createActivityStack(mService, mStackId, mDisplayId, mOnTop);
- }
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 419a161..d6d0209 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -30,6 +30,7 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.UserManagerInternal;
+import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
@@ -59,14 +60,20 @@
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+/**
+ * Usage: bit FrameworksServicesTests:com.android.server.am.UserControllerTest
+ */
+@Presubmit
public class UserControllerTest extends AndroidTestCase {
private static final int TEST_USER_ID = 10;
private static final int NONEXIST_USER_ID = 2;
@@ -96,8 +103,11 @@
@Override
public void setUp() throws Exception {
super.setUp();
- System.setProperty("dexmaker.share_classloader", "true");
- mInjector = new TestInjector(getContext());
+ mInjector = Mockito.spy(new TestInjector(getContext()));
+ doNothing().when(mInjector).clearLockTaskMode(anyString());
+ doNothing().when(mInjector).startHomeActivity(anyInt(), anyString());
+ doReturn(false).when(mInjector).stackSupervisorSwitchUser(anyInt(), any());
+ doNothing().when(mInjector).stackSupervisorResumeFocusedStackTopActivity();
mUserController = new UserController(mInjector);
setUpUser(TEST_USER_ID, 0);
}
@@ -106,6 +116,7 @@
protected void tearDown() throws Exception {
super.tearDown();
mInjector.handlerThread.quit();
+ Mockito.validateMockitoUsage();
}
@SmallTest
@@ -115,7 +126,7 @@
Mockito.verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
Mockito.verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(anyBoolean());
Mockito.verify(mInjector.getWindowManager()).setSwitchingUser(true);
- Mockito.verify(mInjector.getLockTaskController()).clearLockTaskMode(anyString());
+ Mockito.verify(mInjector).clearLockTaskMode(anyString());
startForegroundUserAssertions();
}
@@ -125,7 +136,7 @@
Mockito.verify(
mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
Mockito.verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
- verifyZeroInteractions(mInjector.getLockTaskController());
+ Mockito.verify(mInjector, never()).clearLockTaskMode(anyString());
startBackgroundUserAssertions();
}
@@ -306,16 +317,14 @@
return result;
}
- private static class TestInjector extends UserController.Injector {
- final Object lock = new Object();
+ // Should be public to allow mocking
+ public static class TestInjector extends UserController.Injector {
TestHandler handler;
TestHandler uiHandler;
HandlerThread handlerThread;
UserManagerService userManagerMock;
UserManagerInternal userManagerInternalMock;
WindowManagerService windowManagerMock;
- ActivityStackSupervisor activityStackSupervisor;
- LockTaskController lockTaskController;
private Context mCtx;
List<Intent> sentIntents = new ArrayList<>();
@@ -329,13 +338,6 @@
userManagerMock = mock(UserManagerService.class);
userManagerInternalMock = mock(UserManagerInternal.class);
windowManagerMock = mock(WindowManagerService.class);
- activityStackSupervisor = mock(ActivityStackSupervisor.class);
- lockTaskController = mock(LockTaskController.class);
- }
-
- @Override
- protected Object getLock() {
- return lock;
}
@Override
@@ -375,12 +377,12 @@
}
@Override
- void updateUserConfigurationLocked() {
- Log.i(TAG, "updateUserConfigurationLocked");
+ void updateUserConfiguration() {
+ Log.i(TAG, "updateUserConfiguration");
}
@Override
- protected int broadcastIntentLocked(Intent intent, String resolvedType,
+ protected int broadcastIntent(Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered,
boolean sticky, int callingPid, int callingUid, int userId) {
@@ -388,20 +390,6 @@
sentIntents.add(intent);
return 0;
}
-
- @Override
- void startHomeActivityLocked(int userId, String reason) {
- Log.i(TAG, "startHomeActivityLocked " + userId);
- }
-
- @Override
- ActivityStackSupervisor getActivityStackSupervisor() {
- return activityStackSupervisor;
- }
-
- LockTaskController getLockTaskController() {
- return lockTaskController;
- }
}
private static class TestHandler extends Handler {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index 13cf9df..7cba280 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -106,7 +106,8 @@
return mService;
}
};
- mSpManager = new MockSyntheticPasswordManager(mStorage, mGateKeeperService, mUserManager);
+ mSpManager = new MockSyntheticPasswordManager(mContext, mStorage, mGateKeeperService,
+ mUserManager);
mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils, mStorage,
mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager,
mSpManager);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
index cf03593..6f68179 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
@@ -15,6 +15,7 @@
*/
package com.android.server.locksettings;
+import android.content.Context;
import android.hardware.weaver.V1_0.IWeaver;
import android.os.RemoteException;
import android.os.UserManager;
@@ -35,9 +36,9 @@
private FakeGateKeeperService mGateKeeper;
private IWeaver mWeaverService;
- public MockSyntheticPasswordManager(LockSettingsStorage storage,
+ public MockSyntheticPasswordManager(Context context, LockSettingsStorage storage,
FakeGateKeeperService gatekeeper, UserManager userManager) {
- super(storage, userManager);
+ super(context, storage, userManager);
mGateKeeper = gatekeeper;
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 2c9aa9d..2ad0580 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -58,7 +58,7 @@
final int USER_ID = 10;
final String PASSWORD = "user-password";
final String BADPASSWORD = "bad-password";
- MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mStorage,
+ MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage,
mGateKeeperService, mUserManager);
AuthenticationToken authToken = manager.newSyntheticPasswordAndSid(mGateKeeperService, null,
null, USER_ID);
diff --git a/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java b/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
index 375edf3..b647b99 100644
--- a/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
@@ -149,11 +149,13 @@
assertThat(json.getLong(DiskStatsFileLogger.DOWNLOADS_KEY)).isEqualTo(3L);
assertThat(json.getLong(DiskStatsFileLogger.SYSTEM_KEY)).isEqualTo(10L);
assertThat(json.getLong(DiskStatsFileLogger.MISC_KEY)).isEqualTo(7L);
- assertThat(json.getLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY)).isEqualTo(15L);
+ assertThat(json.getLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY)).isEqualTo(10L);
+ assertThat(json.getLong(DiskStatsFileLogger.APP_DATA_SIZE_AGG_KEY)).isEqualTo(5L);
assertThat(json.getLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY)).isEqualTo(55L);
assertThat(
json.getJSONArray(DiskStatsFileLogger.PACKAGE_NAMES_KEY).length()).isEqualTo(1L);
assertThat(json.getJSONArray(DiskStatsFileLogger.APP_SIZES_KEY).length()).isEqualTo(1L);
+ assertThat(json.getJSONArray(DiskStatsFileLogger.APP_DATA_KEY).length()).isEqualTo(1L);
assertThat(json.getJSONArray(DiskStatsFileLogger.APP_CACHES_KEY).length()).isEqualTo(1L);
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index f732503..d362c3b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -16,7 +16,8 @@
package com.android.server.wm;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
@@ -347,17 +348,20 @@
*/
@Test
public void testPinnedStackLocation() {
- createStackControllerOnStackOnDisplay(PINNED_STACK_ID, mDisplayContent);
+ createStackControllerOnStackOnDisplay(
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
final int initialStackCount = mDisplayContent.getStackCount();
// Ensure that the pinned stack was placed at the end
- assertEquals(initialStackCount - 1, mDisplayContent.getStackPosById(PINNED_STACK_ID));
+ assertEquals(initialStackCount - 1,
+ mDisplayContent.getStackPosition(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD));
// By default, this should try to create a new stack on top
createTaskStackOnDisplay(mDisplayContent);
final int afterStackCount = mDisplayContent.getStackCount();
// Make sure the stack count has increased
assertEquals(initialStackCount + 1, afterStackCount);
// Ensure that the pinned stack is still on top
- assertEquals(afterStackCount - 1, mDisplayContent.getStackPosById(PINNED_STACK_ID));
+ assertEquals(afterStackCount - 1,
+ mDisplayContent.getStackPosition(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD));
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index 29bbe6e..536a504 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -29,7 +29,7 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import static android.app.ActivityManager.StackId.getWindowingModeForStackId;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -53,8 +53,7 @@
public void setUp() throws Exception {
super.setUp();
final Configuration overrideConfig = new Configuration();
- overrideConfig.windowConfiguration.setWindowingMode(
- getWindowingModeForStackId(PINNED_STACK_ID, false /* inSplitScreenMode */));
+ overrideConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED);
mPinnedStack = new StackWindowController(PINNED_STACK_ID, null,
mDisplayContent.getDisplayId(), true /* onTop */, new Rect(), sWm).mContainer;
mPinnedStack.onOverrideConfigurationChanged(overrideConfig);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
index 31aad79..e78224c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
@@ -26,10 +26,10 @@
import android.support.test.runner.AndroidJUnit4;
import android.view.DisplayInfo;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
import static android.app.WindowConfiguration.WINDOW_CONFIG_WINDOWING_MODE;
import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
@@ -155,7 +155,7 @@
shiftedBounds.offset(10, 10);
final Rect expectedBounds = new Rect(mParentBounds);
expectedBounds.intersect(shiftedBounds);
- testStackBoundsConfiguration(null /*stackId*/, mParentBounds, shiftedBounds,
+ testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, shiftedBounds,
expectedBounds);
}
@@ -163,7 +163,7 @@
@Test
public void testAppBounds_EmptyBounds() throws Exception {
final Rect emptyBounds = new Rect();
- testStackBoundsConfiguration(null /*stackId*/, mParentBounds, emptyBounds,
+ testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, emptyBounds,
null /*ExpectedBounds*/);
}
@@ -172,7 +172,7 @@
public void testAppBounds_FreeFormBounds() throws Exception {
final Rect freeFormBounds = new Rect(mParentBounds);
freeFormBounds.offset(10, 10);
- testStackBoundsConfiguration(FREEFORM_WORKSPACE_STACK_ID, mParentBounds, freeFormBounds,
+ testStackBoundsConfiguration(WINDOWING_MODE_FREEFORM, mParentBounds, freeFormBounds,
freeFormBounds);
}
@@ -181,7 +181,8 @@
public void testAppBounds_ContainedBounds() throws Exception {
final Rect insetBounds = new Rect(mParentBounds);
insetBounds.inset(5, 5, 5, 5);
- testStackBoundsConfiguration(null /*stackId*/, mParentBounds, insetBounds, insetBounds);
+ testStackBoundsConfiguration(
+ WINDOWING_MODE_FULLSCREEN, mParentBounds, insetBounds, insetBounds);
}
/** Ensures that full screen free form bounds are clipped */
@@ -189,15 +190,14 @@
public void testAppBounds_FullScreenFreeFormBounds() throws Exception {
final Rect fullScreenBounds = new Rect(0, 0, mDisplayInfo.logicalWidth,
mDisplayInfo.logicalHeight);
- testStackBoundsConfiguration(null /*stackId*/, mParentBounds, fullScreenBounds,
+ testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, fullScreenBounds,
mParentBounds);
}
- private void testStackBoundsConfiguration(Integer stackId, Rect parentBounds, Rect bounds,
+ private void testStackBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
Rect expectedConfigBounds) {
- final StackWindowController stackController = stackId != null ?
- createStackControllerOnStackOnDisplay(stackId, mDisplayContent)
- : createStackControllerOnDisplay(mDisplayContent);
+ final StackWindowController stackController = createStackControllerOnStackOnDisplay(
+ windowingMode, ACTIVITY_TYPE_STANDARD, mDisplayContent);
final Configuration parentConfig = mDisplayContent.getConfiguration();
parentConfig.windowConfiguration.setAppBounds(parentBounds);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
index e1f318d..3c3514f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
@@ -23,9 +23,11 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -160,12 +162,14 @@
@Test
public void testStackLayers() throws Exception {
- WindowState pinnedStackWindow = createWindowOnStack(null, PINNED_STACK_ID,
- TYPE_BASE_APPLICATION, mDisplayContent, "pinnedStackWindow");
- WindowState dockedStackWindow = createWindowOnStack(null, DOCKED_STACK_ID,
- TYPE_BASE_APPLICATION, mDisplayContent, "dockedStackWindow");
- WindowState assistantStackWindow = createWindowOnStack(null, ASSISTANT_STACK_ID,
- TYPE_BASE_APPLICATION, mDisplayContent, "assistantStackWindow");
+ WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
+ ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent, "pinnedStackWindow");
+ WindowState dockedStackWindow = createWindowOnStack(null,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
+ mDisplayContent, "dockedStackWindow");
+ WindowState assistantStackWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
+ mDisplayContent, "assistantStackWindow");
mLayersController.assignWindowLayers(mDisplayContent);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index 0315c8d..1aafac6 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -32,6 +32,7 @@
import static android.content.res.Configuration.EMPTY;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
/**
* A collection of static functions that can be referenced by other test packages to provide access
@@ -51,7 +52,10 @@
* Retrieves an instance of a mock {@link WindowManagerService}.
*/
public static WindowManagerService getMockWindowManagerService() {
- return mock(WindowManagerService.class);
+ final WindowManagerService service = mock(WindowManagerService.class);
+ final WindowHashMap windowMap = new WindowHashMap();
+ when(service.getWindowManagerLock()).thenReturn(windowMap);
+ return service;
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 3df13ab..4e810f2 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -16,7 +16,8 @@
package com.android.server.wm;
-import static android.app.ActivityManager.StackId.getWindowingModeForStackId;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.View.VISIBLE;
@@ -167,14 +168,14 @@
sWm.mAnimationHandler.runWithScissors(() -> { }, 0);
}
- private WindowToken createWindowToken(DisplayContent dc, int stackId, int type) {
+ private WindowToken createWindowToken(
+ DisplayContent dc, int windowingMode, int activityType, int type) {
if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
return new WindowTestUtils.TestWindowToken(type, dc);
}
- final TaskStack stack = stackId == INVALID_STACK_ID
- ? createTaskStackOnDisplay(dc)
- : createStackControllerOnStackOnDisplay(stackId, dc).mContainer;
+ final TaskStack stack =
+ createStackControllerOnStackOnDisplay(windowingMode, activityType, dc).mContainer;
final Task task = createTaskInStack(stack, 0 /* userId */);
final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(dc);
task.addChild(token, 0);
@@ -187,9 +188,9 @@
: createWindow(parent, type, parent.mToken, name);
}
- WindowState createWindowOnStack(WindowState parent, int stackId, int type,
- DisplayContent dc, String name) {
- final WindowToken token = createWindowToken(dc, stackId, type);
+ WindowState createWindowOnStack(WindowState parent, int windowingMode, int activityType,
+ int type, DisplayContent dc, String name) {
+ final WindowToken token = createWindowToken(dc, windowingMode, activityType, type);
return createWindow(parent, type, token, name);
}
@@ -200,13 +201,15 @@
}
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
- final WindowToken token = createWindowToken(dc, INVALID_STACK_ID, type);
+ final WindowToken token = createWindowToken(
+ dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
return createWindow(parent, type, token, name);
}
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
boolean ownerCanAddInternalSystemWindow) {
- final WindowToken token = createWindowToken(dc, INVALID_STACK_ID, type);
+ final WindowToken token = createWindowToken(
+ dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
return createWindow(parent, type, token, name, ownerCanAddInternalSystemWindow);
}
@@ -233,14 +236,16 @@
}
StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
- final int stackId = ++sNextStackId;
- return createStackControllerOnStackOnDisplay(stackId, dc);
+ return createStackControllerOnStackOnDisplay(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
}
- StackWindowController createStackControllerOnStackOnDisplay(int stackId, DisplayContent dc) {
+ StackWindowController createStackControllerOnStackOnDisplay(
+ int windowingMode, int activityType, DisplayContent dc) {
final Configuration overrideConfig = new Configuration();
- overrideConfig.windowConfiguration.setWindowingMode(
- getWindowingModeForStackId(stackId, false /* inSplitScreenMode */));
+ overrideConfig.windowConfiguration.setWindowingMode(windowingMode);
+ overrideConfig.windowConfiguration.setActivityType(activityType);
+ final int stackId = ++sNextStackId;
final StackWindowController controller = new StackWindowController(stackId, null,
dc.getDisplayId(), true /* onTop */, new Rect(), sWm);
controller.onOverrideConfigurationChanged(overrideConfig);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index cde0bdf..c0564c5 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -107,8 +107,6 @@
public static final String MODEM_ACTIVITY_RESULT_KEY =
BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY;
- private static ITelephonyRegistry sRegistry;
-
/**
* The allowed states of Wi-Fi calling.
*
@@ -179,11 +177,6 @@
mContext = context;
}
mSubscriptionManager = SubscriptionManager.from(mContext);
-
- if (sRegistry == null) {
- sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
- "telephony.registry"));
- }
}
/** @hide */
@@ -3513,6 +3506,10 @@
return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));
}
+ private ITelephonyRegistry getTelephonyRegistry() {
+ return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
+ }
+
//
//
// PhoneStateListener
@@ -3552,12 +3549,16 @@
if (listener.mSubId == null) {
listener.mSubId = mSubId;
}
- sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(),
- listener.callback, events, notifyNow);
+
+ ITelephonyRegistry registry = getTelephonyRegistry();
+ if (registry != null) {
+ registry.listenForSubscriber(listener.mSubId, getOpPackageName(),
+ listener.callback, events, notifyNow);
+ } else {
+ Rlog.w(TAG, "telephony registry not ready.");
+ }
} catch (RemoteException ex) {
// system process dead
- } catch (NullPointerException ex) {
- // system process dead
}
}
diff --git a/tests/Compatibility/Android.mk b/tests/Compatibility/Android.mk
index feeae02..82e2126 100644
--- a/tests/Compatibility/Android.mk
+++ b/tests/Compatibility/Android.mk
@@ -17,9 +17,7 @@
# We only want this apk build for tests.
LOCAL_MODULE_TAGS := tests
-
-LOCAL_JAVA_LIBRARIES := legacy-android-test
-LOCAL_STATIC_JAVA_LIBRARIES := junit
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
# Include all test java files.
LOCAL_SRC_FILES := \
$(call all-java-files-under, src)
diff --git a/tests/Compatibility/AndroidManifest.xml b/tests/Compatibility/AndroidManifest.xml
index 7017431..5d1317e 100644
--- a/tests/Compatibility/AndroidManifest.xml
+++ b/tests/Compatibility/AndroidManifest.xml
@@ -15,12 +15,12 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.compatibilitytest" >
+ package="com.android.compatibilitytest"
+ android:sharedUserId="android.uid.system">
<uses-sdk android:minSdkVersion="21"
android:targetSdkVersion="21" />
- <application >
- <uses-library android:name="android.test.runner" />
- </application>
+ <application />
+ <uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<instrumentation
android:name=".AppCompatibilityRunner"
diff --git a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
index f81b001..a5261d0 100644
--- a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
+++ b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
@@ -17,62 +17,91 @@
package com.android.compatibilitytest;
import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.IActivityController;
+import android.app.IActivityManager;
+import android.app.Instrumentation;
import android.app.UiAutomation;
import android.app.UiModeManager;
-import android.app.ActivityManager.ProcessErrorStateInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.os.Bundle;
-import android.test.InstrumentationTestCase;
+import android.os.DropBoxManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
-import junit.framework.Assert;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* Application Compatibility Test that launches an application and detects
* crashes.
*/
-public class AppCompatibility extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AppCompatibility {
private static final String TAG = AppCompatibility.class.getSimpleName();
private static final String PACKAGE_TO_LAUNCH = "package_to_launch";
private static final String APP_LAUNCH_TIMEOUT_MSECS = "app_launch_timeout_ms";
private static final String WORKSPACE_LAUNCH_TIMEOUT_MSECS = "workspace_launch_timeout_ms";
+ private static final Set<String> DROPBOX_TAGS = new HashSet<>();
+ static {
+ DROPBOX_TAGS.add("SYSTEM_TOMBSTONE");
+ DROPBOX_TAGS.add("system_app_anr");
+ DROPBOX_TAGS.add("system_app_native_crash");
+ DROPBOX_TAGS.add("system_app_crash");
+ DROPBOX_TAGS.add("data_app_anr");
+ DROPBOX_TAGS.add("data_app_native_crash");
+ DROPBOX_TAGS.add("data_app_crash");
+ }
+ // time waiting for app to launch
private int mAppLaunchTimeout = 7000;
+ // time waiting for launcher home screen to show up
private int mWorkspaceLaunchTimeout = 2000;
private Context mContext;
private ActivityManager mActivityManager;
private PackageManager mPackageManager;
- private AppCompatibilityRunner mRunner;
private Bundle mArgs;
+ private Instrumentation mInstrumentation;
+ private String mLauncherPackageName;
+ private IActivityController mCrashSupressor = new CrashSuppressor();
+ private Map<String, List<String>> mAppErrors = new HashMap<>();
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
- mRunner = (AppCompatibilityRunner) getInstrumentation();
- assertNotNull("Could not fetch InstrumentationTestRunner.", mRunner);
-
- mContext = mRunner.getTargetContext();
- Assert.assertNotNull("Could not get the Context", mContext);
-
- mActivityManager = (ActivityManager)
- mContext.getSystemService(Context.ACTIVITY_SERVICE);
- Assert.assertNotNull("Could not get Activity Manager", mActivityManager);
-
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mContext = InstrumentationRegistry.getTargetContext();
+ mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
mPackageManager = mContext.getPackageManager();
- Assert.assertNotNull("Missing Package Manager", mPackageManager);
+ mArgs = InstrumentationRegistry.getArguments();
- mArgs = mRunner.getBundle();
+ // resolve launcher package name
+ Intent intent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
+ ResolveInfo resolveInfo = mPackageManager.resolveActivity(
+ intent, PackageManager.MATCH_DEFAULT_ONLY);
+ mLauncherPackageName = resolveInfo.activityInfo.packageName;
+ Assert.assertNotNull("failed to resolve package name for launcher", mLauncherPackageName);
+ Log.v(TAG, "Using launcher package name: " + mLauncherPackageName);
// Parse optional inputs.
String appLaunchTimeoutMsecs = mArgs.getString(APP_LAUNCH_TIMEOUT_MSECS);
@@ -83,13 +112,20 @@
if (workspaceLaunchTimeoutMsecs != null) {
mWorkspaceLaunchTimeout = Integer.parseInt(workspaceLaunchTimeoutMsecs);
}
- getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
+ mInstrumentation.getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
+
+ // set activity controller to suppress crash dialogs and collects them by process name
+ mAppErrors.clear();
+ IActivityManager.Stub.asInterface(ServiceManager.checkService(Context.ACTIVITY_SERVICE))
+ .setActivityController(mCrashSupressor, false);
}
- @Override
- protected void tearDown() throws Exception {
- getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
- super.tearDown();
+ @After
+ public void tearDown() throws Exception {
+ // unset activity controller
+ IActivityManager.Stub.asInterface(ServiceManager.checkService(Context.ACTIVITY_SERVICE))
+ .setActivityController(null, false);
+ mInstrumentation.getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
}
/**
@@ -98,6 +134,7 @@
*
* @throws Exception
*/
+ @Test
public void testAppStability() throws Exception {
String packageName = mArgs.getString(PACKAGE_TO_LAUNCH);
if (packageName != null) {
@@ -107,13 +144,23 @@
Log.w(TAG, String.format("Skipping %s; no launch intent", packageName));
return;
}
- ProcessErrorStateInfo err = launchActivity(packageName, intent);
- // Make sure there are no errors when launching the application,
- // otherwise raise an
- // exception with the first error encountered.
- assertNull(getStackTrace(err), err);
+ long startTime = System.currentTimeMillis();
+ launchActivity(packageName, intent);
try {
- assertTrue("App crashed after launch.", processStillUp(packageName));
+ checkDropbox(startTime, packageName);
+ if (mAppErrors.containsKey(packageName)) {
+ StringBuilder message = new StringBuilder("Error detected for package: ")
+ .append(packageName);
+ for (String err : mAppErrors.get(packageName)) {
+ message.append("\n\n");
+ message.append(err);
+ }
+ Assert.fail(message.toString());
+ }
+ // last check: see if app process is still running
+ Assert.assertTrue("app package \"" + packageName + "\" no longer found in running "
+ + "tasks, but no explicit crashes were detected; check logcat for details",
+ processStillUp(packageName));
} finally {
returnHome();
}
@@ -124,31 +171,30 @@
}
/**
- * Gets the stack trace for the error.
- *
- * @param in {@link ProcessErrorStateInfo} to parse.
- * @return {@link String} the long message of the error.
+ * Check dropbox for entries of interest regarding the specified process
+ * @param startTime if not 0, only check entries with timestamp later than the start time
+ * @param processName the process name to check for
*/
- private String getStackTrace(ProcessErrorStateInfo in) {
- if (in == null) {
- return null;
- } else {
- return in.stackTrace;
- }
- }
-
- /**
- * Returns the process name that the package is going to use.
- *
- * @param packageName name of the package
- * @return process name of the package
- */
- private String getProcessName(String packageName) {
- try {
- PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
- return pi.applicationInfo.processName;
- } catch (NameNotFoundException e) {
- return packageName;
+ private void checkDropbox(long startTime, String processName) {
+ DropBoxManager dropbox = (DropBoxManager) mContext
+ .getSystemService(Context.DROPBOX_SERVICE);
+ DropBoxManager.Entry entry = null;
+ while (null != (entry = dropbox.getNextEntry(null, startTime))) {
+ try {
+ // only check entries with tag that's of interest
+ String tag = entry.getTag();
+ if (DROPBOX_TAGS.contains(tag)) {
+ String content = entry.getText(4096);
+ if (content != null) {
+ if (content.contains(processName)) {
+ addProcessError(processName, "dropbox:" + tag, content);
+ }
+ }
+ }
+ startTime = entry.getTimeMillis();
+ } finally {
+ entry.close();
+ }
}
}
@@ -166,8 +212,7 @@
}
private Intent getLaunchIntentForPackage(String packageName) {
- UiModeManager umm = (UiModeManager)
- getInstrumentation().getContext().getSystemService(Context.UI_MODE_SERVICE);
+ UiModeManager umm = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
boolean isLeanback = umm.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION;
Intent intent = null;
if (isLeanback) {
@@ -186,35 +231,32 @@
* @return {@link Collection} of {@link ProcessErrorStateInfo} detected
* during the app launch.
*/
- private ProcessErrorStateInfo launchActivity(String packageName, Intent intent) {
+ private void launchActivity(String packageName, Intent intent) {
Log.d(TAG, String.format("launching package \"%s\" with intent: %s",
packageName, intent.toString()));
- String processName = getProcessName(packageName);
-
// Launch Activity
mContext.startActivity(intent);
try {
+ // artificial delay: in case app crashes after doing some work during launch
Thread.sleep(mAppLaunchTimeout);
} catch (InterruptedException e) {
// ignore
}
+ }
- // See if there are any errors. We wait until down here to give ANRs as much time as
- // possible to occur.
- final Collection<ProcessErrorStateInfo> postErr =
- mActivityManager.getProcessesInErrorState();
-
- if (postErr == null) {
- return null;
+ private void addProcessError(String processName, String errorType, String errorInfo) {
+ // parse out the package name if necessary, for apps with multiple proceses
+ String pkgName = processName.split(":", 2)[0];
+ List<String> errors;
+ if (mAppErrors.containsKey(pkgName)) {
+ errors = mAppErrors.get(pkgName);
+ } else {
+ errors = new ArrayList<>();
}
- for (ProcessErrorStateInfo error : postErr) {
- if (error.processName.equals(processName)) {
- return error;
- }
- }
- return null;
+ errors.add(String.format("type: %s details:\n%s", errorType, errorInfo));
+ mAppErrors.put(pkgName, errors);
}
/**
@@ -233,4 +275,55 @@
}
return false;
}
+
+ /**
+ * An {@link IActivityController} that instructs framework to kill processes hitting crashes
+ * directly without showing crash dialogs
+ *
+ */
+ private class CrashSuppressor extends IActivityController.Stub {
+
+ @Override
+ public boolean activityStarting(Intent intent, String pkg) throws RemoteException {
+ Log.d(TAG, "activity starting: " + intent.getComponent().toShortString());
+ return true;
+ }
+
+ @Override
+ public boolean activityResuming(String pkg) throws RemoteException {
+ Log.d(TAG, "activity resuming: " + pkg);
+ return true;
+ }
+
+ @Override
+ public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg,
+ long timeMillis, String stackTrace) throws RemoteException {
+ Log.d(TAG, "app crash: " + processName);
+ addProcessError(processName, "crash", stackTrace);
+ // don't show dialog
+ return false;
+ }
+
+ @Override
+ public int appEarlyNotResponding(String processName, int pid, String annotation)
+ throws RemoteException {
+ // ignore
+ return 0;
+ }
+
+ @Override
+ public int appNotResponding(String processName, int pid, String processStats)
+ throws RemoteException {
+ Log.d(TAG, "app ANR: " + processName);
+ addProcessError(processName, "ANR", processStats);
+ // don't show dialog
+ return -1;
+ }
+
+ @Override
+ public int systemNotResponding(String msg) throws RemoteException {
+ // ignore
+ return -1;
+ }
+ }
}
diff --git a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibilityRunner.java b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibilityRunner.java
index 258937f..b61ec34 100644
--- a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibilityRunner.java
+++ b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibilityRunner.java
@@ -16,20 +16,7 @@
package com.android.compatibilitytest;
-import android.os.Bundle;
-import android.test.InstrumentationTestRunner;
+import android.support.test.runner.AndroidJUnitRunner;
-public class AppCompatibilityRunner extends InstrumentationTestRunner {
-
- private Bundle mArgs;
-
- @Override
- public void onCreate(Bundle args) {
- super.onCreate(args);
- mArgs = args;
- }
-
- public Bundle getBundle() {
- return mArgs;
- }
-}
+// empty subclass to maintain backwards compatibility on host-side harness
+public class AppCompatibilityRunner extends AndroidJUnitRunner {}
diff --git a/tests/net/java/android/net/util/BlockingSocketReaderTest.java b/tests/net/java/android/net/util/BlockingSocketReaderTest.java
index e03350f..1aad453 100644
--- a/tests/net/java/android/net/util/BlockingSocketReaderTest.java
+++ b/tests/net/java/android/net/util/BlockingSocketReaderTest.java
@@ -16,8 +16,11 @@
package android.net.util;
+import static android.net.util.BlockingSocketReader.DEFAULT_RECV_BUF_SIZE;
import static android.system.OsConstants.*;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructTimeval;
@@ -27,6 +30,7 @@
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
+import java.io.UncheckedIOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.Inet6Address;
@@ -53,61 +57,83 @@
protected FileDescriptor mLocalSocket;
protected InetSocketAddress mLocalSockName;
protected byte[] mLastRecvBuf;
- protected boolean mExited;
+ protected boolean mStopped;
+ protected HandlerThread mHandlerThread;
protected BlockingSocketReader mReceiver;
+ class UdpLoopbackReader extends BlockingSocketReader {
+ public UdpLoopbackReader(Handler h) {
+ super(h);
+ }
+
+ @Override
+ protected FileDescriptor createFd() {
+ FileDescriptor s = null;
+ try {
+ s = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ Os.bind(s, LOOPBACK6, 0);
+ mLocalSockName = (InetSocketAddress) Os.getsockname(s);
+ Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO);
+ } catch (ErrnoException|SocketException e) {
+ closeFd(s);
+ fail();
+ return null;
+ }
+
+ mLocalSocket = s;
+ return s;
+ }
+
+ @Override
+ protected void handlePacket(byte[] recvbuf, int length) {
+ mLastRecvBuf = Arrays.copyOf(recvbuf, length);
+ mLatch.countDown();
+ }
+
+ @Override
+ protected void onStart() {
+ mStopped = false;
+ mLatch.countDown();
+ }
+
+ @Override
+ protected void onStop() {
+ mStopped = true;
+ mLatch.countDown();
+ }
+ };
+
@Override
public void setUp() {
resetLatch();
mLocalSocket = null;
mLocalSockName = null;
mLastRecvBuf = null;
- mExited = false;
+ mStopped = false;
- mReceiver = new BlockingSocketReader() {
- @Override
- protected FileDescriptor createSocket() {
- FileDescriptor s = null;
- try {
- s = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
- Os.bind(s, LOOPBACK6, 0);
- mLocalSockName = (InetSocketAddress) Os.getsockname(s);
- Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO);
- } catch (ErrnoException|SocketException e) {
- closeSocket(s);
- fail();
- return null;
- }
-
- mLocalSocket = s;
- return s;
- }
-
- @Override
- protected void handlePacket(byte[] recvbuf, int length) {
- mLastRecvBuf = Arrays.copyOf(recvbuf, length);
- mLatch.countDown();
- }
-
- @Override
- protected void onExit() {
- mExited = true;
- mLatch.countDown();
- }
- };
+ mHandlerThread = new HandlerThread(BlockingSocketReaderTest.class.getSimpleName());
+ mHandlerThread.start();
}
@Override
- public void tearDown() {
- if (mReceiver != null) mReceiver.stop();
+ public void tearDown() throws Exception {
+ if (mReceiver != null) {
+ mHandlerThread.getThreadHandler().post(() -> { mReceiver.stop(); });
+ waitForActivity();
+ }
mReceiver = null;
+ mHandlerThread.quit();
+ mHandlerThread = null;
}
void resetLatch() { mLatch = new CountDownLatch(1); }
void waitForActivity() throws Exception {
- assertTrue(mLatch.await(500, TimeUnit.MILLISECONDS));
- resetLatch();
+ try {
+ mLatch.await(1000, TimeUnit.MILLISECONDS);
+ } finally {
+ resetLatch();
+ }
}
void sendPacket(byte[] contents) throws Exception {
@@ -118,31 +144,54 @@
}
public void testBasicWorking() throws Exception {
- assertTrue(mReceiver.start());
+ final Handler h = mHandlerThread.getThreadHandler();
+ mReceiver = new UdpLoopbackReader(h);
+
+ h.post(() -> { mReceiver.start(); });
+ waitForActivity();
assertTrue(mLocalSockName != null);
assertEquals(LOOPBACK6, mLocalSockName.getAddress());
assertTrue(0 < mLocalSockName.getPort());
assertTrue(mLocalSocket != null);
- assertFalse(mExited);
+ assertFalse(mStopped);
final byte[] one = "one 1".getBytes("UTF-8");
sendPacket(one);
waitForActivity();
assertEquals(1, mReceiver.numPacketsReceived());
assertTrue(Arrays.equals(one, mLastRecvBuf));
- assertFalse(mExited);
+ assertFalse(mStopped);
final byte[] two = "two 2".getBytes("UTF-8");
sendPacket(two);
waitForActivity();
assertEquals(2, mReceiver.numPacketsReceived());
assertTrue(Arrays.equals(two, mLastRecvBuf));
- assertFalse(mExited);
+ assertFalse(mStopped);
mReceiver.stop();
waitForActivity();
assertEquals(2, mReceiver.numPacketsReceived());
assertTrue(Arrays.equals(two, mLastRecvBuf));
- assertTrue(mExited);
+ assertTrue(mStopped);
+ mReceiver = null;
+ }
+
+ class NullBlockingSocketReader extends BlockingSocketReader {
+ public NullBlockingSocketReader(Handler h, int recvbufsize) {
+ super(h, recvbufsize);
+ }
+
+ @Override
+ public FileDescriptor createFd() { return null; }
+ }
+
+ public void testMinimalRecvBufSize() throws Exception {
+ final Handler h = mHandlerThread.getThreadHandler();
+
+ for (int i : new int[]{-1, 0, 1, DEFAULT_RECV_BUF_SIZE-1}) {
+ final BlockingSocketReader b = new NullBlockingSocketReader(h, i);
+ assertEquals(DEFAULT_RECV_BUF_SIZE, b.recvBufSize());
+ }
}
}
diff --git a/tests/net/java/com/android/internal/util/RingBufferTest.java b/tests/net/java/com/android/internal/util/RingBufferTest.java
new file mode 100644
index 0000000..7a2344317
--- /dev/null
+++ b/tests/net/java/com/android/internal/util/RingBufferTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import java.util.Arrays;
+import java.util.Objects;
+
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RingBufferTest {
+
+ @Test
+ public void testEmptyRingBuffer() {
+ RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
+
+ assertArraysEqual(new String[0], buffer.toArray());
+ }
+
+ @Test
+ public void testIncorrectConstructorArguments() {
+ try {
+ RingBuffer<String> buffer = new RingBuffer<>(String.class, -10);
+ fail("Should not be able to create a negative capacity RingBuffer");
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ RingBuffer<String> buffer = new RingBuffer<>(String.class, 0);
+ fail("Should not be able to create a 0 capacity RingBuffer");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testRingBufferWithNoWrapping() {
+ RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
+
+ buffer.append("a");
+ buffer.append("b");
+ buffer.append("c");
+ buffer.append("d");
+ buffer.append("e");
+
+ String[] expected = {"a", "b", "c", "d", "e"};
+ assertArraysEqual(expected, buffer.toArray());
+ }
+
+ @Test
+ public void testRingBufferWithCapacity1() {
+ RingBuffer<String> buffer = new RingBuffer<>(String.class, 1);
+
+ buffer.append("a");
+ assertArraysEqual(new String[]{"a"}, buffer.toArray());
+
+ buffer.append("b");
+ assertArraysEqual(new String[]{"b"}, buffer.toArray());
+
+ buffer.append("c");
+ assertArraysEqual(new String[]{"c"}, buffer.toArray());
+
+ buffer.append("d");
+ assertArraysEqual(new String[]{"d"}, buffer.toArray());
+
+ buffer.append("e");
+ assertArraysEqual(new String[]{"e"}, buffer.toArray());
+ }
+
+ @Test
+ public void testRingBufferWithWrapping() {
+ int capacity = 100;
+ RingBuffer<String> buffer = new RingBuffer<>(String.class, capacity);
+
+ buffer.append("a");
+ buffer.append("b");
+ buffer.append("c");
+ buffer.append("d");
+ buffer.append("e");
+
+ String[] expected1 = {"a", "b", "c", "d", "e"};
+ assertArraysEqual(expected1, buffer.toArray());
+
+ String[] expected2 = new String[capacity];
+ int firstIndex = 0;
+ int lastIndex = capacity - 1;
+
+ expected2[firstIndex] = "e";
+ for (int i = 1; i < capacity; i++) {
+ buffer.append("x");
+ expected2[i] = "x";
+ }
+ assertArraysEqual(expected2, buffer.toArray());
+
+ buffer.append("x");
+ expected2[firstIndex] = "x";
+ assertArraysEqual(expected2, buffer.toArray());
+
+ for (int i = 0; i < 10; i++) {
+ for (String s : expected2) {
+ buffer.append(s);
+ }
+ }
+ assertArraysEqual(expected2, buffer.toArray());
+
+ buffer.append("a");
+ expected2[lastIndex] = "a";
+ assertArraysEqual(expected2, buffer.toArray());
+ }
+
+ static <T> void assertArraysEqual(T[] expected, T[] got) {
+ if (expected.length != got.length) {
+ fail(Arrays.toString(expected) + " and " + Arrays.toString(got)
+ + " did not have the same length");
+ }
+
+ for (int i = 0; i < expected.length; i++) {
+ if (!Objects.equals(expected[i], got[i])) {
+ fail(Arrays.toString(expected) + " and " + Arrays.toString(got)
+ + " were not equal");
+ }
+ }
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index a814738..335e6240 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -19,6 +19,8 @@
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
+import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.getNetworkTypeName;
@@ -119,7 +121,6 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.BooleanSupplier;
import java.util.function.Predicate;
/**
@@ -782,6 +783,13 @@
return new FakeWakeupMessage(context, handler, cmdName, cmd, 0, 0, obj);
}
+ @Override
+ public boolean hasService(String name) {
+ // Currenty, the only relevant service that ConnectivityService checks for is
+ // ETHERNET_SERVICE.
+ return Context.ETHERNET_SERVICE.equals(name);
+ }
+
public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
return mLastCreatedNetworkMonitor;
}
@@ -929,6 +937,13 @@
// will fail. Failing here is much easier to debug.
assertTrue(mCm.isNetworkSupported(TYPE_WIFI));
assertTrue(mCm.isNetworkSupported(TYPE_MOBILE));
+ assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_MMS));
+ assertFalse(mCm.isNetworkSupported(TYPE_MOBILE_FOTA));
+
+ // Check that TYPE_ETHERNET is supported. Unlike the asserts above, which only validate our
+ // mocks, this assert exercises the ConnectivityService code path that ensures that
+ // TYPE_ETHERNET is supported if the ethernet service is running.
+ assertTrue(mCm.isNetworkSupported(TYPE_ETHERNET));
}
@SmallTest
@@ -3196,68 +3211,68 @@
}
@SmallTest
- public void testNetworkRequestMaximum() {
+ public void testNetworkCallbackMaximum() {
final int MAX_REQUESTS = 100;
- // Test that the limit is enforced when MAX_REQUESTS simultaneous requests are added.
+ final int CALLBACKS = 90;
+ final int INTENTS = 10;
+ assertEquals(MAX_REQUESTS, CALLBACKS + INTENTS);
+
NetworkRequest networkRequest = new NetworkRequest.Builder().build();
- ArrayList<NetworkCallback> networkCallbacks = new ArrayList<NetworkCallback>();
- try {
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.requestNetwork(networkRequest, networkCallback);
- networkCallbacks.add(networkCallback);
- }
- fail("Registering " + MAX_REQUESTS + " NetworkRequests did not throw exception");
- } catch (TooManyRequestsException expected) {}
- for (NetworkCallback networkCallback : networkCallbacks) {
- mCm.unregisterNetworkCallback(networkCallback);
- }
- networkCallbacks.clear();
+ ArrayList<Object> registered = new ArrayList<>();
- try {
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
- networkCallbacks.add(networkCallback);
- }
- fail("Registering " + MAX_REQUESTS + " NetworkCallbacks did not throw exception");
- } catch (TooManyRequestsException expected) {}
- for (NetworkCallback networkCallback : networkCallbacks) {
- mCm.unregisterNetworkCallback(networkCallback);
+ int j = 0;
+ while (j++ < CALLBACKS / 2) {
+ NetworkCallback cb = new NetworkCallback();
+ mCm.requestNetwork(networkRequest, cb);
+ registered.add(cb);
}
- networkCallbacks.clear();
+ while (j++ < CALLBACKS) {
+ NetworkCallback cb = new NetworkCallback();
+ mCm.registerNetworkCallback(networkRequest, cb);
+ registered.add(cb);
+ }
+ j = 0;
+ while (j++ < INTENTS / 2) {
+ PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, new Intent("a" + j), 0);
+ mCm.requestNetwork(networkRequest, pi);
+ registered.add(pi);
+ }
+ while (j++ < INTENTS) {
+ PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, new Intent("b" + j), 0);
+ mCm.registerNetworkCallback(networkRequest, pi);
+ registered.add(pi);
+ }
- ArrayList<PendingIntent> pendingIntents = new ArrayList<PendingIntent>();
+ // Test that the limit is enforced when MAX_REQUESTS simultaneous requests are added.
try {
- for (int i = 0; i < MAX_REQUESTS + 1; i++) {
- PendingIntent pendingIntent =
- PendingIntent.getBroadcast(mContext, 0, new Intent("a" + i), 0);
- mCm.requestNetwork(networkRequest, pendingIntent);
- pendingIntents.add(pendingIntent);
- }
- fail("Registering " + MAX_REQUESTS +
- " PendingIntent NetworkRequests did not throw exception");
+ mCm.requestNetwork(networkRequest, new NetworkCallback());
+ fail("Registering " + MAX_REQUESTS + " network requests did not throw exception");
} catch (TooManyRequestsException expected) {}
- for (PendingIntent pendingIntent : pendingIntents) {
- mCm.unregisterNetworkCallback(pendingIntent);
- }
- pendingIntents.clear();
+ try {
+ mCm.registerNetworkCallback(networkRequest, new NetworkCallback());
+ fail("Registering " + MAX_REQUESTS + " network callbacks did not throw exception");
+ } catch (TooManyRequestsException expected) {}
+ try {
+ mCm.requestNetwork(networkRequest,
+ PendingIntent.getBroadcast(mContext, 0, new Intent("c"), 0));
+ fail("Registering " + MAX_REQUESTS + " PendingIntent requests did not throw exception");
+ } catch (TooManyRequestsException expected) {}
+ try {
+ mCm.registerNetworkCallback(networkRequest,
+ PendingIntent.getBroadcast(mContext, 0, new Intent("d"), 0));
+ fail("Registering " + MAX_REQUESTS
+ + " PendingIntent callbacks did not throw exception");
+ } catch (TooManyRequestsException expected) {}
- try {
- for (int i = 0; i < MAX_REQUESTS + 1; i++) {
- PendingIntent pendingIntent =
- PendingIntent.getBroadcast(mContext, 0, new Intent("a" + i), 0);
- mCm.registerNetworkCallback(networkRequest, pendingIntent);
- pendingIntents.add(pendingIntent);
+ for (Object o : registered) {
+ if (o instanceof NetworkCallback) {
+ mCm.unregisterNetworkCallback((NetworkCallback)o);
}
- fail("Registering " + MAX_REQUESTS +
- " PendingIntent NetworkCallbacks did not throw exception");
- } catch (TooManyRequestsException expected) {}
- for (PendingIntent pendingIntent : pendingIntents) {
- mCm.unregisterNetworkCallback(pendingIntent);
+ if (o instanceof PendingIntent) {
+ mCm.unregisterNetworkCallback((PendingIntent)o);
+ }
}
- pendingIntents.clear();
- waitForIdle(5000);
+ waitForIdle();
// Test that the limit is not hit when MAX_REQUESTS requests are added and removed.
for (int i = 0; i < MAX_REQUESTS; i++) {
@@ -3265,23 +3280,23 @@
mCm.requestNetwork(networkRequest, networkCallback);
mCm.unregisterNetworkCallback(networkCallback);
}
- waitForIdle();
+
for (int i = 0; i < MAX_REQUESTS; i++) {
NetworkCallback networkCallback = new NetworkCallback();
mCm.registerNetworkCallback(networkRequest, networkCallback);
mCm.unregisterNetworkCallback(networkCallback);
}
- waitForIdle();
+
for (int i = 0; i < MAX_REQUESTS; i++) {
PendingIntent pendingIntent =
- PendingIntent.getBroadcast(mContext, 0, new Intent("b" + i), 0);
+ PendingIntent.getBroadcast(mContext, 0, new Intent("e" + i), 0);
mCm.requestNetwork(networkRequest, pendingIntent);
mCm.unregisterNetworkCallback(pendingIntent);
}
- waitForIdle();
+
for (int i = 0; i < MAX_REQUESTS; i++) {
PendingIntent pendingIntent =
- PendingIntent.getBroadcast(mContext, 0, new Intent("c" + i), 0);
+ PendingIntent.getBroadcast(mContext, 0, new Intent("f" + i), 0);
mCm.registerNetworkCallback(networkRequest, pendingIntent);
mCm.unregisterNetworkCallback(pendingIntent);
}
diff --git a/tests/net/java/com/android/server/NsdServiceTest.java b/tests/net/java/com/android/server/NsdServiceTest.java
index 2e49c98..b88c784 100644
--- a/tests/net/java/com/android/server/NsdServiceTest.java
+++ b/tests/net/java/com/android/server/NsdServiceTest.java
@@ -77,7 +77,10 @@
@After
public void tearDown() throws Exception {
- mThread.quit();
+ if (mThread != null) {
+ mThread.quit();
+ mThread = null;
+ }
}
@Test
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index de28de6..dfe31bd 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -126,7 +126,6 @@
mLooper.dispatchNext();
verify(mNms).getInterfaceConfig(eq(STACKED_IFACE));
- verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(false));
verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
assertFalse(c.getValue().getStackedLinks().isEmpty());
assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
@@ -136,7 +135,6 @@
nat.stop();
verify(mNms).stopClatd(eq(BASE_IFACE));
- verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(true));
// Stacked interface removed notification arrives.
nat.interfaceRemoved(STACKED_IFACE);
@@ -167,7 +165,6 @@
mLooper.dispatchNext();
verify(mNms).getInterfaceConfig(eq(STACKED_IFACE));
- verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(false));
verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
assertFalse(c.getValue().getStackedLinks().isEmpty());
assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
@@ -179,7 +176,6 @@
verify(mNms).unregisterObserver(eq(nat));
verify(mNms).stopClatd(eq(BASE_IFACE));
- verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(true));
verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
assertTrue(c.getValue().getStackedLinks().isEmpty());
assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 43918da..7a8a4ee 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -106,9 +106,8 @@
"optimize/ResourceDeduper.cpp",
"optimize/VersionCollapser.cpp",
"process/SymbolTable.cpp",
- "proto/ProtoHelpers.cpp",
- "proto/TableProtoDeserializer.cpp",
- "proto/TableProtoSerializer.cpp",
+ "proto/ProtoDeserialize.cpp",
+ "proto/ProtoSerialize.cpp",
"split/TableSplitter.cpp",
"text/Unicode.cpp",
"text/Utf8Iterator.cpp",
@@ -139,6 +138,7 @@
"xml/XmlDom.cpp",
"xml/XmlPullParser.cpp",
"xml/XmlUtil.cpp",
+ "Configuration.proto",
"Resources.proto",
"ResourcesInternal.proto",
],
diff --git a/tools/aapt2/ConfigDescription.cpp b/tools/aapt2/ConfigDescription.cpp
index a9278c1..59a6e12 100644
--- a/tools/aapt2/ConfigDescription.cpp
+++ b/tools/aapt2/ConfigDescription.cpp
@@ -876,6 +876,12 @@
return copy;
}
+std::string ConfigDescription::GetBcp47LanguageTag(bool canonicalize) const {
+ char locale[RESTABLE_MAX_LOCALE_LEN];
+ getBcp47Locale(locale, canonicalize);
+ return std::string(locale);
+}
+
bool ConfigDescription::Dominates(const ConfigDescription& o) const {
if (*this == o) {
return true;
diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h
index 65c9617..c1d0e10 100644
--- a/tools/aapt2/ConfigDescription.h
+++ b/tools/aapt2/ConfigDescription.h
@@ -61,6 +61,9 @@
ConfigDescription CopyWithoutSdkVersion() const;
+ // Returns the BCP-47 language tag of this configuration's locale.
+ std::string GetBcp47LanguageTag(bool canonicalize = false) 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
diff --git a/tools/aapt2/Configuration.proto b/tools/aapt2/Configuration.proto
new file mode 100644
index 0000000..fc636a4
--- /dev/null
+++ b/tools/aapt2/Configuration.proto
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package aapt.pb;
+
+option java_package = "com.android.aapt";
+option optimize_for = LITE_RUNTIME;
+
+// A description of the requirements a device must have in order for a
+// resource to be matched and selected.
+message Configuration {
+ enum LayoutDirection {
+ LAYOUT_DIRECTION_UNSET = 0;
+ LAYOUT_DIRECTION_LTR = 1;
+ LAYOUT_DIRECTION_RTL = 2;
+ }
+
+ enum ScreenLayoutSize {
+ SCREEN_LAYOUT_SIZE_UNSET = 0;
+ SCREEN_LAYOUT_SIZE_SMALL = 1;
+ SCREEN_LAYOUT_SIZE_NORMAL = 2;
+ SCREEN_LAYOUT_SIZE_LARGE = 3;
+ SCREEN_LAYOUT_SIZE_XLARGE = 4;
+ }
+
+ enum ScreenLayoutLong {
+ SCREEN_LAYOUT_LONG_UNSET = 0;
+ SCREEN_LAYOUT_LONG_LONG = 1;
+ SCREEN_LAYOUT_LONG_NOTLONG = 2;
+ }
+
+ enum ScreenRound {
+ SCREEN_ROUND_UNSET = 0;
+ SCREEN_ROUND_ROUND = 1;
+ SCREEN_ROUND_NOTROUND = 2;
+ }
+
+ enum WideColorGamut {
+ WIDE_COLOR_GAMUT_UNSET = 0;
+ WIDE_COLOR_GAMUT_WIDECG = 1;
+ WIDE_COLOR_GAMUT_NOWIDECG = 2;
+ }
+
+ enum Hdr {
+ HDR_UNSET = 0;
+ HDR_HIGHDR = 1;
+ HDR_LOWDR = 2;
+ }
+
+ enum Orientation {
+ ORIENTATION_UNSET = 0;
+ ORIENTATION_PORT = 1;
+ ORIENTATION_LAND = 2;
+ ORIENTATION_SQUARE = 3;
+ }
+
+ enum UiModeType {
+ UI_MODE_TYPE_UNSET = 0;
+ UI_MODE_TYPE_NORMAL = 1;
+ UI_MODE_TYPE_DESK = 2;
+ UI_MODE_TYPE_CAR = 3;
+ UI_MODE_TYPE_TELEVISION = 4;
+ UI_MODE_TYPE_APPLIANCE = 5;
+ UI_MODE_TYPE_WATCH = 6;
+ UI_MODE_TYPE_VRHEADSET = 7;
+ }
+
+ enum UiModeNight {
+ UI_MODE_NIGHT_UNSET = 0;
+ UI_MODE_NIGHT_NIGHT = 1;
+ UI_MODE_NIGHT_NOTNIGHT = 2;
+ }
+
+ enum Touchscreen {
+ TOUCHSCREEN_UNSET = 0;
+ TOUCHSCREEN_NOTOUCH = 1;
+ TOUCHSCREEN_STYLUS = 2;
+ TOUCHSCREEN_FINGER = 3;
+ }
+
+ enum KeysHidden {
+ KEYS_HIDDEN_UNSET = 0;
+ KEYS_HIDDEN_KEYSEXPOSED = 1;
+ KEYS_HIDDEN_KEYSHIDDEN = 2;
+ KEYS_HIDDEN_KEYSSOFT = 3;
+ }
+
+ enum Keyboard {
+ KEYBOARD_UNSET = 0;
+ KEYBOARD_NOKEYS = 1;
+ KEYBOARD_QWERTY = 2;
+ KEYBOARD_TWELVEKEY = 3;
+ }
+
+ enum NavHidden {
+ NAV_HIDDEN_UNSET = 0;
+ NAV_HIDDEN_NAVEXPOSED = 1;
+ NAV_HIDDEN_NAVHIDDEN = 2;
+ }
+
+ enum Navigation {
+ NAVIGATION_UNSET = 0;
+ NAVIGATION_NONAV = 1;
+ NAVIGATION_DPAD = 2;
+ NAVIGATION_TRACKBALL = 3;
+ NAVIGATION_WHEEL = 4;
+ }
+
+ //
+ // Axis/dimensions that are understood by the runtime.
+ //
+
+ // Mobile country code.
+ uint32 mcc = 1;
+
+ // Mobile network code.
+ uint32 mnc = 2;
+
+ // BCP-47 locale tag.
+ string locale = 3;
+
+ // Left-to-right, right-to-left...
+ LayoutDirection layout_direction = 4;
+
+ // Screen width in pixels. Prefer screen_width_dp.
+ uint32 screen_width = 5;
+
+ // Screen height in pixels. Prefer screen_height_dp.
+ uint32 screen_height = 6;
+
+ // Screen width in density independent pixels (dp).
+ uint32 screen_width_dp = 7;
+
+ // Screen height in density independent pixels (dp).
+ uint32 screen_height_dp = 8;
+
+ // The smallest screen dimension, regardless of orientation, in dp.
+ uint32 smallest_screen_width_dp = 9;
+
+ // Whether the device screen is classified as small, normal, large, xlarge.
+ ScreenLayoutSize screen_layout_size = 10;
+
+ // Whether the device screen is long.
+ ScreenLayoutLong screen_layout_long = 11;
+
+ // Whether the screen is round (Android Wear).
+ ScreenRound screen_round = 12;
+
+ // Whether the screen supports wide color gamut.
+ WideColorGamut wide_color_gamut = 13;
+
+ // Whether the screen has high dynamic range.
+ Hdr hdr = 14;
+
+ // Which orientation the device is in (portrait, landscape).
+ Orientation orientation = 15;
+
+ // Which type of UI mode the device is in (television, car, etc.).
+ UiModeType ui_mode_type = 16;
+
+ // Whether the device is in night mode.
+ UiModeNight ui_mode_night = 17;
+
+ // The device's screen density in dots-per-inch (dpi).
+ uint32 density = 18;
+
+ // Whether a touchscreen exists, supports a stylus, or finger.
+ Touchscreen touchscreen = 19;
+
+ // Whether the keyboard hardware keys are currently hidden, exposed, or
+ // if the keyboard is a software keyboard.
+ KeysHidden keys_hidden = 20;
+
+ // The type of keyboard present (none, QWERTY, 12-key).
+ Keyboard keyboard = 21;
+
+ // Whether the navigation is exposed or hidden.
+ NavHidden nav_hidden = 22;
+
+ // The type of navigation present on the device
+ // (trackball, wheel, dpad, etc.).
+ Navigation navigation = 23;
+
+ // The minimum SDK version of the device.
+ uint32 sdk_version = 24;
+
+ //
+ // Build-time only dimensions.
+ //
+
+ string product = 25;
+}
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index dba9cb5..1555d6126 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -35,9 +35,9 @@
namespace {
-class PrintVisitor : public ValueVisitor {
+class PrintVisitor : public DescendingValueVisitor {
public:
- using ValueVisitor::Visit;
+ using DescendingValueVisitor::Visit;
void Visit(Attribute* attr) override {
std::cout << "(attr) type=";
diff --git a/tools/aapt2/Locale.cpp b/tools/aapt2/Locale.cpp
index 7664fac..d81921f 100644
--- a/tools/aapt2/Locale.cpp
+++ b/tools/aapt2/Locale.cpp
@@ -24,9 +24,10 @@
#include "util/Util.h"
-namespace aapt {
+using ::android::ResTable_config;
+using ::android::StringPiece;
-using android::ResTable_config;
+namespace aapt {
void LocaleValue::set_language(const char* language_chars) {
size_t i = 0;
@@ -72,7 +73,7 @@
return std::all_of(std::begin(str), std::end(str), ::isdigit);
}
-bool LocaleValue::InitFromFilterString(const android::StringPiece& str) {
+bool LocaleValue::InitFromFilterString(const StringPiece& str) {
// A locale (as specified in the filter) is an underscore separated name such
// as "en_US", "en_Latn_US", or "en_US_POSIX".
std::vector<std::string> parts = util::SplitAndLowercase(str, '_');
@@ -138,6 +139,71 @@
return true;
}
+bool LocaleValue::InitFromBcp47Tag(const StringPiece& bcp47tag) {
+ return InitFromBcp47TagImpl(bcp47tag, '-');
+}
+
+bool LocaleValue::InitFromBcp47TagImpl(const StringPiece& bcp47tag, const char separator) {
+ std::vector<std::string> subtags = util::SplitAndLowercase(bcp47tag, separator);
+ if (subtags.size() == 1) {
+ set_language(subtags[0].c_str());
+ } else if (subtags.size() == 2) {
+ set_language(subtags[0].c_str());
+
+ // The second tag can either be a region, a variant or a script.
+ switch (subtags[1].size()) {
+ case 2:
+ case 3:
+ set_region(subtags[1].c_str());
+ break;
+ case 4:
+ if ('0' <= subtags[1][0] && subtags[1][0] <= '9') {
+ // This is a variant: fall through
+ } else {
+ set_script(subtags[1].c_str());
+ break;
+ }
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ set_variant(subtags[1].c_str());
+ break;
+ default:
+ return false;
+ }
+ } else if (subtags.size() == 3) {
+ // The language is always the first subtag.
+ set_language(subtags[0].c_str());
+
+ // The second subtag can either be a script or a region code.
+ // If its size is 4, it's a script code, else it's a region code.
+ if (subtags[1].size() == 4) {
+ set_script(subtags[1].c_str());
+ } else if (subtags[1].size() == 2 || subtags[1].size() == 3) {
+ set_region(subtags[1].c_str());
+ } else {
+ return false;
+ }
+
+ // The third tag can either be a region code (if the second tag was
+ // a script), else a variant code.
+ if (subtags[2].size() >= 4) {
+ set_variant(subtags[2].c_str());
+ } else {
+ set_region(subtags[2].c_str());
+ }
+ } else if (subtags.size() == 4) {
+ set_language(subtags[0].c_str());
+ set_script(subtags[1].c_str());
+ set_region(subtags[2].c_str());
+ set_variant(subtags[3].c_str());
+ } else {
+ return false;
+ }
+ return true;
+}
+
ssize_t LocaleValue::InitFromParts(std::vector<std::string>::iterator iter,
std::vector<std::string>::iterator end) {
const std::vector<std::string>::iterator start_iter = iter;
@@ -145,71 +211,13 @@
std::string& part = *iter;
if (part[0] == 'b' && part[1] == '+') {
// This is a "modified" BCP 47 language tag. Same semantics as BCP 47 tags,
- // except that the separator is "+" and not "-".
- std::vector<std::string> subtags = util::SplitAndLowercase(part, '+');
- subtags.erase(subtags.begin());
- if (subtags.size() == 1) {
- set_language(subtags[0].c_str());
- } else if (subtags.size() == 2) {
- set_language(subtags[0].c_str());
-
- // The second tag can either be a region, a variant or a script.
- switch (subtags[1].size()) {
- case 2:
- case 3:
- set_region(subtags[1].c_str());
- break;
- case 4:
- if ('0' <= subtags[1][0] && subtags[1][0] <= '9') {
- // This is a variant: fall through
- } else {
- set_script(subtags[1].c_str());
- break;
- }
- case 5:
- case 6:
- case 7:
- case 8:
- set_variant(subtags[1].c_str());
- break;
- default:
- return -1;
- }
- } else if (subtags.size() == 3) {
- // The language is always the first subtag.
- set_language(subtags[0].c_str());
-
- // The second subtag can either be a script or a region code.
- // If its size is 4, it's a script code, else it's a region code.
- if (subtags[1].size() == 4) {
- set_script(subtags[1].c_str());
- } else if (subtags[1].size() == 2 || subtags[1].size() == 3) {
- set_region(subtags[1].c_str());
- } else {
- return -1;
- }
-
- // The third tag can either be a region code (if the second tag was
- // a script), else a variant code.
- if (subtags[2].size() >= 4) {
- set_variant(subtags[2].c_str());
- } else {
- set_region(subtags[2].c_str());
- }
- } else if (subtags.size() == 4) {
- set_language(subtags[0].c_str());
- set_script(subtags[1].c_str());
- set_region(subtags[2].c_str());
- set_variant(subtags[3].c_str());
- } else {
+ // except that the separator is "+" and not "-". Skip the prefix 'b+'.
+ if (!InitFromBcp47TagImpl(StringPiece(part).substr(2), '+')) {
return -1;
}
-
++iter;
-
} else {
- if ((part.length() == 2 || part.length() == 3) && is_alpha(part) &&
- part != "car") {
+ if ((part.length() == 2 || part.length() == 3) && is_alpha(part) && part != "car") {
set_language(part.c_str());
++iter;
@@ -222,7 +230,6 @@
}
}
}
-
return static_cast<ssize_t>(iter - start_iter);
}
diff --git a/tools/aapt2/Locale.h b/tools/aapt2/Locale.h
index 3d73b2e..6d8b598 100644
--- a/tools/aapt2/Locale.h
+++ b/tools/aapt2/Locale.h
@@ -41,6 +41,9 @@
*/
bool InitFromFilterString(const android::StringPiece& config);
+ // Initializes this LocaleValue from a BCP-47 locale tag.
+ bool InitFromBcp47Tag(const android::StringPiece& bcp47tag);
+
/**
* Initialize this LocaleValue from parts of a vector.
*/
@@ -67,6 +70,8 @@
inline bool operator>(const LocaleValue& o) const;
private:
+ bool InitFromBcp47TagImpl(const android::StringPiece& bcp47tag, const char separator);
+
void set_language(const char* language);
void set_region(const char* language);
void set_script(const char* script);
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 1cba194..e013729 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -35,15 +35,25 @@
}
template <typename Derived>
-void BaseValue<Derived>::Accept(RawValueVisitor* visitor) {
+void BaseValue<Derived>::Accept(ValueVisitor* visitor) {
visitor->Visit(static_cast<Derived*>(this));
}
template <typename Derived>
-void BaseItem<Derived>::Accept(RawValueVisitor* visitor) {
+void BaseValue<Derived>::Accept(ConstValueVisitor* visitor) const {
+ visitor->Visit(static_cast<const Derived*>(this));
+}
+
+template <typename Derived>
+void BaseItem<Derived>::Accept(ValueVisitor* visitor) {
visitor->Visit(static_cast<Derived*>(this));
}
+template <typename Derived>
+void BaseItem<Derived>::Accept(ConstValueVisitor* visitor) const {
+ visitor->Visit(static_cast<const Derived*>(this));
+}
+
RawString::RawString(const StringPool::Ref& ref) : value(ref) {}
bool RawString::Equals(const Value* value) const {
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index 275864b..742765d 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -33,7 +33,8 @@
namespace aapt {
-struct RawValueVisitor;
+class ValueVisitor;
+class ConstValueVisitor;
// A resource value. This is an all-encompassing representation
// of Item and Map and their subclasses. The way to do
@@ -45,36 +46,58 @@
virtual ~Value() = default;
// Whether this value is weak and can be overridden without warning or error. Default is false.
- bool IsWeak() const { return weak_; }
+ bool IsWeak() const {
+ return weak_;
+ }
- void SetWeak(bool val) { weak_ = val; }
+ void SetWeak(bool val) {
+ weak_ = val;
+ }
- // Whether the value is marked as translatable.
- // This does not persist when flattened.
+ // Whether the value is marked as translatable. This does not persist when flattened to binary.
// It is only used during compilation phase.
- void SetTranslatable(bool val) { translatable_ = val; }
+ void SetTranslatable(bool val) {
+ translatable_ = val;
+ }
// Default true.
- bool IsTranslatable() const { return translatable_; }
+ bool IsTranslatable() const {
+ return translatable_;
+ }
// Returns the source where this value was defined.
- const Source& GetSource() const { return source_; }
+ const Source& GetSource() const {
+ return source_;
+ }
- void SetSource(const Source& source) { source_ = source; }
+ void SetSource(const Source& source) {
+ source_ = source;
+ }
- void SetSource(Source&& source) { source_ = std::move(source); }
+ void SetSource(Source&& source) {
+ source_ = std::move(source);
+ }
// Returns the comment that was associated with this resource.
- const std::string& GetComment() const { return comment_; }
+ const std::string& GetComment() const {
+ return comment_;
+ }
- void SetComment(const android::StringPiece& str) { comment_ = str.to_string(); }
+ void SetComment(const android::StringPiece& str) {
+ comment_ = str.to_string();
+ }
- void SetComment(std::string&& str) { comment_ = std::move(str); }
+ void SetComment(std::string&& str) {
+ comment_ = std::move(str);
+ }
virtual bool Equals(const Value* value) const = 0;
// Calls the appropriate overload of ValueVisitor.
- virtual void Accept(RawValueVisitor* visitor) = 0;
+ virtual void Accept(ValueVisitor* visitor) = 0;
+
+ // Calls the appropriate overload of ConstValueVisitor.
+ virtual void Accept(ConstValueVisitor* visitor) const = 0;
// Clone the value. `new_pool` is the new StringPool that
// any resources with strings should use when copying their string.
@@ -95,7 +118,8 @@
// Inherit from this to get visitor accepting implementations for free.
template <typename Derived>
struct BaseValue : public Value {
- void Accept(RawValueVisitor* visitor) override;
+ void Accept(ValueVisitor* visitor) override;
+ void Accept(ConstValueVisitor* visitor) const override;
};
// A resource item with a single value. This maps to android::ResTable_entry.
@@ -111,7 +135,8 @@
// Inherit from this to get visitor accepting implementations for free.
template <typename Derived>
struct BaseItem : public Item {
- void Accept(RawValueVisitor* visitor) override;
+ void Accept(ValueVisitor* visitor) override;
+ void Accept(ConstValueVisitor* visitor) const override;
};
// A reference to another resource. This maps to android::Res_value::TYPE_REFERENCE.
@@ -144,7 +169,10 @@
// An ID resource. Has no real value, just a place holder.
struct Id : public BaseItem<Id> {
- Id() { weak_ = true; }
+ Id() {
+ weak_ = true;
+ }
+
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out) const override;
Id* Clone(StringPool* new_pool) const override;
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index 71f33b0..174b7f6 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -14,77 +14,80 @@
* limitations under the License.
*/
-// Keep proto2 syntax because we require the distinction between fields that
-// are set and unset.
-syntax = "proto2";
+syntax = "proto3";
+
+import "frameworks/base/tools/aapt2/Configuration.proto";
+
+package aapt.pb;
option java_package = "com.android.aapt";
option optimize_for = LITE_RUNTIME;
-package aapt.pb;
-
-// A configuration description that wraps the binary form of the C++ class
-// aapt::ConfigDescription, with an added product definition.
-// TODO(adamlesinski): Flesh this out to be represented in proto.
-message ConfigDescription {
- optional bytes data = 1;
- optional string product = 2;
-}
-
// A string pool that wraps the binary form of the C++ class android::ResStringPool.
message StringPool {
- optional bytes data = 1;
+ bytes data = 1;
}
// The position of a declared entity within a file.
message SourcePosition {
- optional uint32 line_number = 1;
- optional uint32 column_number = 2;
+ uint32 line_number = 1;
+ uint32 column_number = 2;
}
// Developer friendly source file information for an entity in the resource table.
message Source {
// The index of the string path within the source string pool of a ResourceTable.
- optional uint32 path_idx = 1;
- optional SourcePosition position = 2;
+ uint32 path_idx = 1;
+ SourcePosition position = 2;
}
// Top level message representing a resource table.
message ResourceTable {
// The string pool containing source paths referenced throughout the resource table. This does
// not end up in the final binary ARSC file.
- optional StringPool source_pool = 1;
+ StringPool source_pool = 1;
// Resource definitions corresponding to an Android package.
repeated Package package = 2;
}
+// A package ID in the range [0x00, 0xff].
+message PackageId {
+ uint32 id = 1;
+}
+
// Defines resources for an Android package.
message Package {
// The package ID of this package, in the range [0x00, 0xff].
- // The ID 0x00 is reserved for shared libraries, or when the ID is assigned at run-time.
- // The ID 0x01 is reserved for the 'android' package (framework).
- // The ID range [0x02, 0x7f) is reserved for auto-assignment to shared libraries at run-time.
- // The ID 0x7f is reserved for the application package.
- // IDs > 0x7f are reserved for the application as well and are treated as feature splits.
- optional uint32 package_id = 1;
+ // - ID 0x00 is reserved for shared libraries, or when the ID is assigned at run-time.
+ // - ID 0x01 is reserved for the 'android' package (framework).
+ // - ID range [0x02, 0x7f) is reserved for auto-assignment to shared libraries at run-time.
+ // - ID 0x7f is reserved for the application package.
+ // - IDs > 0x7f are reserved for the application as well and are treated as feature splits.
+ // This may not be set if no ID was assigned.
+ PackageId package_id = 1;
// The Java compatible Android package name of the app.
- optional string package_name = 2;
+ string package_name = 2;
// The series of types defined by the package.
repeated Type type = 3;
}
+// A type ID in the range [0x01, 0xff].
+message TypeId {
+ uint32 id = 1;
+}
+
// A set of resources grouped under a common type. Such types include string, layout, xml, dimen,
// attr, etc. This maps to the second part of a resource identifier in Java (R.type.entry).
message Type {
- // The ID of the type. This may be 0, which indicates no ID is set.
- optional uint32 id = 1;
+ // The ID of the type. This may not be set if no ID was assigned.
+ TypeId type_id = 1;
// The name of the type. This corresponds to the 'type' part of a full resource name of the form
// package:type/entry. The set of legal type names is listed in Resource.cpp.
- optional string name = 2;
+ string name = 2;
// The entries defined for this type.
repeated Entry entry = 3;
@@ -112,17 +115,22 @@
PUBLIC = 2;
}
- optional Visibility visibility = 1;
+ Visibility visibility = 1;
// The path at which this entry's visibility was defined (eg. public.xml).
- optional Source source = 2;
+ Source source = 2;
// The comment associated with the <public> tag.
- optional string comment = 3;
+ string comment = 3;
// Whether the symbol can be merged into another resource table without there being an existing
// definition to override. Used for overlays and set to true when <add-resource> is specified.
- optional bool allow_new = 4;
+ bool allow_new = 4;
+}
+
+// An entry ID in the range [0x0000, 0xffff].
+message EntryId {
+ uint32 id = 1;
}
// An entry declaration. An entry has a full resource ID that is the combination of package ID,
@@ -132,14 +140,15 @@
// The ID of this entry. Together with the package ID and type ID, this forms a full resource ID
// of the form 0xPPTTEEEE, where PP is the package ID, TT is the type ID, and EEEE is the entry
// ID.
- optional uint32 id = 1;
+ // This may not be set if no ID was assigned.
+ EntryId entry_id = 1;
// The name of this entry. This corresponds to the 'entry' part of a full resource name of the
// form package:type/entry.
- optional string name = 2;
+ string name = 2;
// The symbol status of this entry, which includes visibility information.
- optional SymbolStatus symbol_status = 3;
+ SymbolStatus symbol_status = 3;
// The set of values defined for this entry, each corresponding to a different
// configuration/variant.
@@ -148,50 +157,54 @@
// A Configuration/Value pair.
message ConfigValue {
- optional ConfigDescription config = 1;
- optional Value value = 2;
+ Configuration config = 1;
+ Value value = 2;
}
// The generic meta-data for every value in a resource table.
message Value {
// Where the value was defined.
- optional Source source = 1;
+ Source source = 1;
// Any comment associated with the value.
- optional string comment = 2;
+ string comment = 2;
// Whether the value can be overridden.
- optional bool weak = 3;
+ bool weak = 3;
- // If the value is an Item, this is set.
- optional Item item = 4;
-
- // If the value is a CompoundValue, this is set.
- optional CompoundValue compound_value = 5;
+ // The value is either an Item or a CompoundValue.
+ oneof value {
+ Item item = 4;
+ CompoundValue compound_value = 5;
+ }
}
// An Item is an abstract type. It represents a value that can appear inline in many places, such
// as XML attribute values or on the right hand side of style attribute definitions. The concrete
// type is one of the types below. Only one can be set.
message Item {
- optional Reference ref = 1;
- optional String str = 2;
- optional RawString raw_str = 3;
- optional StyledString styled_str = 4;
- optional FileReference file = 5;
- optional Id id = 6;
- optional Primitive prim = 7;
+ oneof value {
+ Reference ref = 1;
+ String str = 2;
+ RawString raw_str = 3;
+ StyledString styled_str = 4;
+ FileReference file = 5;
+ Id id = 6;
+ Primitive prim = 7;
+ }
}
// A CompoundValue is an abstract type. It represents a value that is a made of other values.
// These can only usually appear as top-level resources. The concrete type is one of the types
// below. Only one can be set.
message CompoundValue {
- optional Attribute attr = 1;
- optional Style style = 2;
- optional Styleable styleable = 3;
- optional Array array = 4;
- optional Plural plural = 5;
+ oneof value {
+ Attribute attr = 1;
+ Style style = 2;
+ Styleable styleable = 3;
+ Array array = 4;
+ Plural plural = 5;
+ }
}
// A value that is a reference to another resource. This reference can be by name or resource ID.
@@ -204,16 +217,16 @@
ATTRIBUTE = 1;
}
- optional Type type = 1;
+ Type type = 1;
- // The resource ID (0xPPTTEEEE) of the resource being referred.
- optional uint32 id = 2;
+ // The resource ID (0xPPTTEEEE) of the resource being referred. This is optional.
+ uint32 id = 2;
- // The optional resource name.
- optional string name = 3;
+ // The name of the resource being referred. This is optional if the resource ID is set.
+ string name = 3;
// Whether this reference is referencing a private resource (@*package:type/entry).
- optional bool private = 4;
+ bool private = 4;
}
// A value that represents an ID. This is just a placeholder, as ID values are used to occupy a
@@ -223,32 +236,32 @@
// A value that is a string.
message String {
- optional string value = 1;
+ string value = 1;
}
// A value that is a raw string, which is unescaped/uninterpreted. This is typically used to
// represent the value of a style attribute before the attribute is compiled and the set of
// allowed values is known.
message RawString {
- optional string value = 1;
+ string value = 1;
}
// A string with styling information, like html tags that specify boldness, italics, etc.
message StyledString {
// The raw text of the string.
- optional string value = 1;
+ string value = 1;
// A Span marks a region of the string text that is styled.
message Span {
// The name of the tag, and its attributes, encoded as follows:
// tag_name;attr1=value1;attr2=value2;[...]
- optional string tag = 1;
+ string tag = 1;
// The first character position this span applies to, in UTF-16 offset.
- optional uint32 first_char = 2;
+ uint32 first_char = 2;
// The last character position this span applies to, in UTF-16 offset.
- optional uint32 last_char = 3;
+ uint32 last_char = 3;
}
repeated Span span = 2;
@@ -257,14 +270,14 @@
// A value that is a reference to an external entity, like an XML file or a PNG.
message FileReference {
// Path to a file within the APK (typically res/type-config/entry.ext).
- optional string path = 1;
+ string path = 1;
}
// A value that represents a primitive data type (float, int, boolean, etc.).
// Corresponds to the fields (type/data) of the C struct android::Res_value.
message Primitive {
- optional uint32 type = 1;
- optional uint32 data = 2;
+ uint32 type = 1;
+ uint32 data = 2;
}
// A value that represents an XML attribute and what values it accepts.
@@ -272,21 +285,22 @@
// A Symbol used to represent an enum or a flag.
message Symbol {
// Where the enum/flag item was defined.
- optional Source source = 1;
+ Source source = 1;
// Any comments associated with the enum or flag.
- optional string comment = 2;
+ string comment = 2;
// The name of the enum/flag as a reference. Enums/flag items are generated as ID resource
// values.
- optional Reference name = 3;
+ Reference name = 3;
// The value of the enum/flag.
- optional uint32 value = 4;
+ uint32 value = 4;
}
// Bitmask of formats allowed for an attribute.
enum FormatFlags {
+ NONE = 0x0; // Proto3 requires a default of 0.
ANY = 0x0000ffff; // Allows any type except ENUM and FLAGS.
REFERENCE = 0x01; // Allows Reference values.
STRING = 0x02; // Allows String/StyledString values.
@@ -304,15 +318,15 @@
// A bitmask of types that this XML attribute accepts. Corresponds to the flags in the
// enum FormatFlags.
- optional uint32 format_flags = 1;
+ uint32 format_flags = 1;
// The smallest integer allowed for this XML attribute. Only makes sense if the format includes
// FormatFlags::INTEGER.
- optional int32 min_int = 2;
+ int32 min_int = 2;
// The largest integer allowed for this XML attribute. Only makes sense if the format includes
// FormatFlags::INTEGER.
- optional int32 max_int = 3;
+ int32 max_int = 3;
// The set of enums/flags defined in this attribute. Only makes sense if the format includes
// either FormatFlags::ENUM or FormatFlags::FLAGS. Having both is an error.
@@ -324,23 +338,23 @@
// An XML attribute/value pair defined in the style.
message Entry {
// Where the entry was defined.
- optional Source source = 1;
+ Source source = 1;
// Any comments associated with the entry.
- optional string comment = 2;
+ string comment = 2;
// A reference to the XML attribute.
- optional Reference key = 3;
+ Reference key = 3;
// The Item defined for this XML attribute.
- optional Item item = 4;
+ Item item = 4;
}
// The optinal style from which this style inherits attributes.
- optional Reference parent = 1;
+ Reference parent = 1;
// The source file information of the parent inheritance declaration.
- optional Source parent_source = 2;
+ Source parent_source = 2;
// The set of XML attribute/value pairs for this style.
repeated Entry entry = 3;
@@ -352,13 +366,13 @@
// An attribute defined for this styleable.
message Entry {
// Where the attribute was defined within the <declare-styleable> block.
- optional Source source = 1;
+ Source source = 1;
// Any comments associated with the declaration.
- optional string comment = 2;
+ string comment = 2;
// The reference to the attribute.
- optional Reference attr = 3;
+ Reference attr = 3;
}
// The set of attribute declarations.
@@ -370,13 +384,13 @@
// A single element of the array.
message Element {
// Where the element was defined.
- optional Source source = 1;
+ Source source = 1;
// Any comments associated with the element.
- optional string comment = 2;
+ string comment = 2;
// The value assigned to this element.
- optional Item item = 3;
+ Item item = 3;
}
// The list of array elements.
@@ -398,16 +412,16 @@
// The plural value for a given arity.
message Entry {
// Where the plural was defined.
- optional Source source = 1;
+ Source source = 1;
// Any comments associated with the plural.
- optional string comment = 2;
+ string comment = 2;
// The arity of the plural.
- optional Arity arity = 3;
+ Arity arity = 3;
// The value assigned to this plural.
- optional Item item = 4;
+ Item item = 4;
}
// The set of arity/plural mappings.
@@ -417,14 +431,13 @@
// Defines an abstract XmlNode that must be either an XmlElement, or
// a text node represented by a string.
message XmlNode {
- // If set, this node is an element/tag.
- optional XmlElement element = 1;
-
- // If set, this node is a chunk of text.
- optional string text = 2;
+ oneof node {
+ XmlElement element = 1;
+ string text = 2;
+ }
// Source line and column info.
- optional SourcePosition source = 3;
+ SourcePosition source = 3;
}
// An <element> in an XML document.
@@ -433,10 +446,10 @@
repeated XmlNamespace namespace_declaration = 1;
// The namespace URI of this element.
- optional string namespace_uri = 2;
+ string namespace_uri = 2;
// The name of this element.
- optional string name = 3;
+ string name = 3;
// The attributes of this element.
repeated XmlAttribute attribute = 4;
@@ -447,25 +460,25 @@
// A namespace declaration on an XmlElement (xmlns:android="http://...").
message XmlNamespace {
- optional string prefix = 1;
- optional string uri = 2;
+ string prefix = 1;
+ string uri = 2;
// Source line and column info.
- optional SourcePosition source = 3;
+ SourcePosition source = 3;
}
// An attribute defined on an XmlElement (android:text="...").
message XmlAttribute {
- optional string namespace_uri = 1;
- optional string name = 2;
- optional string value = 3;
+ string namespace_uri = 1;
+ string name = 2;
+ string value = 3;
// Source line and column info.
- optional SourcePosition source = 4;
+ SourcePosition source = 4;
- // The resource ID (0xPPTTEEEE) of the attribute.
- optional uint32 resource_id = 5;
+ // The optional resource ID (0xPPTTEEEE) of the attribute.
+ uint32 resource_id = 5;
- // The interpreted/compiled version of the `value` string.
- optional Item compiled_item = 6;
+ // The optional interpreted/compiled version of the `value` string.
+ Item compiled_item = 6;
}
diff --git a/tools/aapt2/ResourcesInternal.proto b/tools/aapt2/ResourcesInternal.proto
index 3117917..0b0a252 100644
--- a/tools/aapt2/ResourcesInternal.proto
+++ b/tools/aapt2/ResourcesInternal.proto
@@ -14,39 +14,40 @@
* limitations under the License.
*/
-syntax = "proto2";
+syntax = "proto3";
-option java_package = "android.aapt.pb.internal";
-option optimize_for = LITE_RUNTIME;
-
+import "frameworks/base/tools/aapt2/Configuration.proto";
import "frameworks/base/tools/aapt2/Resources.proto";
package aapt.pb.internal;
+option java_package = "android.aapt.pb.internal";
+option optimize_for = LITE_RUNTIME;
+
// The top level message representing an external resource file (layout XML, PNG, etc).
// This is used to represent a compiled file before it is linked. Only useful to aapt2.
message CompiledFile {
message Symbol {
// The name of the symbol (in the form package:type/name).
- optional string resource_name = 1;
+ string resource_name = 1;
// The position in the file at which this symbol is defined. For debug use.
- optional aapt.pb.SourcePosition source = 2;
+ aapt.pb.SourcePosition source = 2;
}
// The name of the resource (in the form package:type/name).
- optional string resource_name = 1;
+ string resource_name = 1;
// The configuration for which the resource is defined.
- optional aapt.pb.ConfigDescription config = 2;
+ aapt.pb.Configuration config = 2;
// The filesystem path to where the source file originated.
// Mainly used to display helpful error messages.
- optional string source_path = 3;
+ string source_path = 3;
// Any symbols this file auto-generates/exports (eg. @+id/foo in an XML file).
repeated Symbol exported_symbol = 4;
// If this is a compiled XML file, this is the root node.
- optional aapt.pb.XmlNode xml_root = 5;
+ aapt.pb.XmlNode xml_root = 5;
}
diff --git a/tools/aapt2/ValueVisitor.h b/tools/aapt2/ValueVisitor.h
index eb4fa49..4e74ec3 100644
--- a/tools/aapt2/ValueVisitor.h
+++ b/tools/aapt2/ValueVisitor.h
@@ -22,12 +22,11 @@
namespace aapt {
-/**
- * Visits a value and invokes the appropriate method based on its type. Does not
- * traverse into compound types. Use ValueVisitor for that.
- */
-struct RawValueVisitor {
- virtual ~RawValueVisitor() = default;
+// Visits a value and invokes the appropriate method based on its type.
+// Does not traverse into compound types. Use ValueVisitor for that.
+class ValueVisitor {
+ public:
+ virtual ~ValueVisitor() = default;
virtual void VisitAny(Value* value) {}
virtual void VisitItem(Item* value) { VisitAny(value); }
@@ -46,21 +45,67 @@
virtual void Visit(Styleable* value) { VisitAny(value); }
};
+// Const version of ValueVisitor.
+class ConstValueVisitor {
+ public:
+ virtual ~ConstValueVisitor() = default;
+
+ virtual void VisitAny(const Value* value) {
+ }
+ virtual void VisitItem(const Item* value) {
+ VisitAny(value);
+ }
+ virtual void Visit(const Reference* value) {
+ VisitItem(value);
+ }
+ virtual void Visit(const RawString* value) {
+ VisitItem(value);
+ }
+ virtual void Visit(const String* value) {
+ VisitItem(value);
+ }
+ virtual void Visit(const StyledString* value) {
+ VisitItem(value);
+ }
+ virtual void Visit(const FileReference* value) {
+ VisitItem(value);
+ }
+ virtual void Visit(const Id* value) {
+ VisitItem(value);
+ }
+ virtual void Visit(const BinaryPrimitive* value) {
+ VisitItem(value);
+ }
+
+ virtual void Visit(const Attribute* value) {
+ VisitAny(value);
+ }
+ virtual void Visit(const Style* value) {
+ VisitAny(value);
+ }
+ virtual void Visit(const Array* value) {
+ VisitAny(value);
+ }
+ virtual void Visit(const Plural* value) {
+ VisitAny(value);
+ }
+ virtual void Visit(const Styleable* value) {
+ VisitAny(value);
+ }
+};
+
// NOLINT, do not add parentheses around T.
#define DECL_VISIT_COMPOUND_VALUE(T) \
virtual void Visit(T* value) override { /* NOLINT */ \
VisitSubValues(value); \
}
-/**
- * Visits values, and if they are compound values, visits the components as
- * well.
- */
-struct ValueVisitor : public RawValueVisitor {
+// Visits values, and if they are compound values, descends into their components as well.
+struct DescendingValueVisitor : public ValueVisitor {
// The compiler will think we're hiding an overload, when we actually intend
// to call into RawValueVisitor. This will expose the visit methods in the
// super class so the compiler knows we are trying to call them.
- using RawValueVisitor::Visit;
+ using ValueVisitor::Visit;
void VisitSubValues(Attribute* attribute) {
for (Attribute::Symbol& symbol : attribute->symbols) {
@@ -106,37 +151,30 @@
DECL_VISIT_COMPOUND_VALUE(Styleable);
};
-/**
- * Do not use directly. Helper struct for dyn_cast.
- */
+// Do not use directly. Helper struct for dyn_cast.
template <typename T>
-struct DynCastVisitor : public RawValueVisitor {
- T* value = nullptr;
+struct DynCastVisitor : public ConstValueVisitor {
+ const T* value = nullptr;
- void Visit(T* v) override { value = v; }
+ void Visit(const T* v) override {
+ value = v;
+ }
};
-/**
- * Specialization that checks if the value is an Item.
- */
+// Specialization that checks if the value is an Item.
template <>
-struct DynCastVisitor<Item> : public RawValueVisitor {
- Item* value = nullptr;
+struct DynCastVisitor<Item> : public ConstValueVisitor {
+ const Item* value = nullptr;
- void VisitItem(Item* item) override { value = item; }
+ void VisitItem(const Item* item) override {
+ value = item;
+ }
};
+// Returns a valid pointer to T if the value is an instance of T. Returns nullptr if value is
+// nullptr of if value is not an instance of T.
template <typename T>
const T* ValueCast(const Value* value) {
- return ValueCast<T>(const_cast<Value*>(value));
-}
-
-/**
- * Returns a valid pointer to T if the Value is of subtype T.
- * Otherwise, returns nullptr.
- */
-template <typename T>
-T* ValueCast(Value* value) {
if (!value) {
return nullptr;
}
@@ -145,8 +183,13 @@
return visitor.value;
}
-inline void VisitAllValuesInPackage(ResourceTablePackage* pkg,
- RawValueVisitor* visitor) {
+// Non-const version of ValueCast.
+template <typename T>
+T* ValueCast(Value* value) {
+ return const_cast<T*>(ValueCast<T>(static_cast<const Value*>(value)));
+}
+
+inline void VisitAllValuesInPackage(ResourceTablePackage* pkg, ValueVisitor* visitor) {
for (auto& type : pkg->types) {
for (auto& entry : type->entries) {
for (auto& config_value : entry->values) {
@@ -156,8 +199,7 @@
}
}
-inline void VisitAllValuesInTable(ResourceTable* table,
- RawValueVisitor* visitor) {
+inline void VisitAllValuesInTable(ResourceTable* table, ValueVisitor* visitor) {
for (auto& pkg : table->packages) {
VisitAllValuesInPackage(pkg.get(), visitor);
}
diff --git a/tools/aapt2/ValueVisitor_test.cpp b/tools/aapt2/ValueVisitor_test.cpp
index eb75b10..5aea77d 100644
--- a/tools/aapt2/ValueVisitor_test.cpp
+++ b/tools/aapt2/ValueVisitor_test.cpp
@@ -24,16 +24,16 @@
namespace aapt {
-struct SingleReferenceVisitor : public ValueVisitor {
- using ValueVisitor::Visit;
+struct SingleReferenceVisitor : public DescendingValueVisitor {
+ using DescendingValueVisitor::Visit;
Reference* visited = nullptr;
void Visit(Reference* ref) override { visited = ref; }
};
-struct StyleVisitor : public ValueVisitor {
- using ValueVisitor::Visit;
+struct StyleVisitor : public DescendingValueVisitor {
+ using DescendingValueVisitor::Visit;
std::list<Reference*> visited_refs;
Style* visited_style = nullptr;
@@ -42,7 +42,7 @@
void Visit(Style* style) override {
visited_style = style;
- ValueVisitor::Visit(style);
+ DescendingValueVisitor::Visit(style);
}
};
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 7f5bbf0..0690dc1 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -248,8 +248,9 @@
// ZeroCopyOutputStream interface.
CopyingOutputStreamAdaptor copying_adaptor(writer);
- std::unique_ptr<pb::ResourceTable> pb_table = SerializeTableToPb(&table);
- if (!pb_table->SerializeToZeroCopyStream(©ing_adaptor)) {
+ pb::ResourceTable pb_table;
+ SerializeTableToPb(table, &pb_table);
+ if (!pb_table.SerializeToZeroCopyStream(©ing_adaptor)) {
context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write");
return false;
}
@@ -282,9 +283,10 @@
// Number of CompiledFiles.
output_stream.WriteLittleEndian32(1);
- std::unique_ptr<pb::internal::CompiledFile> compiled_file = SerializeCompiledFileToPb(file);
- output_stream.WriteCompiledFile(compiled_file.get());
- output_stream.WriteData(&buffer);
+ pb::internal::CompiledFile pb_compiled_file;
+ SerializeCompiledFileToPb(file, &pb_compiled_file);
+ output_stream.WriteCompiledFile(pb_compiled_file);
+ output_stream.WriteData(buffer);
if (output_stream.HadError()) {
diag->Error(DiagMessage(output_path) << "failed to write data");
@@ -319,8 +321,9 @@
// Number of CompiledFiles.
output_stream.WriteLittleEndian32(1);
- std::unique_ptr<pb::internal::CompiledFile> compiled_file = SerializeCompiledFileToPb(file);
- output_stream.WriteCompiledFile(compiled_file.get());
+ pb::internal::CompiledFile pb_compiled_file;
+ SerializeCompiledFileToPb(file, &pb_compiled_file);
+ output_stream.WriteCompiledFile(pb_compiled_file);
output_stream.WriteData(map.getDataPtr(), map.getDataLength());
if (output_stream.HadError()) {
@@ -346,13 +349,13 @@
return false;
}
- std::unique_ptr<pb::internal::CompiledFile> pb_compiled_file =
- SerializeCompiledFileToPb(xmlres->file);
- out->WriteCompiledFile(pb_compiled_file.get());
- out->WriteData(&buffer);
+ pb::internal::CompiledFile pb_compiled_file;
+ SerializeCompiledFileToPb(xmlres->file, &pb_compiled_file);
+ out->WriteCompiledFile(pb_compiled_file);
+ out->WriteData(buffer);
if (out->HadError()) {
- context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write data");
+ context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write XML data");
return false;
}
return true;
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index 1a6f348..625c47c 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -22,7 +22,7 @@
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
-using android::StringPiece;
+using ::android::StringPiece;
namespace aapt {
@@ -325,9 +325,9 @@
return diff;
}
-class ZeroingReferenceVisitor : public ValueVisitor {
+class ZeroingReferenceVisitor : public DescendingValueVisitor {
public:
- using ValueVisitor::Visit;
+ using DescendingValueVisitor::Visit;
void Visit(Reference* ref) override {
if (ref->name && ref->id) {
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 0965910..0dedc91 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -23,7 +23,7 @@
#include "Flags.h"
#include "io/ZipArchive.h"
#include "process/IResourceTableConsumer.h"
-#include "proto/ProtoSerialize.h"
+#include "proto/ProtoDeserialize.h"
#include "unflatten/BinaryResourceParser.h"
#include "util/Files.h"
@@ -33,29 +33,28 @@
bool DumpCompiledFile(const pb::internal::CompiledFile& pb_file, const void* data, size_t len,
const Source& source, IAaptContext* context) {
- std::unique_ptr<ResourceFile> file =
- DeserializeCompiledFileFromPb(pb_file, source, context->GetDiagnostics());
- if (!file) {
- context->GetDiagnostics()->Warn(DiagMessage() << "failed to read compiled file");
+ ResourceFile file;
+ std::string error;
+ if (!DeserializeCompiledFileFromPb(pb_file, &file, &error)) {
+ context->GetDiagnostics()->Warn(DiagMessage(source)
+ << "failed to read compiled file: " << error);
return false;
}
- std::cout << "Resource: " << file->name << "\n"
- << "Config: " << file->config << "\n"
- << "Source: " << file->source << "\n";
+ std::cout << "Resource: " << file.name << "\n"
+ << "Config: " << file.config << "\n"
+ << "Source: " << file.source << "\n";
return true;
}
bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
- std::unique_ptr<ResourceTable> table;
-
std::string err;
std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err);
if (zip) {
- io::IFile* file = zip->FindFile("resources.arsc.flat");
- if (file) {
+ ResourceTable table;
+ if (io::IFile* file = zip->FindFile("resources.arsc.flat")) {
std::unique_ptr<io::IData> data = file->OpenAsData();
- if (!data) {
+ if (data == nullptr) {
context->GetDiagnostics()->Error(DiagMessage(file_path)
<< "failed to open resources.arsc.flat");
return false;
@@ -67,83 +66,78 @@
return false;
}
- table = DeserializeTableFromPb(pb_table, Source(file_path), context->GetDiagnostics());
- if (!table) {
+ ResourceTable table;
+ if (!DeserializeTableFromPb(pb_table, &table, &err)) {
+ context->GetDiagnostics()->Error(DiagMessage(file_path)
+ << "failed to parse table: " << err);
+ return false;
+ }
+ } else if (io::IFile* file = zip->FindFile("resources.arsc")) {
+ std::unique_ptr<io::IData> data = file->OpenAsData();
+ if (!data) {
+ context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.arsc");
+ return false;
+ }
+
+ BinaryResourceParser parser(context, &table, Source(file_path), data->data(), data->size());
+ if (!parser.Parse()) {
return false;
}
}
- if (!table) {
- file = zip->FindFile("resources.arsc");
- if (file) {
- std::unique_ptr<io::IData> data = file->OpenAsData();
- if (!data) {
- context->GetDiagnostics()->Error(DiagMessage(file_path)
- << "failed to open resources.arsc");
- return false;
- }
+ DebugPrintTableOptions options;
+ options.show_sources = true;
+ Debug::PrintTable(&table, options);
+ return true;
+ }
- table = util::make_unique<ResourceTable>();
- BinaryResourceParser parser(context, table.get(), Source(file_path), data->data(),
- data->size());
- if (!parser.Parse()) {
- return false;
- }
- }
+ err.clear();
+
+ Maybe<android::FileMap> file = file::MmapPath(file_path, &err);
+ if (!file) {
+ context->GetDiagnostics()->Error(DiagMessage(file_path) << err);
+ return false;
+ }
+
+ android::FileMap* file_map = &file.value();
+
+ // Check to see if this is a loose ResourceTable.
+ pb::ResourceTable pb_table;
+ if (pb_table.ParseFromArray(file_map->getDataPtr(), file_map->getDataLength())) {
+ ResourceTable table;
+ if (DeserializeTableFromPb(pb_table, &table, &err)) {
+ DebugPrintTableOptions options;
+ options.show_sources = true;
+ Debug::PrintTable(&table, options);
+ return true;
}
}
- if (!table) {
- Maybe<android::FileMap> file = file::MmapPath(file_path, &err);
- if (!file) {
- context->GetDiagnostics()->Error(DiagMessage(file_path) << err);
+ // Try as a compiled file.
+ CompiledFileInputStream input(file_map->getDataPtr(), file_map->getDataLength());
+ uint32_t num_files = 0;
+ if (!input.ReadLittleEndian32(&num_files)) {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < num_files; i++) {
+ pb::internal::CompiledFile compiled_file;
+ if (!input.ReadCompiledFile(&compiled_file)) {
+ context->GetDiagnostics()->Warn(DiagMessage() << "failed to read compiled file");
return false;
}
- android::FileMap* file_map = &file.value();
-
- // Try as a compiled table.
- pb::ResourceTable pb_table;
- if (pb_table.ParseFromArray(file_map->getDataPtr(), file_map->getDataLength())) {
- table = DeserializeTableFromPb(pb_table, Source(file_path), context->GetDiagnostics());
+ uint64_t offset, len;
+ if (!input.ReadDataMetaData(&offset, &len)) {
+ context->GetDiagnostics()->Warn(DiagMessage() << "failed to read meta data");
+ return false;
}
- if (!table) {
- // Try as a compiled file.
- CompiledFileInputStream input(file_map->getDataPtr(), file_map->getDataLength());
-
- uint32_t num_files = 0;
- if (!input.ReadLittleEndian32(&num_files)) {
- return false;
- }
-
- for (uint32_t i = 0; i < num_files; i++) {
- pb::internal::CompiledFile compiled_file;
- if (!input.ReadCompiledFile(&compiled_file)) {
- context->GetDiagnostics()->Warn(DiagMessage() << "failed to read compiled file");
- return false;
- }
-
- uint64_t offset, len;
- if (!input.ReadDataMetaData(&offset, &len)) {
- context->GetDiagnostics()->Warn(DiagMessage() << "failed to read meta data");
- return false;
- }
-
- const void* data = static_cast<const uint8_t*>(file_map->getDataPtr()) + offset;
- if (!DumpCompiledFile(compiled_file, data, len, Source(file_path), context)) {
- return false;
- }
- }
+ const void* data = static_cast<const uint8_t*>(file_map->getDataPtr()) + offset;
+ if (!DumpCompiledFile(compiled_file, data, len, Source(file_path), context)) {
+ return false;
}
}
-
- if (table) {
- DebugPrintTableOptions options;
- options.show_sources = true;
- Debug::PrintTable(table.get(), options);
- }
-
return true;
}
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 3a2faa9..f72069c 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -33,6 +33,8 @@
#include "Locale.h"
#include "NameMangler.h"
#include "ResourceUtils.h"
+#include "ResourceValues.h"
+#include "ValueVisitor.h"
#include "cmd/Util.h"
#include "compile/IdAssigner.h"
#include "filter/ConfigFilter.h"
@@ -56,6 +58,7 @@
#include "optimize/VersionCollapser.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
+#include "proto/ProtoDeserialize.h"
#include "proto/ProtoSerialize.h"
#include "split/TableSplitter.h"
#include "unflatten/BinaryResourceParser.h"
@@ -279,8 +282,10 @@
return {};
}
- std::unique_ptr<ResourceTable> table = DeserializeTableFromPb(pb_table, source, diag);
- if (!table) {
+ std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
+ std::string error;
+ if (!DeserializeTableFromPb(pb_table, table.get(), &error)) {
+ diag->Error(DiagMessage(source) << "invalid compiled table: " << error);
return {};
}
return table;
@@ -915,8 +920,9 @@
}
bool FlattenTableToPb(ResourceTable* table, IArchiveWriter* writer) {
- std::unique_ptr<pb::ResourceTable> pb_table = SerializeTableToPb(table);
- return io::CopyProtoToArchive(context_, pb_table.get(), "resources.arsc.flat", 0, writer);
+ pb::ResourceTable pb_table;
+ SerializeTableToPb(*table, &pb_table);
+ return io::CopyProtoToArchive(context_, &pb_table, "resources.arsc.flat", 0, writer);
}
bool WriteJavaFile(ResourceTable* table, const StringPiece& package_name_to_generate,
@@ -1395,14 +1401,15 @@
return false;
}
- std::unique_ptr<ResourceFile> resource_file = DeserializeCompiledFileFromPb(
- compiled_file, file->GetSource(), context_->GetDiagnostics());
- if (!resource_file) {
+ ResourceFile resource_file;
+ std::string error;
+ if (!DeserializeCompiledFileFromPb(compiled_file, &resource_file, &error)) {
+ context_->GetDiagnostics()->Error(DiagMessage(src)
+ << "failed to read compiled header: " << error);
return false;
}
- if (!MergeCompiledFile(file->CreateFileSegment(offset, len), resource_file.get(),
- override)) {
+ if (!MergeCompiledFile(file->CreateFileSegment(offset, len), &resource_file, override)) {
return false;
}
}
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 33a1d3a..704faee 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -18,6 +18,7 @@
#include <vector>
#include "android-base/stringprintf.h"
+
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp
index 871ed4f..36c24bc 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -24,8 +24,8 @@
#include "compile/Pseudolocalizer.h"
#include "util/Util.h"
-using android::StringPiece;
-using android::StringPiece16;
+using ::android::StringPiece;
+using ::android::StringPiece16;
namespace aapt {
@@ -215,7 +215,7 @@
namespace {
-class Visitor : public RawValueVisitor {
+class Visitor : public ValueVisitor {
public:
// Either value or item will be populated upon visiting the value.
std::unique_ptr<Value> value;
diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp
index 14b776b..097727c 100644
--- a/tools/aapt2/flatten/TableFlattener.cpp
+++ b/tools/aapt2/flatten/TableFlattener.cpp
@@ -76,9 +76,9 @@
uint32_t entry_key;
};
-class MapFlattenVisitor : public RawValueVisitor {
+class MapFlattenVisitor : public ValueVisitor {
public:
- using RawValueVisitor::Visit;
+ using ValueVisitor::Visit;
MapFlattenVisitor(ResTable_entry_ext* out_entry, BigBuffer* buffer)
: out_entry_(out_entry), buffer_(buffer) {}
diff --git a/tools/aapt2/java/ClassDefinition.cpp b/tools/aapt2/java/ClassDefinition.cpp
index 6ad0dd6..0c57e7e 100644
--- a/tools/aapt2/java/ClassDefinition.cpp
+++ b/tools/aapt2/java/ClassDefinition.cpp
@@ -41,18 +41,21 @@
ClassDefinition::Result ClassDefinition::AddMember(std::unique_ptr<ClassMember> member) {
Result result = Result::kAdded;
- auto iter = members_.find(member);
- if (iter != members_.end()) {
- members_.erase(iter);
+ auto iter = indexed_members_.find(member->GetName());
+ if (iter != indexed_members_.end()) {
+ // Overwrite the entry.
+ ordered_members_[iter->second].reset();
result = Result::kOverridden;
}
- members_.insert(std::move(member));
+
+ indexed_members_[member->GetName()] = ordered_members_.size();
+ ordered_members_.push_back(std::move(member));
return result;
}
bool ClassDefinition::empty() const {
- for (const std::unique_ptr<ClassMember>& member : members_) {
- if (!member->empty()) {
+ for (const std::unique_ptr<ClassMember>& member : ordered_members_) {
+ if (member != nullptr && !member->empty()) {
return false;
}
}
@@ -61,7 +64,7 @@
void ClassDefinition::WriteToStream(const StringPiece& prefix, bool final,
std::ostream* out) const {
- if (members_.empty() && !create_if_empty_) {
+ if (empty() && !create_if_empty_) {
return;
}
@@ -76,9 +79,14 @@
std::string new_prefix = prefix.to_string();
new_prefix.append(kIndent);
- for (const std::unique_ptr<ClassMember>& member : members_) {
- member->WriteToStream(new_prefix, final, out);
- *out << "\n";
+ for (const std::unique_ptr<ClassMember>& member : ordered_members_) {
+ // There can be nullptr members when a member is added to the ClassDefinition
+ // and takes precedence over a previous member with the same name. The overridden member is
+ // set to nullptr.
+ if (member != nullptr) {
+ member->WriteToStream(new_prefix, final, out);
+ *out << "\n";
+ }
}
*out << prefix << "}";
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
index 6c4bcad..28a3489 100644
--- a/tools/aapt2/java/ClassDefinition.h
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -18,8 +18,9 @@
#define AAPT_JAVA_CLASSDEFINITION_H
#include <ostream>
-#include <set>
#include <string>
+#include <unordered_map>
+#include <vector>
#include "android-base/macros.h"
#include "androidfw/StringPiece.h"
@@ -73,21 +74,18 @@
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override {
ClassMember::WriteToStream(prefix, final, out);
-
- *out << prefix << "public static " << (final ? "final " : "") << "int "
- << name_ << "=" << val_ << ";";
+ *out << prefix << "public static " << (final ? "final " : "") << "int " << name_ << "=" << val_
+ << ";";
}
private:
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
+
std::string name_;
T val_;
-
- DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
};
-/**
- * Specialization for strings so they get the right type and are quoted with "".
- */
+// Specialization for strings so they get the right type and are quoted with "".
template <>
class PrimitiveMember<std::string> : public ClassMember {
public:
@@ -111,10 +109,10 @@
}
private:
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
+
std::string name_;
std::string val_;
-
- DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
};
using IntMember = PrimitiveMember<uint32_t>;
@@ -160,10 +158,10 @@
}
private:
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
+
std::string name_;
std::vector<T> elements_;
-
- DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
};
using ResourceArrayMember = PrimitiveArrayMember<ResourceId>;
@@ -185,12 +183,16 @@
}
// Even if the method is empty, we always want to write the method signature.
- bool empty() const override { return false; }
+ bool empty() const override {
+ return false;
+ }
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override;
private:
+ DISALLOW_COPY_AND_ASSIGN(MethodDefinition);
+
std::string signature_;
std::vector<std::string> statements_;
};
@@ -222,19 +224,13 @@
std::ostream* out) const override;
private:
- struct ClassMemberCompare {
- using T = std::unique_ptr<ClassMember>;
- bool operator()(const T& a, const T& b) const {
- return a->GetName() < b->GetName();
- }
- };
+ DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
std::string name_;
ClassQualifier qualifier_;
bool create_if_empty_;
- std::set<std::unique_ptr<ClassMember>, ClassMemberCompare> members_;
-
- DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
+ std::vector<std::unique_ptr<ClassMember>> ordered_members_;
+ std::unordered_map<android::StringPiece, size_t> indexed_members_;
};
} // namespace aapt
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index 4f449f0..668e434 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -24,6 +24,8 @@
using ::android::StringPiece;
using ::testing::HasSubstr;
+using ::testing::Lt;
+using ::testing::Ne;
using ::testing::Not;
namespace aapt {
@@ -306,6 +308,53 @@
EXPECT_THAT(output, HasSubstr(styleable.GetComment()));
}
+TEST(JavaClassGeneratorTest, StyleableAndIndicesAreColocated) {
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("android", 0x01)
+ .AddValue("android:attr/layout_gravity", util::make_unique<Attribute>())
+ .AddValue("android:attr/background", util::make_unique<Attribute>())
+ .AddValue("android:styleable/ActionBar",
+ test::StyleableBuilder()
+ .AddItem("android:attr/background", ResourceId(0x01010000))
+ .Build())
+ .AddValue("android:styleable/ActionBar.LayoutParams",
+ test::StyleableBuilder()
+ .AddItem("android:attr/layout_gravity", ResourceId(0x01010001))
+ .Build())
+ .Build();
+
+ std::unique_ptr<IAaptContext> context =
+ test::ContextBuilder()
+ .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+ .SetNameManglerPolicy(NameManglerPolicy{"android"})
+ .Build();
+
+ JavaClassGeneratorOptions options;
+ JavaClassGenerator generator(context.get(), table.get(), {});
+ std::stringstream out;
+ ASSERT_TRUE(generator.Generate("android", &out));
+ std::string output = out.str();
+
+ std::string::size_type actionbar_pos = output.find("int[] ActionBar");
+ ASSERT_THAT(actionbar_pos, Ne(std::string::npos));
+
+ std::string::size_type actionbar_background_pos = output.find("int ActionBar_background");
+ ASSERT_THAT(actionbar_background_pos, Ne(std::string::npos));
+
+ std::string::size_type actionbar_layout_params_pos = output.find("int[] ActionBar_LayoutParams");
+ ASSERT_THAT(actionbar_layout_params_pos, Ne(std::string::npos));
+
+ std::string::size_type actionbar_layout_params_layout_gravity_pos =
+ output.find("int ActionBar_LayoutParams_layout_gravity");
+ ASSERT_THAT(actionbar_layout_params_layout_gravity_pos, Ne(std::string::npos));
+
+ EXPECT_THAT(actionbar_pos, Lt(actionbar_background_pos));
+ EXPECT_THAT(actionbar_pos, Lt(actionbar_layout_params_pos));
+ EXPECT_THAT(actionbar_background_pos, Lt(actionbar_layout_params_pos));
+ EXPECT_THAT(actionbar_layout_params_pos, Lt(actionbar_layout_params_layout_gravity_pos));
+}
+
TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) {
Attribute attr(false);
attr.SetComment(StringPiece("removed"));
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index 71e828b..ad7d8b6 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -42,9 +42,9 @@
// to the reference object.
//
// NOTE: All of the entries in the ResourceTable must be assigned IDs.
-class ReferenceLinkerVisitor : public ValueVisitor {
+class ReferenceLinkerVisitor : public DescendingValueVisitor {
public:
- using ValueVisitor::Visit;
+ using DescendingValueVisitor::Visit;
ReferenceLinkerVisitor(const CallSite& callsite, IAaptContext* context, SymbolTable* symbols,
StringPool* string_pool, xml::IPackageDeclStack* decl)
diff --git a/tools/aapt2/link/ReferenceLinker.h b/tools/aapt2/link/ReferenceLinker.h
index 3b11bee..b0b4945 100644
--- a/tools/aapt2/link/ReferenceLinker.h
+++ b/tools/aapt2/link/ReferenceLinker.h
@@ -21,7 +21,6 @@
#include "Resource.h"
#include "ResourceValues.h"
-#include "ValueVisitor.h"
#include "link/Linkers.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp
index 6ebb80f..8852c8e 100644
--- a/tools/aapt2/link/XmlReferenceLinker.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker.cpp
@@ -21,6 +21,7 @@
#include "Diagnostics.h"
#include "ResourceUtils.h"
#include "SdkConstants.h"
+#include "ValueVisitor.h"
#include "link/ReferenceLinker.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
@@ -34,9 +35,9 @@
// Visits all references (including parents of styles, references in styles, arrays, etc) and
// links their symbolic name to their Resource ID, performing mangling and package aliasing
// as needed.
-class ReferenceVisitor : public ValueVisitor {
+class ReferenceVisitor : public DescendingValueVisitor {
public:
- using ValueVisitor::Visit;
+ using DescendingValueVisitor::Visit;
ReferenceVisitor(const CallSite& callsite, IAaptContext* context, SymbolTable* symbols,
xml::IPackageDeclStack* decls)
diff --git a/tools/aapt2/proto/ProtoDeserialize.cpp b/tools/aapt2/proto/ProtoDeserialize.cpp
new file mode 100644
index 0000000..dc13881
--- /dev/null
+++ b/tools/aapt2/proto/ProtoDeserialize.cpp
@@ -0,0 +1,918 @@
+/*
+ * 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 "proto/ProtoDeserialize.h"
+
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+#include "androidfw/ResourceTypes.h"
+
+#include "Locale.h"
+#include "ResourceTable.h"
+#include "ResourceUtils.h"
+#include "ValueVisitor.h"
+
+using ::android::ResStringPool;
+using ::google::protobuf::io::CodedInputStream;
+
+namespace aapt {
+
+namespace {
+
+class ReferenceIdToNameVisitor : public DescendingValueVisitor {
+ public:
+ using DescendingValueVisitor::Visit;
+
+ explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping)
+ : mapping_(mapping) {
+ CHECK(mapping_ != nullptr);
+ }
+
+ void Visit(Reference* reference) override {
+ if (!reference->id || !reference->id.value().is_valid()) {
+ return;
+ }
+
+ ResourceId id = reference->id.value();
+ auto cache_iter = mapping_->find(id);
+ if (cache_iter != mapping_->end()) {
+ reference->name = cache_iter->second.ToResourceName();
+ }
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ReferenceIdToNameVisitor);
+
+ const std::map<ResourceId, ResourceNameRef>* mapping_;
+};
+
+} // namespace
+
+bool DeserializeConfigFromPb(const pb::Configuration& pb_config, ConfigDescription* out_config,
+ std::string* out_error) {
+ out_config->mcc = static_cast<uint16_t>(pb_config.mcc());
+ out_config->mnc = static_cast<uint16_t>(pb_config.mnc());
+
+ if (!pb_config.locale().empty()) {
+ LocaleValue lv;
+ if (!lv.InitFromBcp47Tag(pb_config.locale())) {
+ std::ostringstream error;
+ error << "configuration has invalid locale '" << pb_config.locale() << "'";
+ *out_error = error.str();
+ return false;
+ }
+ lv.WriteTo(out_config);
+ }
+
+ switch (pb_config.layout_direction()) {
+ case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR:
+ out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) |
+ ConfigDescription::LAYOUTDIR_LTR;
+ break;
+
+ case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL:
+ out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) |
+ ConfigDescription::LAYOUTDIR_RTL;
+ break;
+
+ default:
+ break;
+ }
+
+ out_config->smallestScreenWidthDp = static_cast<uint16_t>(pb_config.smallest_screen_width_dp());
+ out_config->screenWidthDp = static_cast<uint16_t>(pb_config.screen_width_dp());
+ out_config->screenHeightDp = static_cast<uint16_t>(pb_config.screen_height_dp());
+
+ switch (pb_config.screen_layout_size()) {
+ case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL:
+ out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
+ ConfigDescription::SCREENSIZE_SMALL;
+ break;
+
+ case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL:
+ out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
+ ConfigDescription::SCREENSIZE_NORMAL;
+ break;
+
+ case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE:
+ out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
+ ConfigDescription::SCREENSIZE_LARGE;
+ break;
+
+ case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE:
+ out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
+ ConfigDescription::SCREENSIZE_XLARGE;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (pb_config.screen_layout_long()) {
+ case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG:
+ out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) |
+ ConfigDescription::SCREENLONG_YES;
+ break;
+
+ case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG:
+ out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) |
+ ConfigDescription::SCREENLONG_NO;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (pb_config.screen_round()) {
+ case pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND:
+ out_config->screenLayout2 =
+ (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) |
+ ConfigDescription::SCREENROUND_YES;
+ break;
+
+ case pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND:
+ out_config->screenLayout2 =
+ (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) |
+ ConfigDescription::SCREENROUND_NO;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (pb_config.wide_color_gamut()) {
+ case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG:
+ out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) |
+ ConfigDescription::WIDE_COLOR_GAMUT_YES;
+ break;
+
+ case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG:
+ out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) |
+ ConfigDescription::WIDE_COLOR_GAMUT_NO;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (pb_config.hdr()) {
+ case pb::Configuration_Hdr_HDR_HIGHDR:
+ out_config->colorMode =
+ (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_YES;
+ break;
+
+ case pb::Configuration_Hdr_HDR_LOWDR:
+ out_config->colorMode =
+ (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_NO;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (pb_config.orientation()) {
+ case pb::Configuration_Orientation_ORIENTATION_PORT:
+ out_config->orientation = ConfigDescription::ORIENTATION_PORT;
+ break;
+
+ case pb::Configuration_Orientation_ORIENTATION_LAND:
+ out_config->orientation = ConfigDescription::ORIENTATION_LAND;
+ break;
+
+ case pb::Configuration_Orientation_ORIENTATION_SQUARE:
+ out_config->orientation = ConfigDescription::ORIENTATION_SQUARE;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (pb_config.ui_mode_type()) {
+ case pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL:
+ out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
+ ConfigDescription::UI_MODE_TYPE_NORMAL;
+ break;
+
+ case pb::Configuration_UiModeType_UI_MODE_TYPE_DESK:
+ out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
+ ConfigDescription::UI_MODE_TYPE_DESK;
+ break;
+
+ case pb::Configuration_UiModeType_UI_MODE_TYPE_CAR:
+ out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
+ ConfigDescription::UI_MODE_TYPE_CAR;
+ break;
+
+ case pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION:
+ out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
+ ConfigDescription::UI_MODE_TYPE_TELEVISION;
+ break;
+
+ case pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE:
+ out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
+ ConfigDescription::UI_MODE_TYPE_APPLIANCE;
+ break;
+
+ case pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH:
+ out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
+ ConfigDescription::UI_MODE_TYPE_WATCH;
+ break;
+
+ case pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET:
+ out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
+ ConfigDescription::UI_MODE_TYPE_VR_HEADSET;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (pb_config.ui_mode_night()) {
+ case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT:
+ out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) |
+ ConfigDescription::UI_MODE_NIGHT_YES;
+ break;
+
+ case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT:
+ out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) |
+ ConfigDescription::UI_MODE_NIGHT_NO;
+ break;
+
+ default:
+ break;
+ }
+
+ out_config->density = static_cast<uint16_t>(pb_config.density());
+
+ switch (pb_config.touchscreen()) {
+ case pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH:
+ out_config->touchscreen = ConfigDescription::TOUCHSCREEN_NOTOUCH;
+ break;
+
+ case pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS:
+ out_config->touchscreen = ConfigDescription::TOUCHSCREEN_STYLUS;
+ break;
+
+ case pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER:
+ out_config->touchscreen = ConfigDescription::TOUCHSCREEN_FINGER;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (pb_config.keys_hidden()) {
+ case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED:
+ out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) |
+ ConfigDescription::KEYSHIDDEN_NO;
+ break;
+
+ case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN:
+ out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) |
+ ConfigDescription::KEYSHIDDEN_YES;
+ break;
+
+ case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT:
+ out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) |
+ ConfigDescription::KEYSHIDDEN_SOFT;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (pb_config.keyboard()) {
+ case pb::Configuration_Keyboard_KEYBOARD_NOKEYS:
+ out_config->keyboard = ConfigDescription::KEYBOARD_NOKEYS;
+ break;
+
+ case pb::Configuration_Keyboard_KEYBOARD_QWERTY:
+ out_config->keyboard = ConfigDescription::KEYBOARD_QWERTY;
+ break;
+
+ case pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY:
+ out_config->keyboard = ConfigDescription::KEYBOARD_12KEY;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (pb_config.nav_hidden()) {
+ case pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED:
+ out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) |
+ ConfigDescription::NAVHIDDEN_NO;
+ break;
+
+ case pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN:
+ out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) |
+ ConfigDescription::NAVHIDDEN_YES;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (pb_config.navigation()) {
+ case pb::Configuration_Navigation_NAVIGATION_NONAV:
+ out_config->navigation = ConfigDescription::NAVIGATION_NONAV;
+ break;
+
+ case pb::Configuration_Navigation_NAVIGATION_DPAD:
+ out_config->navigation = ConfigDescription::NAVIGATION_DPAD;
+ break;
+
+ case pb::Configuration_Navigation_NAVIGATION_TRACKBALL:
+ out_config->navigation = ConfigDescription::NAVIGATION_TRACKBALL;
+ break;
+
+ case pb::Configuration_Navigation_NAVIGATION_WHEEL:
+ out_config->navigation = ConfigDescription::NAVIGATION_WHEEL;
+ break;
+
+ default:
+ break;
+ }
+
+ out_config->screenWidth = static_cast<uint16_t>(pb_config.screen_width());
+ out_config->screenHeight = static_cast<uint16_t>(pb_config.screen_height());
+ out_config->sdkVersion = static_cast<uint16_t>(pb_config.sdk_version());
+ return true;
+}
+
+static void DeserializeSourceFromPb(const pb::Source& pb_source, const ResStringPool& src_pool,
+ Source* out_source) {
+ out_source->path = util::GetString(src_pool, pb_source.path_idx());
+ out_source->line = static_cast<size_t>(pb_source.position().line_number());
+}
+
+static SymbolState DeserializeVisibilityFromPb(const pb::SymbolStatus_Visibility& pb_visibility) {
+ switch (pb_visibility) {
+ case pb::SymbolStatus_Visibility_PRIVATE:
+ return SymbolState::kPrivate;
+ case pb::SymbolStatus_Visibility_PUBLIC:
+ return SymbolState::kPublic;
+ default:
+ break;
+ }
+ return SymbolState::kUndefined;
+}
+
+static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStringPool& src_pool,
+ ResourceTable* out_table, std::string* out_error) {
+ Maybe<uint8_t> id;
+ if (pb_package.has_package_id()) {
+ id = static_cast<uint8_t>(pb_package.package_id().id());
+ }
+
+ std::map<ResourceId, ResourceNameRef> id_index;
+
+ ResourceTablePackage* pkg = out_table->CreatePackage(pb_package.package_name(), id);
+ for (const pb::Type& pb_type : pb_package.type()) {
+ const ResourceType* res_type = ParseResourceType(pb_type.name());
+ if (res_type == nullptr) {
+ std::ostringstream error;
+ error << "unknown type '" << pb_type.name() << "'";
+ *out_error = error.str();
+ return false;
+ }
+
+ ResourceTableType* type = pkg->FindOrCreateType(*res_type);
+ for (const pb::Entry& pb_entry : pb_type.entry()) {
+ ResourceEntry* entry = type->FindOrCreateEntry(pb_entry.name());
+
+ // Deserialize the symbol status (public/private with source and comments).
+ if (pb_entry.has_symbol_status()) {
+ const pb::SymbolStatus& pb_status = pb_entry.symbol_status();
+ if (pb_status.has_source()) {
+ DeserializeSourceFromPb(pb_status.source(), src_pool, &entry->symbol_status.source);
+ }
+
+ entry->symbol_status.comment = pb_status.comment();
+ entry->symbol_status.allow_new = pb_status.allow_new();
+
+ const SymbolState visibility = DeserializeVisibilityFromPb(pb_status.visibility());
+ entry->symbol_status.state = visibility;
+
+ if (visibility == SymbolState::kPublic) {
+ // This is a public symbol, we must encode the ID now if there is one.
+ if (pb_entry.has_entry_id()) {
+ entry->id = static_cast<uint16_t>(pb_entry.entry_id().id());
+ }
+
+ if (type->symbol_status.state != SymbolState::kPublic) {
+ // If the type has not been made public, do so now.
+ type->symbol_status.state = SymbolState::kPublic;
+ if (pb_type.has_type_id()) {
+ type->id = static_cast<uint8_t>(pb_type.type_id().id());
+ }
+ }
+ } else if (visibility == SymbolState::kPrivate) {
+ if (type->symbol_status.state == SymbolState::kUndefined) {
+ type->symbol_status.state = SymbolState::kPrivate;
+ }
+ }
+ }
+
+ ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(),
+ pb_entry.entry_id().id());
+ if (resid.is_valid()) {
+ id_index[resid] = ResourceNameRef(pkg->name, type->type, entry->name);
+ }
+
+ for (const pb::ConfigValue& pb_config_value : pb_entry.config_value()) {
+ const pb::Configuration& pb_config = pb_config_value.config();
+
+ ConfigDescription config;
+ if (!DeserializeConfigFromPb(pb_config, &config, out_error)) {
+ return false;
+ }
+
+ ResourceConfigValue* config_value = entry->FindOrCreateValue(config, pb_config.product());
+ if (config_value->value != nullptr) {
+ *out_error = "duplicate configuration in resource table";
+ return false;
+ }
+
+ config_value->value = DeserializeValueFromPb(pb_config_value.value(), src_pool, config,
+ &out_table->string_pool, out_error);
+ if (config_value->value == nullptr) {
+ return false;
+ }
+ }
+ }
+ }
+
+ ReferenceIdToNameVisitor visitor(&id_index);
+ VisitAllValuesInPackage(pkg, &visitor);
+ return true;
+}
+
+bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, ResourceTable* out_table,
+ std::string* out_error) {
+ // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which
+ // causes errors when qualifying it with android::
+ using namespace android;
+
+ ResStringPool source_pool;
+ if (pb_table.has_source_pool()) {
+ status_t result = source_pool.setTo(pb_table.source_pool().data().data(),
+ pb_table.source_pool().data().size());
+ if (result != NO_ERROR) {
+ *out_error = "invalid source pool";
+ return false;
+ }
+ }
+
+ for (const pb::Package& pb_package : pb_table.package()) {
+ if (!DeserializePackageFromPb(pb_package, source_pool, out_table, out_error)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool DeserializeCompiledFileFromPb(const pb::internal::CompiledFile& pb_file,
+ ResourceFile* out_file, std::string* out_error) {
+ ResourceNameRef name_ref;
+ if (!ResourceUtils::ParseResourceName(pb_file.resource_name(), &name_ref)) {
+ std::ostringstream error;
+ error << "invalid resource name in compiled file header: " << pb_file.resource_name();
+ *out_error = error.str();
+ return false;
+ }
+
+ out_file->name = name_ref.ToResourceName();
+ out_file->source.path = pb_file.source_path();
+
+ std::string config_error;
+ if (!DeserializeConfigFromPb(pb_file.config(), &out_file->config, &config_error)) {
+ std::ostringstream error;
+ error << "invalid resource configuration in compiled file header: " << config_error;
+ *out_error = error.str();
+ return false;
+ }
+
+ for (const pb::internal::CompiledFile_Symbol& pb_symbol : pb_file.exported_symbol()) {
+ if (!ResourceUtils::ParseResourceName(pb_symbol.resource_name(), &name_ref)) {
+ std::ostringstream error;
+ error << "invalid resource name for exported symbol in compiled file header: "
+ << pb_file.resource_name();
+ *out_error = error.str();
+ return false;
+ }
+
+ size_t line = 0u;
+ if (pb_symbol.has_source()) {
+ line = pb_symbol.source().line_number();
+ }
+ out_file->exported_symbols.push_back(SourcedResourceName{name_ref.ToResourceName(), line});
+ }
+ return true;
+}
+
+static Reference::Type DeserializeReferenceTypeFromPb(const pb::Reference_Type& pb_type) {
+ switch (pb_type) {
+ case pb::Reference_Type_REFERENCE:
+ return Reference::Type::kResource;
+ case pb::Reference_Type_ATTRIBUTE:
+ return Reference::Type::kAttribute;
+ default:
+ break;
+ }
+ return Reference::Type::kResource;
+}
+
+static bool DeserializeReferenceFromPb(const pb::Reference& pb_ref, Reference* out_ref,
+ std::string* out_error) {
+ out_ref->reference_type = DeserializeReferenceTypeFromPb(pb_ref.type());
+ out_ref->private_reference = pb_ref.private_();
+
+ if (pb_ref.id() != 0) {
+ out_ref->id = ResourceId(pb_ref.id());
+ }
+
+ if (!pb_ref.name().empty()) {
+ ResourceNameRef name_ref;
+ if (!ResourceUtils::ParseResourceName(pb_ref.name(), &name_ref, nullptr)) {
+ std::ostringstream error;
+ error << "reference has invalid resource name '" << pb_ref.name() << "'";
+ *out_error = error.str();
+ return false;
+ }
+ out_ref->name = name_ref.ToResourceName();
+ }
+ return true;
+}
+
+template <typename T>
+static void DeserializeItemMetaDataFromPb(const T& pb_item, const android::ResStringPool& src_pool,
+ Value* out_value) {
+ if (pb_item.has_source()) {
+ Source source;
+ DeserializeSourceFromPb(pb_item.source(), src_pool, &source);
+ out_value->SetSource(std::move(source));
+ }
+ out_value->SetComment(pb_item.comment());
+}
+
+static size_t DeserializePluralEnumFromPb(const pb::Plural_Arity& arity) {
+ switch (arity) {
+ case pb::Plural_Arity_ZERO:
+ return Plural::Zero;
+ case pb::Plural_Arity_ONE:
+ return Plural::One;
+ case pb::Plural_Arity_TWO:
+ return Plural::Two;
+ case pb::Plural_Arity_FEW:
+ return Plural::Few;
+ case pb::Plural_Arity_MANY:
+ return Plural::Many;
+ default:
+ break;
+ }
+ return Plural::Other;
+}
+
+std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
+ const android::ResStringPool& src_pool,
+ const ConfigDescription& config,
+ StringPool* value_pool, std::string* out_error) {
+ std::unique_ptr<Value> value;
+ if (pb_value.has_item()) {
+ value = DeserializeItemFromPb(pb_value.item(), src_pool, config, value_pool, out_error);
+ if (value == nullptr) {
+ return {};
+ }
+
+ } else if (pb_value.has_compound_value()) {
+ const pb::CompoundValue& pb_compound_value = pb_value.compound_value();
+ switch (pb_compound_value.value_case()) {
+ case pb::CompoundValue::kAttr: {
+ const pb::Attribute& pb_attr = pb_compound_value.attr();
+ std::unique_ptr<Attribute> attr = util::make_unique<Attribute>();
+ attr->type_mask = pb_attr.format_flags();
+ attr->min_int = pb_attr.min_int();
+ attr->max_int = pb_attr.max_int();
+ for (const pb::Attribute_Symbol& pb_symbol : pb_attr.symbol()) {
+ Attribute::Symbol symbol;
+ DeserializeItemMetaDataFromPb(pb_symbol, src_pool, &symbol.symbol);
+ if (!DeserializeReferenceFromPb(pb_symbol.name(), &symbol.symbol, out_error)) {
+ return {};
+ }
+ symbol.value = pb_symbol.value();
+ attr->symbols.push_back(std::move(symbol));
+ }
+ value = std::move(attr);
+ } break;
+
+ case pb::CompoundValue::kStyle: {
+ const pb::Style& pb_style = pb_compound_value.style();
+ std::unique_ptr<Style> style = util::make_unique<Style>();
+ if (pb_style.has_parent()) {
+ style->parent = Reference();
+ if (!DeserializeReferenceFromPb(pb_style.parent(), &style->parent.value(), out_error)) {
+ return {};
+ }
+
+ if (pb_style.has_parent_source()) {
+ Source parent_source;
+ DeserializeSourceFromPb(pb_style.parent_source(), src_pool, &parent_source);
+ style->parent.value().SetSource(std::move(parent_source));
+ }
+ }
+
+ for (const pb::Style_Entry& pb_entry : pb_style.entry()) {
+ Style::Entry entry;
+ if (!DeserializeReferenceFromPb(pb_entry.key(), &entry.key, out_error)) {
+ return {};
+ }
+ DeserializeItemMetaDataFromPb(pb_entry, src_pool, &entry.key);
+ entry.value =
+ DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error);
+ if (entry.value == nullptr) {
+ return {};
+ }
+
+ // Copy the meta-data into the value as well.
+ DeserializeItemMetaDataFromPb(pb_entry, src_pool, entry.value.get());
+ style->entries.push_back(std::move(entry));
+ }
+ value = std::move(style);
+ } break;
+
+ case pb::CompoundValue::kStyleable: {
+ const pb::Styleable& pb_styleable = pb_compound_value.styleable();
+ std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
+ for (const pb::Styleable_Entry& pb_entry : pb_styleable.entry()) {
+ Reference attr_ref;
+ DeserializeItemMetaDataFromPb(pb_entry, src_pool, &attr_ref);
+ DeserializeReferenceFromPb(pb_entry.attr(), &attr_ref, out_error);
+ styleable->entries.push_back(std::move(attr_ref));
+ }
+ value = std::move(styleable);
+ } break;
+
+ case pb::CompoundValue::kArray: {
+ const pb::Array& pb_array = pb_compound_value.array();
+ std::unique_ptr<Array> array = util::make_unique<Array>();
+ for (const pb::Array_Element& pb_entry : pb_array.element()) {
+ std::unique_ptr<Item> item =
+ DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error);
+ if (item == nullptr) {
+ return {};
+ }
+
+ DeserializeItemMetaDataFromPb(pb_entry, src_pool, item.get());
+ array->elements.push_back(std::move(item));
+ }
+ value = std::move(array);
+ } break;
+
+ case pb::CompoundValue::kPlural: {
+ const pb::Plural& pb_plural = pb_compound_value.plural();
+ std::unique_ptr<Plural> plural = util::make_unique<Plural>();
+ for (const pb::Plural_Entry& pb_entry : pb_plural.entry()) {
+ size_t plural_idx = DeserializePluralEnumFromPb(pb_entry.arity());
+ plural->values[plural_idx] =
+ DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error);
+ if (!plural->values[plural_idx]) {
+ return {};
+ }
+
+ DeserializeItemMetaDataFromPb(pb_entry, src_pool, plural->values[plural_idx].get());
+ }
+ value = std::move(plural);
+ } break;
+
+ default:
+ LOG(FATAL) << "unknown compound value: " << (int) pb_compound_value.value_case();
+ break;
+ }
+ } else {
+ LOG(FATAL) << "unknown value: " << (int) pb_value.value_case();
+ return {};
+ }
+
+ CHECK(value) << "forgot to set value";
+
+ value->SetWeak(pb_value.weak());
+ DeserializeItemMetaDataFromPb(pb_value, src_pool, value.get());
+ return value;
+}
+
+std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
+ const android::ResStringPool& src_pool,
+ const ConfigDescription& config, StringPool* value_pool,
+ std::string* out_error) {
+ switch (pb_item.value_case()) {
+ case pb::Item::kRef: {
+ const pb::Reference& pb_ref = pb_item.ref();
+ std::unique_ptr<Reference> ref = util::make_unique<Reference>();
+ if (!DeserializeReferenceFromPb(pb_ref, ref.get(), out_error)) {
+ return {};
+ }
+ return std::move(ref);
+ } break;
+
+ case pb::Item::kPrim: {
+ const pb::Primitive& pb_prim = pb_item.prim();
+ return util::make_unique<BinaryPrimitive>(static_cast<uint8_t>(pb_prim.type()),
+ pb_prim.data());
+ } break;
+
+ case pb::Item::kId: {
+ return util::make_unique<Id>();
+ } break;
+
+ case pb::Item::kStr: {
+ return util::make_unique<String>(
+ value_pool->MakeRef(pb_item.str().value(), StringPool::Context(config)));
+ } break;
+
+ case pb::Item::kRawStr: {
+ return util::make_unique<RawString>(
+ value_pool->MakeRef(pb_item.raw_str().value(), StringPool::Context(config)));
+ } break;
+
+ case pb::Item::kStyledStr: {
+ const pb::StyledString& pb_str = pb_item.styled_str();
+ StyleString style_str{pb_str.value()};
+ for (const pb::StyledString::Span& pb_span : pb_str.span()) {
+ style_str.spans.push_back(Span{pb_span.tag(), pb_span.first_char(), pb_span.last_char()});
+ }
+ return util::make_unique<StyledString>(value_pool->MakeRef(
+ style_str, StringPool::Context(StringPool::Context::kNormalPriority, config)));
+ } break;
+
+ case pb::Item::kFile: {
+ return util::make_unique<FileReference>(value_pool->MakeRef(
+ pb_item.file().path(), StringPool::Context(StringPool::Context::kHighPriority, config)));
+ } break;
+
+ default:
+ LOG(FATAL) << "unknown item: " << (int) pb_item.value_case();
+ break;
+ }
+ return {};
+}
+
+std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode& pb_node,
+ std::string* out_error) {
+ if (!pb_node.has_element()) {
+ return {};
+ }
+
+ std::unique_ptr<xml::XmlResource> resource = util::make_unique<xml::XmlResource>();
+ resource->root = util::make_unique<xml::Element>();
+ if (!DeserializeXmlFromPb(pb_node, resource->root.get(), &resource->string_pool, out_error)) {
+ return {};
+ }
+ return resource;
+}
+
+bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, StringPool* value_pool,
+ std::string* out_error) {
+ const pb::XmlElement& pb_el = pb_node.element();
+ out_el->name = pb_el.name();
+ out_el->namespace_uri = pb_el.namespace_uri();
+ out_el->line_number = pb_node.source().line_number();
+ out_el->column_number = pb_node.source().column_number();
+
+ for (const pb::XmlNamespace& pb_ns : pb_el.namespace_declaration()) {
+ xml::NamespaceDecl decl;
+ decl.uri = pb_ns.uri();
+ decl.prefix = pb_ns.prefix();
+ decl.line_number = pb_ns.source().line_number();
+ decl.column_number = pb_ns.source().column_number();
+ out_el->namespace_decls.push_back(std::move(decl));
+ }
+
+ for (const pb::XmlAttribute& pb_attr : pb_el.attribute()) {
+ xml::Attribute attr;
+ attr.name = pb_attr.name();
+ attr.namespace_uri = pb_attr.namespace_uri();
+ attr.value = pb_attr.value();
+ if (pb_attr.resource_id() != 0u) {
+ attr.compiled_attribute = xml::AaptAttribute{Attribute(), ResourceId(pb_attr.resource_id())};
+ }
+ if (pb_attr.has_compiled_item()) {
+ attr.compiled_value =
+ DeserializeItemFromPb(pb_attr.compiled_item(), {}, {}, value_pool, out_error);
+ if (attr.compiled_value == nullptr) {
+ return {};
+ }
+ attr.compiled_value->SetSource(Source().WithLine(pb_attr.source().line_number()));
+ }
+ out_el->attributes.push_back(std::move(attr));
+ }
+
+ // Deserialize the children.
+ for (const pb::XmlNode& pb_child : pb_el.child()) {
+ switch (pb_child.node_case()) {
+ case pb::XmlNode::NodeCase::kText: {
+ std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>();
+ text->line_number = pb_child.source().line_number();
+ text->column_number = pb_child.source().column_number();
+ text->text = pb_child.text();
+ out_el->AppendChild(std::move(text));
+ } break;
+
+ case pb::XmlNode::NodeCase::kElement: {
+ std::unique_ptr<xml::Element> child_el = util::make_unique<xml::Element>();
+ if (!DeserializeXmlFromPb(pb_child, child_el.get(), value_pool, out_error)) {
+ return false;
+ }
+ out_el->AppendChild(std::move(child_el));
+ } break;
+
+ default:
+ LOG(FATAL) << "unknown XmlNode " << (int) pb_child.node_case();
+ break;
+ }
+ }
+ return true;
+}
+
+CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size)
+ : in_(static_cast<const uint8_t*>(data), size) {
+}
+
+void CompiledFileInputStream::EnsureAlignedRead() {
+ const int overflow = in_.CurrentPosition() % 4;
+ if (overflow > 0) {
+ // Reads are always 4 byte aligned.
+ in_.Skip(4 - overflow);
+ }
+}
+
+bool CompiledFileInputStream::ReadLittleEndian32(uint32_t* out_val) {
+ EnsureAlignedRead();
+ return in_.ReadLittleEndian32(out_val);
+}
+
+bool CompiledFileInputStream::ReadCompiledFile(pb::internal::CompiledFile* out_val) {
+ EnsureAlignedRead();
+
+ google::protobuf::uint64 pb_size = 0u;
+ if (!in_.ReadLittleEndian64(&pb_size)) {
+ return false;
+ }
+
+ CodedInputStream::Limit l = in_.PushLimit(static_cast<int>(pb_size));
+
+ // Check that we haven't tried to read past the end.
+ if (static_cast<uint64_t>(in_.BytesUntilLimit()) != pb_size) {
+ in_.PopLimit(l);
+ in_.PushLimit(0);
+ return false;
+ }
+
+ if (!out_val->ParsePartialFromCodedStream(&in_)) {
+ in_.PopLimit(l);
+ in_.PushLimit(0);
+ return false;
+ }
+
+ in_.PopLimit(l);
+ return true;
+}
+
+bool CompiledFileInputStream::ReadDataMetaData(uint64_t* out_offset, uint64_t* out_len) {
+ EnsureAlignedRead();
+
+ google::protobuf::uint64 pb_size = 0u;
+ if (!in_.ReadLittleEndian64(&pb_size)) {
+ return false;
+ }
+
+ // Check that we aren't trying to read past the end.
+ if (pb_size > static_cast<uint64_t>(in_.BytesUntilLimit())) {
+ in_.PushLimit(0);
+ return false;
+ }
+
+ uint64_t offset = static_cast<uint64_t>(in_.CurrentPosition());
+ if (!in_.Skip(pb_size)) {
+ return false;
+ }
+
+ *out_offset = offset;
+ *out_len = pb_size;
+ return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/proto/ProtoDeserialize.h b/tools/aapt2/proto/ProtoDeserialize.h
new file mode 100644
index 0000000..3d76ea4
--- /dev/null
+++ b/tools/aapt2/proto/ProtoDeserialize.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_PROTO_PROTODESERIALIZE_H
+#define AAPT_PROTO_PROTODESERIALIZE_H
+
+#include "android-base/macros.h"
+#include "androidfw/ResourceTypes.h"
+#include "google/protobuf/io/coded_stream.h"
+
+#include "ConfigDescription.h"
+#include "Configuration.pb.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "Resources.pb.h"
+#include "ResourcesInternal.pb.h"
+#include "StringPool.h"
+#include "xml/XmlDom.h"
+
+namespace aapt {
+
+std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
+ const android::ResStringPool& src_pool,
+ const ConfigDescription& config,
+ StringPool* value_pool, std::string* out_error);
+
+std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
+ const android::ResStringPool& src_pool,
+ const ConfigDescription& config, StringPool* value_pool,
+ std::string* out_error);
+
+std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode& pb_node,
+ std::string* out_error);
+
+bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, StringPool* value_pool,
+ std::string* out_error);
+
+bool DeserializeConfigFromPb(const pb::Configuration& pb_config, ConfigDescription* out_config,
+ std::string* out_error);
+
+bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, ResourceTable* out_table,
+ std::string* out_error);
+
+bool DeserializeCompiledFileFromPb(const pb::internal::CompiledFile& pb_file,
+ ResourceFile* out_file, std::string* out_error);
+
+class CompiledFileInputStream {
+ public:
+ explicit CompiledFileInputStream(const void* data, size_t size);
+
+ bool ReadLittleEndian32(uint32_t* outVal);
+ bool ReadCompiledFile(pb::internal::CompiledFile* outVal);
+ bool ReadDataMetaData(uint64_t* outOffset, uint64_t* outLen);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CompiledFileInputStream);
+
+ void EnsureAlignedRead();
+
+ ::google::protobuf::io::CodedInputStream in_;
+};
+
+} // namespace aapt
+
+#endif /* AAPT_PROTO_PROTODESERIALIZE_H */
diff --git a/tools/aapt2/proto/ProtoHelpers.cpp b/tools/aapt2/proto/ProtoHelpers.cpp
deleted file mode 100644
index aa99c98..0000000
--- a/tools/aapt2/proto/ProtoHelpers.cpp
+++ /dev/null
@@ -1,161 +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.
- */
-
-#include "proto/ProtoHelpers.h"
-
-namespace aapt {
-
-void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool) {
- BigBuffer buffer(1024);
- StringPool::FlattenUtf8(&buffer, pool);
-
- std::string* data = out_pb_pool->mutable_data();
- data->reserve(buffer.size());
-
- size_t offset = 0;
- for (const BigBuffer::Block& block : buffer) {
- data->insert(data->begin() + offset, block.buffer.get(), block.buffer.get() + block.size);
- offset += block.size;
- }
-}
-
-void SerializeSourceToPb(const Source& source, StringPool* src_pool, pb::Source* out_pb_source) {
- StringPool::Ref ref = src_pool->MakeRef(source.path);
- out_pb_source->set_path_idx(static_cast<uint32_t>(ref.index()));
- if (source.line) {
- out_pb_source->mutable_position()->set_line_number(static_cast<uint32_t>(source.line.value()));
- }
-}
-
-void DeserializeSourceFromPb(const pb::Source& pb_source, const android::ResStringPool& src_pool,
- Source* out_source) {
- if (pb_source.has_path_idx()) {
- out_source->path = util::GetString(src_pool, pb_source.path_idx());
- }
-
- if (pb_source.has_position()) {
- out_source->line = static_cast<size_t>(pb_source.position().line_number());
- }
-}
-
-pb::SymbolStatus_Visibility SerializeVisibilityToPb(SymbolState state) {
- switch (state) {
- case SymbolState::kPrivate:
- return pb::SymbolStatus_Visibility_PRIVATE;
- case SymbolState::kPublic:
- return pb::SymbolStatus_Visibility_PUBLIC;
- default:
- break;
- }
- return pb::SymbolStatus_Visibility_UNKNOWN;
-}
-
-SymbolState DeserializeVisibilityFromPb(pb::SymbolStatus_Visibility pb_visibility) {
- switch (pb_visibility) {
- case pb::SymbolStatus_Visibility_PRIVATE:
- return SymbolState::kPrivate;
- case pb::SymbolStatus_Visibility_PUBLIC:
- return SymbolState::kPublic;
- default:
- break;
- }
- return SymbolState::kUndefined;
-}
-
-void SerializeConfig(const ConfigDescription& config, pb::ConfigDescription* out_pb_config) {
- android::ResTable_config flat_config = config;
- flat_config.size = sizeof(flat_config);
- flat_config.swapHtoD();
- out_pb_config->set_data(&flat_config, sizeof(flat_config));
-}
-
-bool DeserializeConfigDescriptionFromPb(const pb::ConfigDescription& pb_config,
- ConfigDescription* out_config) {
- if (!pb_config.has_data()) {
- return false;
- }
-
- const android::ResTable_config* config;
- if (pb_config.data().size() > sizeof(*config)) {
- return false;
- }
-
- config = reinterpret_cast<const android::ResTable_config*>(pb_config.data().data());
- out_config->copyFromDtoH(*config);
- return true;
-}
-
-pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type) {
- switch (type) {
- case Reference::Type::kResource:
- return pb::Reference_Type_REFERENCE;
- case Reference::Type::kAttribute:
- return pb::Reference_Type_ATTRIBUTE;
- default:
- break;
- }
- return pb::Reference_Type_REFERENCE;
-}
-
-Reference::Type DeserializeReferenceTypeFromPb(pb::Reference_Type pb_type) {
- switch (pb_type) {
- case pb::Reference_Type_REFERENCE:
- return Reference::Type::kResource;
- case pb::Reference_Type_ATTRIBUTE:
- return Reference::Type::kAttribute;
- default:
- break;
- }
- return Reference::Type::kResource;
-}
-
-pb::Plural_Arity SerializePluralEnumToPb(size_t plural_idx) {
- switch (plural_idx) {
- case Plural::Zero:
- return pb::Plural_Arity_ZERO;
- case Plural::One:
- return pb::Plural_Arity_ONE;
- case Plural::Two:
- return pb::Plural_Arity_TWO;
- case Plural::Few:
- return pb::Plural_Arity_FEW;
- case Plural::Many:
- return pb::Plural_Arity_MANY;
- default:
- break;
- }
- return pb::Plural_Arity_OTHER;
-}
-
-size_t DeserializePluralEnumFromPb(pb::Plural_Arity arity) {
- switch (arity) {
- case pb::Plural_Arity_ZERO:
- return Plural::Zero;
- case pb::Plural_Arity_ONE:
- return Plural::One;
- case pb::Plural_Arity_TWO:
- return Plural::Two;
- case pb::Plural_Arity_FEW:
- return Plural::Few;
- case pb::Plural_Arity_MANY:
- return Plural::Many;
- default:
- break;
- }
- return Plural::Other;
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/proto/ProtoHelpers.h b/tools/aapt2/proto/ProtoHelpers.h
deleted file mode 100644
index 2f268f4..0000000
--- a/tools/aapt2/proto/ProtoHelpers.h
+++ /dev/null
@@ -1,57 +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.
- */
-
-#ifndef AAPT_PROTO_PROTOHELPERS_H
-#define AAPT_PROTO_PROTOHELPERS_H
-
-#include "androidfw/ResourceTypes.h"
-
-#include "ConfigDescription.h"
-#include "ResourceTable.h"
-#include "Source.h"
-#include "StringPool.h"
-#include "Resources.pb.h"
-#include "ResourcesInternal.pb.h"
-
-namespace aapt {
-
-void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool);
-
-void SerializeSourceToPb(const Source& source, StringPool* src_pool, pb::Source* out_pb_source);
-
-void DeserializeSourceFromPb(const pb::Source& pb_source, const android::ResStringPool& src_pool,
- Source* out_source);
-
-pb::SymbolStatus_Visibility SerializeVisibilityToPb(SymbolState state);
-
-SymbolState DeserializeVisibilityFromPb(pb::SymbolStatus_Visibility pb_visibility);
-
-void SerializeConfig(const ConfigDescription& config, pb::ConfigDescription* out_pb_config);
-
-bool DeserializeConfigDescriptionFromPb(const pb::ConfigDescription& pb_config,
- ConfigDescription* out_config);
-
-pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type);
-
-Reference::Type DeserializeReferenceTypeFromPb(pb::Reference_Type pb_type);
-
-pb::Plural_Arity SerializePluralEnumToPb(size_t plural_idx);
-
-size_t DeserializePluralEnumFromPb(pb::Plural_Arity arity);
-
-} // namespace aapt
-
-#endif /* AAPT_PROTO_PROTOHELPERS_H */
diff --git a/tools/aapt2/proto/ProtoSerialize.cpp b/tools/aapt2/proto/ProtoSerialize.cpp
new file mode 100644
index 0000000..d36d668
--- /dev/null
+++ b/tools/aapt2/proto/ProtoSerialize.cpp
@@ -0,0 +1,622 @@
+/*
+ * 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 "proto/ProtoSerialize.h"
+
+#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
+
+#include "ValueVisitor.h"
+#include "util/BigBuffer.h"
+
+using ::google::protobuf::io::CodedOutputStream;
+using ::google::protobuf::io::ZeroCopyOutputStream;
+
+namespace aapt {
+
+void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool) {
+ BigBuffer buffer(1024);
+ StringPool::FlattenUtf8(&buffer, pool);
+
+ std::string* data = out_pb_pool->mutable_data();
+ data->reserve(buffer.size());
+
+ size_t offset = 0;
+ for (const BigBuffer::Block& block : buffer) {
+ data->insert(data->begin() + offset, block.buffer.get(), block.buffer.get() + block.size);
+ offset += block.size;
+ }
+}
+
+void SerializeSourceToPb(const Source& source, StringPool* src_pool, pb::Source* out_pb_source) {
+ StringPool::Ref ref = src_pool->MakeRef(source.path);
+ out_pb_source->set_path_idx(static_cast<uint32_t>(ref.index()));
+ if (source.line) {
+ out_pb_source->mutable_position()->set_line_number(static_cast<uint32_t>(source.line.value()));
+ }
+}
+
+static pb::SymbolStatus_Visibility SerializeVisibilityToPb(SymbolState state) {
+ switch (state) {
+ case SymbolState::kPrivate:
+ return pb::SymbolStatus_Visibility_PRIVATE;
+ case SymbolState::kPublic:
+ return pb::SymbolStatus_Visibility_PUBLIC;
+ default:
+ break;
+ }
+ return pb::SymbolStatus_Visibility_UNKNOWN;
+}
+
+void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config) {
+ out_pb_config->set_mcc(config.mcc);
+ out_pb_config->set_mnc(config.mnc);
+ out_pb_config->set_locale(config.GetBcp47LanguageTag());
+
+ switch (config.screenLayout & ConfigDescription::MASK_LAYOUTDIR) {
+ case ConfigDescription::LAYOUTDIR_LTR:
+ out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR);
+ break;
+
+ case ConfigDescription::LAYOUTDIR_RTL:
+ out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL);
+ break;
+ }
+
+ out_pb_config->set_screen_width(config.screenWidth);
+ out_pb_config->set_screen_height(config.screenHeight);
+ out_pb_config->set_screen_width_dp(config.screenWidthDp);
+ out_pb_config->set_screen_height_dp(config.screenHeightDp);
+ out_pb_config->set_smallest_screen_width_dp(config.smallestScreenWidthDp);
+
+ switch (config.screenLayout & ConfigDescription::MASK_SCREENSIZE) {
+ case ConfigDescription::SCREENSIZE_SMALL:
+ out_pb_config->set_screen_layout_size(
+ pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL);
+ break;
+
+ case ConfigDescription::SCREENSIZE_NORMAL:
+ out_pb_config->set_screen_layout_size(
+ pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL);
+ break;
+
+ case ConfigDescription::SCREENSIZE_LARGE:
+ out_pb_config->set_screen_layout_size(
+ pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE);
+ break;
+
+ case ConfigDescription::SCREENSIZE_XLARGE:
+ out_pb_config->set_screen_layout_size(
+ pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE);
+ break;
+ }
+
+ switch (config.screenLayout & ConfigDescription::MASK_SCREENLONG) {
+ case ConfigDescription::SCREENLONG_YES:
+ out_pb_config->set_screen_layout_long(
+ pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG);
+ break;
+
+ case ConfigDescription::SCREENLONG_NO:
+ out_pb_config->set_screen_layout_long(
+ pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG);
+ break;
+ }
+
+ switch (config.screenLayout2 & ConfigDescription::MASK_SCREENROUND) {
+ case ConfigDescription::SCREENROUND_YES:
+ out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND);
+ break;
+
+ case ConfigDescription::SCREENROUND_NO:
+ out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND);
+ break;
+ }
+
+ switch (config.colorMode & ConfigDescription::MASK_WIDE_COLOR_GAMUT) {
+ case ConfigDescription::WIDE_COLOR_GAMUT_YES:
+ out_pb_config->set_wide_color_gamut(pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG);
+ break;
+
+ case ConfigDescription::WIDE_COLOR_GAMUT_NO:
+ out_pb_config->set_wide_color_gamut(
+ pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG);
+ break;
+ }
+
+ switch (config.colorMode & ConfigDescription::MASK_HDR) {
+ case ConfigDescription::HDR_YES:
+ out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_HIGHDR);
+ break;
+
+ case ConfigDescription::HDR_NO:
+ out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_LOWDR);
+ break;
+ }
+
+ switch (config.orientation) {
+ case ConfigDescription::ORIENTATION_PORT:
+ out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_PORT);
+ break;
+
+ case ConfigDescription::ORIENTATION_LAND:
+ out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_LAND);
+ break;
+
+ case ConfigDescription::ORIENTATION_SQUARE:
+ out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_SQUARE);
+ break;
+ }
+
+ switch (config.uiMode & ConfigDescription::MASK_UI_MODE_TYPE) {
+ case ConfigDescription::UI_MODE_TYPE_NORMAL:
+ out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL);
+ break;
+
+ case ConfigDescription::UI_MODE_TYPE_DESK:
+ out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_DESK);
+ break;
+
+ case ConfigDescription::UI_MODE_TYPE_CAR:
+ out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_CAR);
+ break;
+
+ case ConfigDescription::UI_MODE_TYPE_TELEVISION:
+ out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION);
+ break;
+
+ case ConfigDescription::UI_MODE_TYPE_APPLIANCE:
+ out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE);
+ break;
+
+ case ConfigDescription::UI_MODE_TYPE_WATCH:
+ out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH);
+ break;
+
+ case ConfigDescription::UI_MODE_TYPE_VR_HEADSET:
+ out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET);
+ break;
+ }
+
+ switch (config.uiMode & ConfigDescription::MASK_UI_MODE_NIGHT) {
+ case ConfigDescription::UI_MODE_NIGHT_YES:
+ out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT);
+ break;
+
+ case ConfigDescription::UI_MODE_NIGHT_NO:
+ out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT);
+ break;
+ }
+
+ out_pb_config->set_density(config.density);
+
+ switch (config.touchscreen) {
+ case ConfigDescription::TOUCHSCREEN_NOTOUCH:
+ out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH);
+ break;
+
+ case ConfigDescription::TOUCHSCREEN_STYLUS:
+ out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS);
+ break;
+
+ case ConfigDescription::TOUCHSCREEN_FINGER:
+ out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER);
+ break;
+ }
+
+ switch (config.inputFlags & ConfigDescription::MASK_KEYSHIDDEN) {
+ case ConfigDescription::KEYSHIDDEN_NO:
+ out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED);
+ break;
+
+ case ConfigDescription::KEYSHIDDEN_YES:
+ out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN);
+ break;
+
+ case ConfigDescription::KEYSHIDDEN_SOFT:
+ out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT);
+ break;
+ }
+
+ switch (config.keyboard) {
+ case ConfigDescription::KEYBOARD_NOKEYS:
+ out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_NOKEYS);
+ break;
+
+ case ConfigDescription::KEYBOARD_QWERTY:
+ out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_QWERTY);
+ break;
+
+ case ConfigDescription::KEYBOARD_12KEY:
+ out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY);
+ break;
+ }
+
+ switch (config.inputFlags & ConfigDescription::MASK_NAVHIDDEN) {
+ case ConfigDescription::NAVHIDDEN_NO:
+ out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED);
+ break;
+
+ case ConfigDescription::NAVHIDDEN_YES:
+ out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN);
+ break;
+ }
+
+ switch (config.navigation) {
+ case ConfigDescription::NAVIGATION_NONAV:
+ out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_NONAV);
+ break;
+
+ case ConfigDescription::NAVIGATION_DPAD:
+ out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_DPAD);
+ break;
+
+ case ConfigDescription::NAVIGATION_TRACKBALL:
+ out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_TRACKBALL);
+ break;
+
+ case ConfigDescription::NAVIGATION_WHEEL:
+ out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_WHEEL);
+ break;
+ }
+
+ out_pb_config->set_sdk_version(config.sdkVersion);
+}
+
+void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table) {
+ StringPool source_pool;
+ for (const std::unique_ptr<ResourceTablePackage>& package : table.packages) {
+ pb::Package* pb_package = out_table->add_package();
+ if (package->id) {
+ pb_package->mutable_package_id()->set_id(package->id.value());
+ }
+ pb_package->set_package_name(package->name);
+
+ for (const std::unique_ptr<ResourceTableType>& type : package->types) {
+ pb::Type* pb_type = pb_package->add_type();
+ if (type->id) {
+ pb_type->mutable_type_id()->set_id(type->id.value());
+ }
+ pb_type->set_name(ToString(type->type).to_string());
+
+ for (const std::unique_ptr<ResourceEntry>& entry : type->entries) {
+ pb::Entry* pb_entry = pb_type->add_entry();
+ if (entry->id) {
+ pb_entry->mutable_entry_id()->set_id(entry->id.value());
+ }
+ pb_entry->set_name(entry->name);
+
+ // Write the SymbolStatus struct.
+ pb::SymbolStatus* pb_status = pb_entry->mutable_symbol_status();
+ pb_status->set_visibility(SerializeVisibilityToPb(entry->symbol_status.state));
+ SerializeSourceToPb(entry->symbol_status.source, &source_pool, pb_status->mutable_source());
+ pb_status->set_comment(entry->symbol_status.comment);
+ pb_status->set_allow_new(entry->symbol_status.allow_new);
+
+ for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) {
+ pb::ConfigValue* pb_config_value = pb_entry->add_config_value();
+ SerializeConfig(config_value->config, pb_config_value->mutable_config());
+ pb_config_value->mutable_config()->set_product(config_value->product);
+ SerializeValueToPb(*config_value->value, pb_config_value->mutable_value(), &source_pool);
+ }
+ }
+ }
+ }
+ SerializeStringPoolToPb(source_pool, out_table->mutable_source_pool());
+}
+
+static pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type) {
+ switch (type) {
+ case Reference::Type::kResource:
+ return pb::Reference_Type_REFERENCE;
+ case Reference::Type::kAttribute:
+ return pb::Reference_Type_ATTRIBUTE;
+ default:
+ break;
+ }
+ return pb::Reference_Type_REFERENCE;
+}
+
+static void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) {
+ pb_ref->set_id(ref.id.value_or_default(ResourceId(0x0)).id);
+
+ if (ref.name) {
+ pb_ref->set_name(ref.name.value().ToString());
+ }
+
+ pb_ref->set_private_(ref.private_reference);
+ pb_ref->set_type(SerializeReferenceTypeToPb(ref.reference_type));
+}
+
+template <typename T>
+static void SerializeItemMetaDataToPb(const Item& item, T* pb_item, StringPool* src_pool) {
+ if (src_pool != nullptr) {
+ SerializeSourceToPb(item.GetSource(), src_pool, pb_item->mutable_source());
+ }
+ pb_item->set_comment(item.GetComment());
+}
+
+static pb::Plural_Arity SerializePluralEnumToPb(size_t plural_idx) {
+ switch (plural_idx) {
+ case Plural::Zero:
+ return pb::Plural_Arity_ZERO;
+ case Plural::One:
+ return pb::Plural_Arity_ONE;
+ case Plural::Two:
+ return pb::Plural_Arity_TWO;
+ case Plural::Few:
+ return pb::Plural_Arity_FEW;
+ case Plural::Many:
+ return pb::Plural_Arity_MANY;
+ default:
+ break;
+ }
+ return pb::Plural_Arity_OTHER;
+}
+
+namespace {
+
+class ValueSerializer : public ConstValueVisitor {
+ public:
+ using ConstValueVisitor::Visit;
+
+ ValueSerializer(pb::Value* out_value, StringPool* src_pool)
+ : out_value_(out_value), src_pool_(src_pool) {
+ }
+
+ void Visit(const Reference* ref) override {
+ SerializeReferenceToPb(*ref, out_value_->mutable_item()->mutable_ref());
+ }
+
+ void Visit(const String* str) override {
+ out_value_->mutable_item()->mutable_str()->set_value(*str->value);
+ }
+
+ void Visit(const RawString* str) override {
+ out_value_->mutable_item()->mutable_raw_str()->set_value(*str->value);
+ }
+
+ void Visit(const StyledString* str) override {
+ pb::StyledString* pb_str = out_value_->mutable_item()->mutable_styled_str();
+ pb_str->set_value(str->value->value);
+ for (const StringPool::Span& span : str->value->spans) {
+ pb::StyledString::Span* pb_span = pb_str->add_span();
+ pb_span->set_tag(*span.name);
+ pb_span->set_first_char(span.first_char);
+ pb_span->set_last_char(span.last_char);
+ }
+ }
+
+ void Visit(const FileReference* file) override {
+ out_value_->mutable_item()->mutable_file()->set_path(*file->path);
+ }
+
+ void Visit(const Id* /*id*/) override {
+ out_value_->mutable_item()->mutable_id();
+ }
+
+ void Visit(const BinaryPrimitive* prim) override {
+ android::Res_value val = {};
+ prim->Flatten(&val);
+
+ pb::Primitive* pb_prim = out_value_->mutable_item()->mutable_prim();
+ pb_prim->set_type(val.dataType);
+ pb_prim->set_data(val.data);
+ }
+
+ void Visit(const Attribute* attr) override {
+ pb::Attribute* pb_attr = out_value_->mutable_compound_value()->mutable_attr();
+ pb_attr->set_format_flags(attr->type_mask);
+ pb_attr->set_min_int(attr->min_int);
+ pb_attr->set_max_int(attr->max_int);
+
+ for (auto& symbol : attr->symbols) {
+ pb::Attribute_Symbol* pb_symbol = pb_attr->add_symbol();
+ SerializeItemMetaDataToPb(symbol.symbol, pb_symbol, src_pool_);
+ SerializeReferenceToPb(symbol.symbol, pb_symbol->mutable_name());
+ pb_symbol->set_value(symbol.value);
+ }
+ }
+
+ void Visit(const Style* style) override {
+ pb::Style* pb_style = out_value_->mutable_compound_value()->mutable_style();
+ if (style->parent) {
+ const Reference& parent = style->parent.value();
+ SerializeReferenceToPb(parent, pb_style->mutable_parent());
+ if (src_pool_ != nullptr) {
+ SerializeSourceToPb(parent.GetSource(), src_pool_, pb_style->mutable_parent_source());
+ }
+ }
+
+ for (const Style::Entry& entry : style->entries) {
+ pb::Style_Entry* pb_entry = pb_style->add_entry();
+ SerializeReferenceToPb(entry.key, pb_entry->mutable_key());
+ SerializeItemMetaDataToPb(entry.key, pb_entry, src_pool_);
+ SerializeItemToPb(*entry.value, pb_entry->mutable_item());
+ }
+ }
+
+ void Visit(const Styleable* styleable) override {
+ pb::Styleable* pb_styleable = out_value_->mutable_compound_value()->mutable_styleable();
+ for (const Reference& entry : styleable->entries) {
+ pb::Styleable_Entry* pb_entry = pb_styleable->add_entry();
+ SerializeItemMetaDataToPb(entry, pb_entry, src_pool_);
+ SerializeReferenceToPb(entry, pb_entry->mutable_attr());
+ }
+ }
+
+ void Visit(const Array* array) override {
+ pb::Array* pb_array = out_value_->mutable_compound_value()->mutable_array();
+ for (const std::unique_ptr<Item>& element : array->elements) {
+ pb::Array_Element* pb_element = pb_array->add_element();
+ SerializeItemMetaDataToPb(*element, pb_element, src_pool_);
+ SerializeItemToPb(*element, pb_element->mutable_item());
+ }
+ }
+
+ void Visit(const Plural* plural) override {
+ pb::Plural* pb_plural = out_value_->mutable_compound_value()->mutable_plural();
+ const size_t count = plural->values.size();
+ for (size_t i = 0; i < count; i++) {
+ if (!plural->values[i]) {
+ // No plural value set here.
+ continue;
+ }
+
+ pb::Plural_Entry* pb_entry = pb_plural->add_entry();
+ pb_entry->set_arity(SerializePluralEnumToPb(i));
+ SerializeItemMetaDataToPb(*plural->values[i], pb_entry, src_pool_);
+ SerializeItemToPb(*plural->values[i], pb_entry->mutable_item());
+ }
+ }
+
+ void VisitAny(const Value* unknown) override {
+ LOG(FATAL) << "unimplemented value: " << *unknown;
+ }
+
+ private:
+ pb::Value* out_value_;
+ StringPool* src_pool_;
+};
+
+} // namespace
+
+void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool) {
+ ValueSerializer serializer(out_value, src_pool);
+ value.Accept(&serializer);
+
+ // Serialize the meta-data of the Value.
+ out_value->set_comment(value.GetComment());
+ out_value->set_weak(value.IsWeak());
+ if (src_pool != nullptr) {
+ SerializeSourceToPb(value.GetSource(), src_pool, out_value->mutable_source());
+ }
+}
+
+void SerializeItemToPb(const Item& item, pb::Item* out_item) {
+ pb::Value value;
+ ValueSerializer serializer(&value, nullptr);
+ item.Accept(&serializer);
+ out_item->MergeFrom(value.item());
+}
+
+void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file) {
+ out_file->set_resource_name(file.name.ToString());
+ out_file->set_source_path(file.source.path);
+ SerializeConfig(file.config, out_file->mutable_config());
+
+ for (const SourcedResourceName& exported : file.exported_symbols) {
+ pb::internal::CompiledFile_Symbol* pb_symbol = out_file->add_exported_symbol();
+ pb_symbol->set_resource_name(exported.name.ToString());
+ pb_symbol->mutable_source()->set_line_number(exported.line);
+ }
+}
+
+static void SerializeXmlCommon(const xml::Node& node, pb::XmlNode* out_node) {
+ pb::SourcePosition* pb_src = out_node->mutable_source();
+ pb_src->set_line_number(node.line_number);
+ pb_src->set_column_number(node.column_number);
+}
+
+void SerializeXmlToPb(const xml::Element& el, pb::XmlNode* out_node) {
+ SerializeXmlCommon(el, out_node);
+
+ pb::XmlElement* pb_element = out_node->mutable_element();
+ pb_element->set_name(el.name);
+ pb_element->set_namespace_uri(el.namespace_uri);
+
+ for (const xml::NamespaceDecl& ns : el.namespace_decls) {
+ pb::XmlNamespace* pb_ns = pb_element->add_namespace_declaration();
+ pb_ns->set_prefix(ns.prefix);
+ pb_ns->set_uri(ns.uri);
+ pb::SourcePosition* pb_src = pb_ns->mutable_source();
+ pb_src->set_line_number(ns.line_number);
+ pb_src->set_column_number(ns.column_number);
+ }
+
+ for (const xml::Attribute& attr : el.attributes) {
+ pb::XmlAttribute* pb_attr = pb_element->add_attribute();
+ pb_attr->set_name(attr.name);
+ pb_attr->set_namespace_uri(attr.namespace_uri);
+ pb_attr->set_value(attr.value);
+ if (attr.compiled_attribute) {
+ const ResourceId attr_id = attr.compiled_attribute.value().id.value_or_default({});
+ pb_attr->set_resource_id(attr_id.id);
+ }
+ if (attr.compiled_value != nullptr) {
+ SerializeItemToPb(*attr.compiled_value, pb_attr->mutable_compiled_item());
+ pb::SourcePosition* pb_src = pb_attr->mutable_source();
+ pb_src->set_line_number(attr.compiled_value->GetSource().line.value_or_default(0));
+ }
+ }
+
+ for (const std::unique_ptr<xml::Node>& child : el.children) {
+ if (const xml::Element* child_el = xml::NodeCast<xml::Element>(child.get())) {
+ SerializeXmlToPb(*child_el, pb_element->add_child());
+ } else if (const xml::Text* text_el = xml::NodeCast<xml::Text>(child.get())) {
+ pb::XmlNode* pb_child_node = pb_element->add_child();
+ SerializeXmlCommon(*text_el, pb_child_node);
+ pb_child_node->set_text(text_el->text);
+ } else {
+ LOG(FATAL) << "unhandled XmlNode type";
+ }
+ }
+}
+
+void SerializeXmlResourceToPb(const xml::XmlResource& resource, pb::XmlNode* out_node) {
+ SerializeXmlToPb(*resource.root, out_node);
+}
+
+CompiledFileOutputStream::CompiledFileOutputStream(ZeroCopyOutputStream* out) : out_(out) {
+}
+
+void CompiledFileOutputStream::EnsureAlignedWrite() {
+ const int overflow = out_.ByteCount() % 4;
+ if (overflow > 0) {
+ uint32_t zero = 0u;
+ out_.WriteRaw(&zero, 4 - overflow);
+ }
+}
+
+void CompiledFileOutputStream::WriteLittleEndian32(uint32_t val) {
+ EnsureAlignedWrite();
+ out_.WriteLittleEndian32(val);
+}
+
+void CompiledFileOutputStream::WriteCompiledFile(const pb::internal::CompiledFile& compiled_file) {
+ EnsureAlignedWrite();
+ out_.WriteLittleEndian64(static_cast<uint64_t>(compiled_file.ByteSize()));
+ compiled_file.SerializeWithCachedSizes(&out_);
+}
+
+void CompiledFileOutputStream::WriteData(const BigBuffer& buffer) {
+ EnsureAlignedWrite();
+ out_.WriteLittleEndian64(static_cast<uint64_t>(buffer.size()));
+ for (const BigBuffer::Block& block : buffer) {
+ out_.WriteRaw(block.buffer.get(), block.size);
+ }
+}
+
+void CompiledFileOutputStream::WriteData(const void* data, size_t len) {
+ EnsureAlignedWrite();
+ out_.WriteLittleEndian64(static_cast<uint64_t>(len));
+ out_.WriteRaw(data, len);
+}
+
+bool CompiledFileOutputStream::HadError() {
+ return out_.HadError();
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/proto/ProtoSerialize.h b/tools/aapt2/proto/ProtoSerialize.h
index 8c46642..4bf7e1c 100644
--- a/tools/aapt2/proto/ProtoSerialize.h
+++ b/tools/aapt2/proto/ProtoSerialize.h
@@ -19,22 +19,60 @@
#include "android-base/macros.h"
#include "google/protobuf/io/coded_stream.h"
-#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
-#include "Diagnostics.h"
+#include "ConfigDescription.h"
+#include "Configuration.pb.h"
#include "ResourceTable.h"
-#include "Source.h"
-#include "proto/ProtoHelpers.h"
+#include "ResourceValues.h"
+#include "Resources.pb.h"
+#include "ResourcesInternal.pb.h"
+#include "StringPool.h"
+#include "xml/XmlDom.h"
+
+namespace google {
+namespace protobuf {
+namespace io {
+class ZeroCopyOutputStream;
+} // namespace io
+} // namespace protobuf
+} // namespace google
namespace aapt {
+// Serializes a Value to its protobuf representation. An optional StringPool will hold the
+// source path string.
+void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool = nullptr);
+
+// Serialize an Item into its protobuf representation. pb::Item does not store the source path nor
+// comments of an Item.
+void SerializeItemToPb(const Item& item, pb::Item* out_item);
+
+// Serializes an XML element into its protobuf representation.
+void SerializeXmlToPb(const xml::Element& el, pb::XmlNode* out_node);
+
+// Serializes an XmlResource into its protobuf representation. The ResourceFile is NOT serialized.
+void SerializeXmlResourceToPb(const xml::XmlResource& resource, pb::XmlNode* out_node);
+
+// Serializes a StringPool into its protobuf representation, which is really just the binary
+// ResStringPool representation stuffed into a bytes field.
+void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool);
+
+// Serializes a ConfigDescription into its protobuf representation.
+void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config);
+
+// Serializes a ResourceTable into its protobuf representation.
+void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table);
+
+// Serializes a ResourceFile into its protobuf representation.
+void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file);
+
class CompiledFileOutputStream {
public:
- explicit CompiledFileOutputStream(google::protobuf::io::ZeroCopyOutputStream* out);
+ explicit CompiledFileOutputStream(::google::protobuf::io::ZeroCopyOutputStream* out);
void WriteLittleEndian32(uint32_t value);
- void WriteCompiledFile(const pb::internal::CompiledFile* compiledFile);
- void WriteData(const BigBuffer* buffer);
+ void WriteCompiledFile(const pb::internal::CompiledFile& compiledFile);
+ void WriteData(const BigBuffer& buffer);
void WriteData(const void* data, size_t len);
bool HadError();
@@ -43,33 +81,9 @@
void EnsureAlignedWrite();
- google::protobuf::io::CodedOutputStream out_;
+ ::google::protobuf::io::CodedOutputStream out_;
};
-class CompiledFileInputStream {
- public:
- explicit CompiledFileInputStream(const void* data, size_t size);
-
- bool ReadLittleEndian32(uint32_t* outVal);
- bool ReadCompiledFile(pb::internal::CompiledFile* outVal);
- bool ReadDataMetaData(uint64_t* outOffset, uint64_t* outLen);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CompiledFileInputStream);
-
- void EnsureAlignedRead();
-
- google::protobuf::io::CodedInputStream in_;
-};
-
-std::unique_ptr<pb::ResourceTable> SerializeTableToPb(ResourceTable* table);
-std::unique_ptr<ResourceTable> DeserializeTableFromPb(const pb::ResourceTable& pbTable,
- const Source& source, IDiagnostics* diag);
-
-std::unique_ptr<pb::internal::CompiledFile> SerializeCompiledFileToPb(const ResourceFile& file);
-std::unique_ptr<ResourceFile> DeserializeCompiledFileFromPb(
- const pb::internal::CompiledFile& pbFile, const Source& source, IDiagnostics* diag);
-
} // namespace aapt
#endif /* AAPT_FLATTEN_TABLEPROTOSERIALIZER_H */
diff --git a/tools/aapt2/proto/ProtoSerialize_test.cpp b/tools/aapt2/proto/ProtoSerialize_test.cpp
new file mode 100644
index 0000000..b263aff
--- /dev/null
+++ b/tools/aapt2/proto/ProtoSerialize_test.cpp
@@ -0,0 +1,435 @@
+/*
+ * 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 "proto/ProtoSerialize.h"
+
+#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
+
+#include "ResourceUtils.h"
+#include "proto/ProtoDeserialize.h"
+#include "test/Test.h"
+
+using ::android::StringPiece;
+using ::google::protobuf::io::StringOutputStream;
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using ::testing::NotNull;
+using ::testing::SizeIs;
+using ::testing::StrEq;
+
+namespace aapt {
+
+TEST(ProtoSerializeTest, SerializeSinglePackage) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddFileReference("com.app.a:layout/main", ResourceId(0x7f020000), "res/layout/main.xml")
+ .AddReference("com.app.a:layout/other", ResourceId(0x7f020001), "com.app.a:layout/main")
+ .AddString("com.app.a:string/text", {}, "hi")
+ .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
+ .SetSymbolState("com.app.a:bool/foo", {}, SymbolState::kUndefined, true /*allow_new*/)
+ .Build();
+
+ Symbol public_symbol;
+ public_symbol.state = SymbolState::kPublic;
+ ASSERT_TRUE(table->SetSymbolState(test::ParseNameOrDie("com.app.a:layout/main"),
+ ResourceId(0x7f020000), public_symbol,
+ context->GetDiagnostics()));
+
+ Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
+ ASSERT_THAT(id, NotNull());
+
+ // Make a plural.
+ std::unique_ptr<Plural> plural = util::make_unique<Plural>();
+ plural->values[Plural::One] = util::make_unique<String>(table->string_pool.MakeRef("one"));
+ ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:plurals/hey"), ConfigDescription{},
+ {}, std::move(plural), context->GetDiagnostics()));
+
+ // Make a styled string.
+ StyleString style_string;
+ style_string.str = "hello";
+ style_string.spans.push_back(Span{"b", 0u, 4u});
+ ASSERT_TRUE(
+ table->AddResource(test::ParseNameOrDie("com.app.a:string/styled"), ConfigDescription{}, {},
+ util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)),
+ context->GetDiagnostics()));
+
+ // Make a resource with different products.
+ ASSERT_TRUE(table->AddResource(
+ test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), {},
+ test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u), context->GetDiagnostics()));
+ ASSERT_TRUE(table->AddResource(
+ test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), "tablet",
+ test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u), context->GetDiagnostics()));
+
+ // Make a reference with both resource name and resource ID.
+ // The reference should point to a resource outside of this table to test that both name and id
+ // get serialized.
+ Reference expected_ref;
+ expected_ref.name = test::ParseNameOrDie("android:layout/main");
+ expected_ref.id = ResourceId(0x01020000);
+ ASSERT_TRUE(table->AddResource(
+ test::ParseNameOrDie("com.app.a:layout/abc"), ConfigDescription::DefaultConfig(), {},
+ util::make_unique<Reference>(expected_ref), context->GetDiagnostics()));
+
+ pb::ResourceTable pb_table;
+ SerializeTableToPb(*table, &pb_table);
+
+ ResourceTable new_table;
+ std::string error;
+ ASSERT_TRUE(DeserializeTableFromPb(pb_table, &new_table, &error));
+ EXPECT_THAT(error, IsEmpty());
+
+ Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo");
+ ASSERT_THAT(new_id, NotNull());
+ EXPECT_THAT(new_id->IsWeak(), Eq(id->IsWeak()));
+
+ Maybe<ResourceTable::SearchResult> result =
+ new_table.FindResource(test::ParseNameOrDie("com.app.a:layout/main"));
+ ASSERT_TRUE(result);
+
+ EXPECT_THAT(result.value().type->symbol_status.state, Eq(SymbolState::kPublic));
+ EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kPublic));
+
+ result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
+ ASSERT_TRUE(result);
+ EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kUndefined));
+ EXPECT_TRUE(result.value().entry->symbol_status.allow_new);
+
+ // Find the product-dependent values
+ BinaryPrimitive* prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
+ &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "");
+ ASSERT_THAT(prim, NotNull());
+ EXPECT_THAT(prim->value.data, Eq(123u));
+
+ prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
+ &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet");
+ ASSERT_THAT(prim, NotNull());
+ EXPECT_THAT(prim->value.data, Eq(321u));
+
+ Reference* actual_ref = test::GetValue<Reference>(&new_table, "com.app.a:layout/abc");
+ ASSERT_THAT(actual_ref, NotNull());
+ ASSERT_TRUE(actual_ref->name);
+ ASSERT_TRUE(actual_ref->id);
+ EXPECT_THAT(*actual_ref, Eq(expected_ref));
+
+ StyledString* actual_styled_str =
+ test::GetValue<StyledString>(&new_table, "com.app.a:string/styled");
+ ASSERT_THAT(actual_styled_str, NotNull());
+ EXPECT_THAT(actual_styled_str->value->value, Eq("hello"));
+ ASSERT_THAT(actual_styled_str->value->spans, SizeIs(1u));
+ EXPECT_THAT(*actual_styled_str->value->spans[0].name, Eq("b"));
+ EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u));
+ EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
+}
+
+TEST(ProtoSerializeTest, SerializeFileHeader) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+ ResourceFile f;
+ f.config = test::ParseConfigOrDie("hdpi-v9");
+ f.name = test::ParseNameOrDie("com.app.a:layout/main");
+ f.source.path = "res/layout-hdpi-v9/main.xml";
+ f.exported_symbols.push_back(SourcedResourceName{test::ParseNameOrDie("id/unchecked"), 23u});
+
+ const std::string expected_data1 = "123";
+ const std::string expected_data2 = "1234";
+
+ std::string output_str;
+ {
+ pb::internal::CompiledFile pb_f1, pb_f2;
+ SerializeCompiledFileToPb(f, &pb_f1);
+
+ f.name.entry = "__" + f.name.entry + "$0";
+ SerializeCompiledFileToPb(f, &pb_f2);
+
+ StringOutputStream out_stream(&output_str);
+ CompiledFileOutputStream out_file_stream(&out_stream);
+ out_file_stream.WriteLittleEndian32(2);
+ out_file_stream.WriteCompiledFile(pb_f1);
+ out_file_stream.WriteData(expected_data1.data(), expected_data1.size());
+ out_file_stream.WriteCompiledFile(pb_f2);
+ out_file_stream.WriteData(expected_data2.data(), expected_data2.size());
+ ASSERT_FALSE(out_file_stream.HadError());
+ }
+
+ CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
+ uint32_t num_files = 0;
+ ASSERT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
+ ASSERT_EQ(2u, num_files);
+
+ // Read the first compiled file.
+
+ pb::internal::CompiledFile new_pb_f1;
+ ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_f1));
+
+ ResourceFile new_f1;
+ std::string error;
+ ASSERT_TRUE(DeserializeCompiledFileFromPb(new_pb_f1, &new_f1, &error));
+ EXPECT_THAT(error, IsEmpty());
+
+ uint64_t offset, len;
+ ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
+
+ std::string actual_data(output_str.data() + offset, len);
+ EXPECT_EQ(expected_data1, actual_data);
+
+ // Expect the data to be aligned.
+ EXPECT_EQ(0u, offset & 0x03);
+
+ ASSERT_EQ(1u, new_f1.exported_symbols.size());
+ EXPECT_EQ(test::ParseNameOrDie("id/unchecked"), new_f1.exported_symbols[0].name);
+
+ // Read the second compiled file.
+
+ pb::internal::CompiledFile new_pb_f2;
+ ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_f2));
+
+ ResourceFile new_f2;
+ ASSERT_TRUE(DeserializeCompiledFileFromPb(new_pb_f2, &new_f2, &error));
+ EXPECT_THAT(error, IsEmpty());
+
+ ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
+
+ actual_data = std::string(output_str.data() + offset, len);
+ EXPECT_EQ(expected_data2, actual_data);
+
+ // Expect the data to be aligned.
+ EXPECT_EQ(0u, offset & 0x03);
+}
+
+TEST(ProtoSerializeTest, DeserializeCorruptHeaderSafely) {
+ ResourceFile f;
+ pb::internal::CompiledFile pb_file;
+ SerializeCompiledFileToPb(f, &pb_file);
+
+ const std::string expected_data = "1234";
+
+ std::string output_str;
+ {
+ StringOutputStream out_stream(&output_str);
+ CompiledFileOutputStream out_file_stream(&out_stream);
+ out_file_stream.WriteLittleEndian32(1);
+ out_file_stream.WriteCompiledFile(pb_file);
+ out_file_stream.WriteData(expected_data.data(), expected_data.size());
+ ASSERT_FALSE(out_file_stream.HadError());
+ }
+
+ output_str[4] = 0xff;
+
+ CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
+
+ uint32_t num_files = 0;
+ EXPECT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
+ EXPECT_EQ(1u, num_files);
+
+ pb::internal::CompiledFile new_pb_file;
+ EXPECT_FALSE(in_file_stream.ReadCompiledFile(&new_pb_file));
+
+ uint64_t offset, len;
+ EXPECT_FALSE(in_file_stream.ReadDataMetaData(&offset, &len));
+}
+
+TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
+ xml::Element element;
+ element.line_number = 22;
+ element.column_number = 23;
+ element.name = "element";
+ element.namespace_uri = "uri://";
+
+ xml::NamespaceDecl decl;
+ decl.prefix = "android";
+ decl.uri = xml::kSchemaAndroid;
+ decl.line_number = 21;
+ decl.column_number = 24;
+
+ element.namespace_decls.push_back(decl);
+
+ xml::Attribute attr;
+ attr.name = "name";
+ attr.namespace_uri = xml::kSchemaAndroid;
+ attr.value = "23dp";
+ attr.compiled_attribute = xml::AaptAttribute({}, ResourceId(0x01010000));
+ attr.compiled_value =
+ ResourceUtils::TryParseItemForAttribute(attr.value, android::ResTable_map::TYPE_DIMENSION);
+ attr.compiled_value->SetSource(Source().WithLine(25));
+ element.attributes.push_back(std::move(attr));
+
+ std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>();
+ text->line_number = 25;
+ text->column_number = 3;
+ text->text = "hey there";
+ element.AppendChild(std::move(text));
+
+ std::unique_ptr<xml::Element> child = util::make_unique<xml::Element>();
+ child->name = "child";
+
+ text = util::make_unique<xml::Text>();
+ text->text = "woah there";
+ child->AppendChild(std::move(text));
+
+ element.AppendChild(std::move(child));
+
+ pb::XmlNode pb_xml;
+ SerializeXmlToPb(element, &pb_xml);
+
+ StringPool pool;
+ xml::Element actual_el;
+ std::string error;
+ ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error));
+ ASSERT_THAT(error, IsEmpty());
+
+ EXPECT_THAT(actual_el.name, StrEq("element"));
+ EXPECT_THAT(actual_el.namespace_uri, StrEq("uri://"));
+ EXPECT_THAT(actual_el.line_number, Eq(22u));
+ EXPECT_THAT(actual_el.column_number, Eq(23u));
+
+ ASSERT_THAT(actual_el.namespace_decls, SizeIs(1u));
+ const xml::NamespaceDecl& actual_decl = actual_el.namespace_decls[0];
+ EXPECT_THAT(actual_decl.prefix, StrEq("android"));
+ EXPECT_THAT(actual_decl.uri, StrEq(xml::kSchemaAndroid));
+ EXPECT_THAT(actual_decl.line_number, Eq(21u));
+ EXPECT_THAT(actual_decl.column_number, Eq(24u));
+
+ ASSERT_THAT(actual_el.attributes, SizeIs(1u));
+ const xml::Attribute& actual_attr = actual_el.attributes[0];
+ EXPECT_THAT(actual_attr.name, StrEq("name"));
+ EXPECT_THAT(actual_attr.namespace_uri, StrEq(xml::kSchemaAndroid));
+ EXPECT_THAT(actual_attr.value, StrEq("23dp"));
+
+ ASSERT_THAT(actual_attr.compiled_value, NotNull());
+ const BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(actual_attr.compiled_value.get());
+ ASSERT_THAT(prim, NotNull());
+ EXPECT_THAT(prim->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
+
+ ASSERT_TRUE(actual_attr.compiled_attribute);
+ ASSERT_TRUE(actual_attr.compiled_attribute.value().id);
+
+ ASSERT_THAT(actual_el.children, SizeIs(2u));
+ const xml::Text* child_text = xml::NodeCast<xml::Text>(actual_el.children[0].get());
+ ASSERT_THAT(child_text, NotNull());
+ const xml::Element* child_el = xml::NodeCast<xml::Element>(actual_el.children[1].get());
+ ASSERT_THAT(child_el, NotNull());
+
+ EXPECT_THAT(child_text->line_number, Eq(25u));
+ EXPECT_THAT(child_text->column_number, Eq(3u));
+ EXPECT_THAT(child_text->text, StrEq("hey there"));
+
+ EXPECT_THAT(child_el->name, StrEq("child"));
+ ASSERT_THAT(child_el->children, SizeIs(1u));
+
+ child_text = xml::NodeCast<xml::Text>(child_el->children[0].get());
+ ASSERT_THAT(child_text, NotNull());
+ EXPECT_THAT(child_text->text, StrEq("woah there"));
+}
+
+static void ExpectConfigSerializes(const StringPiece& config_str) {
+ const ConfigDescription expected_config = test::ParseConfigOrDie(config_str);
+ pb::Configuration pb_config;
+ SerializeConfig(expected_config, &pb_config);
+
+ ConfigDescription actual_config;
+ std::string error;
+ ASSERT_TRUE(DeserializeConfigFromPb(pb_config, &actual_config, &error));
+ ASSERT_THAT(error, IsEmpty());
+ EXPECT_EQ(expected_config, actual_config);
+}
+
+TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) {
+ ExpectConfigSerializes("");
+
+ ExpectConfigSerializes("mcc123");
+
+ ExpectConfigSerializes("mnc123");
+
+ ExpectConfigSerializes("en");
+ ExpectConfigSerializes("en-rGB");
+ ExpectConfigSerializes("b+en+GB");
+
+ ExpectConfigSerializes("ldltr");
+ ExpectConfigSerializes("ldrtl");
+
+ ExpectConfigSerializes("sw3600dp");
+
+ ExpectConfigSerializes("w300dp");
+
+ ExpectConfigSerializes("h400dp");
+
+ ExpectConfigSerializes("small");
+ ExpectConfigSerializes("normal");
+ ExpectConfigSerializes("large");
+ ExpectConfigSerializes("xlarge");
+
+ ExpectConfigSerializes("long");
+ ExpectConfigSerializes("notlong");
+
+ ExpectConfigSerializes("round");
+ ExpectConfigSerializes("notround");
+
+ ExpectConfigSerializes("widecg");
+ ExpectConfigSerializes("nowidecg");
+
+ ExpectConfigSerializes("highdr");
+ ExpectConfigSerializes("lowdr");
+
+ ExpectConfigSerializes("port");
+ ExpectConfigSerializes("land");
+ ExpectConfigSerializes("square");
+
+ ExpectConfigSerializes("desk");
+ ExpectConfigSerializes("car");
+ ExpectConfigSerializes("television");
+ ExpectConfigSerializes("appliance");
+ ExpectConfigSerializes("watch");
+ ExpectConfigSerializes("vrheadset");
+
+ ExpectConfigSerializes("night");
+ ExpectConfigSerializes("notnight");
+
+ ExpectConfigSerializes("300dpi");
+ ExpectConfigSerializes("hdpi");
+
+ ExpectConfigSerializes("notouch");
+ ExpectConfigSerializes("stylus");
+ ExpectConfigSerializes("finger");
+
+ ExpectConfigSerializes("keysexposed");
+ ExpectConfigSerializes("keyshidden");
+ ExpectConfigSerializes("keyssoft");
+
+ ExpectConfigSerializes("nokeys");
+ ExpectConfigSerializes("qwerty");
+ ExpectConfigSerializes("12key");
+
+ ExpectConfigSerializes("navhidden");
+ ExpectConfigSerializes("navexposed");
+
+ ExpectConfigSerializes("nonav");
+ ExpectConfigSerializes("dpad");
+ ExpectConfigSerializes("trackball");
+ ExpectConfigSerializes("wheel");
+
+ ExpectConfigSerializes("300x200");
+
+ ExpectConfigSerializes("v8");
+
+ ExpectConfigSerializes(
+ "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-"
+ "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/proto/TableProtoDeserializer.cpp b/tools/aapt2/proto/TableProtoDeserializer.cpp
deleted file mode 100644
index b9d5878..0000000
--- a/tools/aapt2/proto/TableProtoDeserializer.cpp
+++ /dev/null
@@ -1,423 +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.
- */
-
-#include "proto/ProtoSerialize.h"
-
-#include "android-base/logging.h"
-#include "androidfw/ResourceTypes.h"
-
-#include "ResourceTable.h"
-#include "ResourceUtils.h"
-#include "ValueVisitor.h"
-#include "proto/ProtoHelpers.h"
-
-namespace aapt {
-
-namespace {
-
-class ReferenceIdToNameVisitor : public ValueVisitor {
- public:
- using ValueVisitor::Visit;
-
- explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping)
- : mapping_(mapping) {
- CHECK(mapping_ != nullptr);
- }
-
- void Visit(Reference* reference) override {
- if (!reference->id || !reference->id.value().is_valid()) {
- return;
- }
-
- ResourceId id = reference->id.value();
- auto cache_iter = mapping_->find(id);
- if (cache_iter != mapping_->end()) {
- reference->name = cache_iter->second.ToResourceName();
- }
- }
-
- private:
- const std::map<ResourceId, ResourceNameRef>* mapping_;
-};
-
-class PackagePbDeserializer {
- public:
- PackagePbDeserializer(const android::ResStringPool* sourcePool, const Source& source,
- IDiagnostics* diag)
- : source_pool_(sourcePool), source_(source), diag_(diag) {
- }
-
- public:
- bool DeserializeFromPb(const pb::Package& pb_package, ResourceTable* table) {
- Maybe<uint8_t> id;
- if (pb_package.has_package_id()) {
- id = static_cast<uint8_t>(pb_package.package_id());
- }
-
- std::map<ResourceId, ResourceNameRef> id_index;
-
- ResourceTablePackage* pkg = table->CreatePackage(pb_package.package_name(), id);
- for (const pb::Type& pb_type : pb_package.type()) {
- const ResourceType* res_type = ParseResourceType(pb_type.name());
- if (res_type == nullptr) {
- diag_->Error(DiagMessage(source_) << "unknown type '" << pb_type.name() << "'");
- return {};
- }
-
- ResourceTableType* type = pkg->FindOrCreateType(*res_type);
-
- for (const pb::Entry& pb_entry : pb_type.entry()) {
- ResourceEntry* entry = type->FindOrCreateEntry(pb_entry.name());
-
- // Deserialize the symbol status (public/private with source and comments).
- if (pb_entry.has_symbol_status()) {
- const pb::SymbolStatus& pb_status = pb_entry.symbol_status();
- if (pb_status.has_source()) {
- DeserializeSourceFromPb(pb_status.source(), *source_pool_,
- &entry->symbol_status.source);
- }
-
- if (pb_status.has_comment()) {
- entry->symbol_status.comment = pb_status.comment();
- }
-
- entry->symbol_status.allow_new = pb_status.allow_new();
-
- SymbolState visibility = DeserializeVisibilityFromPb(pb_status.visibility());
- entry->symbol_status.state = visibility;
-
- if (visibility == SymbolState::kPublic) {
- // This is a public symbol, we must encode the ID now if there is one.
- if (pb_entry.has_id()) {
- entry->id = static_cast<uint16_t>(pb_entry.id());
- }
-
- if (type->symbol_status.state != SymbolState::kPublic) {
- // If the type has not been made public, do so now.
- type->symbol_status.state = SymbolState::kPublic;
- if (pb_type.has_id()) {
- type->id = static_cast<uint8_t>(pb_type.id());
- }
- }
- } else if (visibility == SymbolState::kPrivate) {
- if (type->symbol_status.state == SymbolState::kUndefined) {
- type->symbol_status.state = SymbolState::kPrivate;
- }
- }
- }
-
- ResourceId resid(pb_package.package_id(), pb_type.id(), pb_entry.id());
- if (resid.is_valid()) {
- id_index[resid] = ResourceNameRef(pkg->name, type->type, entry->name);
- }
-
- for (const pb::ConfigValue& pb_config_value : pb_entry.config_value()) {
- const pb::ConfigDescription& pb_config = pb_config_value.config();
-
- ConfigDescription config;
- if (!DeserializeConfigDescriptionFromPb(pb_config, &config)) {
- diag_->Error(DiagMessage(source_) << "invalid configuration");
- return {};
- }
-
- ResourceConfigValue* config_value = entry->FindOrCreateValue(config, pb_config.product());
- if (config_value->value) {
- // Duplicate config.
- diag_->Error(DiagMessage(source_) << "duplicate configuration");
- return {};
- }
-
- config_value->value =
- DeserializeValueFromPb(pb_config_value.value(), config, &table->string_pool);
- if (!config_value->value) {
- return {};
- }
- }
- }
- }
-
- ReferenceIdToNameVisitor visitor(&id_index);
- VisitAllValuesInPackage(pkg, &visitor);
- return true;
- }
-
- private:
- std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
- const ConfigDescription& config, StringPool* pool) {
- if (pb_item.has_ref()) {
- const pb::Reference& pb_ref = pb_item.ref();
- std::unique_ptr<Reference> ref = util::make_unique<Reference>();
- if (!DeserializeReferenceFromPb(pb_ref, ref.get())) {
- return {};
- }
- return std::move(ref);
-
- } else if (pb_item.has_prim()) {
- const pb::Primitive& pb_prim = pb_item.prim();
- return util::make_unique<BinaryPrimitive>(static_cast<uint8_t>(pb_prim.type()),
- pb_prim.data());
-
- } else if (pb_item.has_id()) {
- return util::make_unique<Id>();
-
- } else if (pb_item.has_str()) {
- return util::make_unique<String>(
- pool->MakeRef(pb_item.str().value(), StringPool::Context(config)));
-
- } else if (pb_item.has_raw_str()) {
- return util::make_unique<RawString>(
- pool->MakeRef(pb_item.raw_str().value(), StringPool::Context(config)));
-
- } else if (pb_item.has_styled_str()) {
- const pb::StyledString& pb_str = pb_item.styled_str();
- StyleString style_str{pb_str.value()};
- for (const pb::StyledString::Span& pb_span : pb_str.span()) {
- style_str.spans.push_back(Span{pb_span.tag(), pb_span.first_char(), pb_span.last_char()});
- }
- return util::make_unique<StyledString>(pool->MakeRef(
- style_str, StringPool::Context(StringPool::Context::kNormalPriority, config)));
-
- } else if (pb_item.has_file()) {
- return util::make_unique<FileReference>(pool->MakeRef(
- pb_item.file().path(), StringPool::Context(StringPool::Context::kHighPriority, config)));
-
- } else {
- diag_->Error(DiagMessage(source_) << "unknown item");
- }
- return {};
- }
-
- std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
- const ConfigDescription& config,
- StringPool* pool) {
- std::unique_ptr<Value> value;
- if (pb_value.has_item()) {
- value = DeserializeItemFromPb(pb_value.item(), config, pool);
- if (!value) {
- return {};
- }
-
- } else if (pb_value.has_compound_value()) {
- const pb::CompoundValue& pb_compound_value = pb_value.compound_value();
- if (pb_compound_value.has_attr()) {
- const pb::Attribute& pb_attr = pb_compound_value.attr();
- std::unique_ptr<Attribute> attr = util::make_unique<Attribute>();
- attr->type_mask = pb_attr.format_flags();
- attr->min_int = pb_attr.min_int();
- attr->max_int = pb_attr.max_int();
- for (const pb::Attribute_Symbol& pb_symbol : pb_attr.symbol()) {
- Attribute::Symbol symbol;
- DeserializeItemCommon(pb_symbol, &symbol.symbol);
- if (!DeserializeReferenceFromPb(pb_symbol.name(), &symbol.symbol)) {
- return {};
- }
- symbol.value = pb_symbol.value();
- attr->symbols.push_back(std::move(symbol));
- }
- value = std::move(attr);
-
- } else if (pb_compound_value.has_style()) {
- const pb::Style& pb_style = pb_compound_value.style();
- std::unique_ptr<Style> style = util::make_unique<Style>();
- if (pb_style.has_parent()) {
- style->parent = Reference();
- if (!DeserializeReferenceFromPb(pb_style.parent(), &style->parent.value())) {
- return {};
- }
-
- if (pb_style.has_parent_source()) {
- Source parent_source;
- DeserializeSourceFromPb(pb_style.parent_source(), *source_pool_, &parent_source);
- style->parent.value().SetSource(std::move(parent_source));
- }
- }
-
- for (const pb::Style_Entry& pb_entry : pb_style.entry()) {
- Style::Entry entry;
- DeserializeItemCommon(pb_entry, &entry.key);
- if (!DeserializeReferenceFromPb(pb_entry.key(), &entry.key)) {
- return {};
- }
-
- entry.value = DeserializeItemFromPb(pb_entry.item(), config, pool);
- if (!entry.value) {
- return {};
- }
-
- DeserializeItemCommon(pb_entry, entry.value.get());
- style->entries.push_back(std::move(entry));
- }
- value = std::move(style);
-
- } else if (pb_compound_value.has_styleable()) {
- const pb::Styleable& pb_styleable = pb_compound_value.styleable();
- std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
- for (const pb::Styleable_Entry& pb_entry : pb_styleable.entry()) {
- Reference attr_ref;
- DeserializeItemCommon(pb_entry, &attr_ref);
- DeserializeReferenceFromPb(pb_entry.attr(), &attr_ref);
- styleable->entries.push_back(std::move(attr_ref));
- }
- value = std::move(styleable);
-
- } else if (pb_compound_value.has_array()) {
- const pb::Array& pb_array = pb_compound_value.array();
- std::unique_ptr<Array> array = util::make_unique<Array>();
- for (const pb::Array_Element& pb_entry : pb_array.element()) {
- std::unique_ptr<Item> item = DeserializeItemFromPb(pb_entry.item(), config, pool);
- if (!item) {
- return {};
- }
-
- DeserializeItemCommon(pb_entry, item.get());
- array->elements.push_back(std::move(item));
- }
- value = std::move(array);
-
- } else if (pb_compound_value.has_plural()) {
- const pb::Plural& pb_plural = pb_compound_value.plural();
- std::unique_ptr<Plural> plural = util::make_unique<Plural>();
- for (const pb::Plural_Entry& pb_entry : pb_plural.entry()) {
- size_t pluralIdx = DeserializePluralEnumFromPb(pb_entry.arity());
- plural->values[pluralIdx] = DeserializeItemFromPb(pb_entry.item(), config, pool);
- if (!plural->values[pluralIdx]) {
- return {};
- }
-
- DeserializeItemCommon(pb_entry, plural->values[pluralIdx].get());
- }
- value = std::move(plural);
-
- } else {
- diag_->Error(DiagMessage(source_) << "unknown compound value");
- return {};
- }
- } else {
- diag_->Error(DiagMessage(source_) << "unknown value");
- return {};
- }
-
- CHECK(value) << "forgot to set value";
-
- value->SetWeak(pb_value.weak());
- DeserializeItemCommon(pb_value, value.get());
- return value;
- }
-
- bool DeserializeReferenceFromPb(const pb::Reference& pb_ref, Reference* out_ref) {
- out_ref->reference_type = DeserializeReferenceTypeFromPb(pb_ref.type());
- out_ref->private_reference = pb_ref.private_();
-
- if (pb_ref.has_id()) {
- out_ref->id = ResourceId(pb_ref.id());
- }
-
- if (pb_ref.has_name()) {
- ResourceNameRef name_ref;
- if (!ResourceUtils::ParseResourceName(pb_ref.name(), &name_ref, nullptr)) {
- diag_->Error(DiagMessage(source_) << "invalid reference name '" << pb_ref.name() << "'");
- return false;
- }
-
- out_ref->name = name_ref.ToResourceName();
- }
- return true;
- }
-
- template <typename T>
- void DeserializeItemCommon(const T& pb_item, Value* out_value) {
- if (pb_item.has_source()) {
- Source source;
- DeserializeSourceFromPb(pb_item.source(), *source_pool_, &source);
- out_value->SetSource(std::move(source));
- }
-
- if (pb_item.has_comment()) {
- out_value->SetComment(pb_item.comment());
- }
- }
-
- private:
- const android::ResStringPool* source_pool_;
- const Source source_;
- IDiagnostics* diag_;
-};
-
-} // namespace
-
-std::unique_ptr<ResourceTable> DeserializeTableFromPb(const pb::ResourceTable& pb_table,
- const Source& source, IDiagnostics* diag) {
- // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which
- // causes errors when qualifying it with android::
- using namespace android;
-
- std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
-
- ResStringPool source_pool;
- if (pb_table.has_source_pool()) {
- status_t result = source_pool.setTo(pb_table.source_pool().data().data(),
- pb_table.source_pool().data().size());
- if (result != NO_ERROR) {
- diag->Error(DiagMessage(source) << "invalid source pool");
- return {};
- }
- }
-
- PackagePbDeserializer package_pb_deserializer(&source_pool, source, diag);
- for (const pb::Package& pb_package : pb_table.package()) {
- if (!package_pb_deserializer.DeserializeFromPb(pb_package, table.get())) {
- return {};
- }
- }
- return table;
-}
-
-std::unique_ptr<ResourceFile> DeserializeCompiledFileFromPb(
- const pb::internal::CompiledFile& pb_file, const Source& source, IDiagnostics* diag) {
- std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>();
-
- ResourceNameRef name_ref;
-
- // Need to create an lvalue here so that nameRef can point to something real.
- if (!ResourceUtils::ParseResourceName(pb_file.resource_name(), &name_ref)) {
- diag->Error(DiagMessage(source)
- << "invalid resource name in compiled file header: "
- << pb_file.resource_name());
- return {};
- }
- file->name = name_ref.ToResourceName();
- file->source.path = pb_file.source_path();
- DeserializeConfigDescriptionFromPb(pb_file.config(), &file->config);
-
- for (const pb::internal::CompiledFile_Symbol& pb_symbol : pb_file.exported_symbol()) {
- // Need to create an lvalue here so that nameRef can point to something real.
- if (!ResourceUtils::ParseResourceName(pb_symbol.resource_name(), &name_ref)) {
- diag->Error(DiagMessage(source)
- << "invalid resource name for exported symbol in "
- "compiled file header: "
- << pb_file.resource_name());
- return {};
- }
- size_t line = 0u;
- if (pb_symbol.has_source()) {
- line = pb_symbol.source().line_number();
- }
- file->exported_symbols.push_back(SourcedResourceName{name_ref.ToResourceName(), line});
- }
- return file;
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp
deleted file mode 100644
index a08df71..0000000
--- a/tools/aapt2/proto/TableProtoSerializer.cpp
+++ /dev/null
@@ -1,399 +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.
- */
-
-#include "Resource.h"
-#include "ResourceTable.h"
-#include "StringPool.h"
-#include "ValueVisitor.h"
-#include "proto/ProtoHelpers.h"
-#include "proto/ProtoSerialize.h"
-#include "util/BigBuffer.h"
-
-#include "android-base/logging.h"
-
-using ::google::protobuf::io::CodedInputStream;
-using ::google::protobuf::io::CodedOutputStream;
-using ::google::protobuf::io::ZeroCopyOutputStream;
-
-namespace aapt {
-
-namespace {
-
-class PbSerializerVisitor : public RawValueVisitor {
- public:
- using RawValueVisitor::Visit;
-
- // Constructor to use when expecting to serialize any value.
- PbSerializerVisitor(StringPool* source_pool, pb::Value* out_pb_value)
- : source_pool_(source_pool), out_pb_value_(out_pb_value), out_pb_item_(nullptr) {
- }
-
- // Constructor to use when expecting to serialize an Item.
- PbSerializerVisitor(StringPool* sourcePool, pb::Item* outPbItem)
- : source_pool_(sourcePool), out_pb_value_(nullptr), out_pb_item_(outPbItem) {
- }
-
- void Visit(Reference* ref) override {
- SerializeReferenceToPb(*ref, pb_item()->mutable_ref());
- }
-
- void Visit(String* str) override {
- pb_item()->mutable_str()->set_value(*str->value);
- }
-
- void Visit(RawString* str) override {
- pb_item()->mutable_raw_str()->set_value(*str->value);
- }
-
- void Visit(StyledString* str) override {
- pb::StyledString* pb_str = pb_item()->mutable_styled_str();
- pb_str->set_value(str->value->value);
-
- for (const StringPool::Span& span : str->value->spans) {
- pb::StyledString::Span* pb_span = pb_str->add_span();
- pb_span->set_tag(*span.name);
- pb_span->set_first_char(span.first_char);
- pb_span->set_last_char(span.last_char);
- }
- }
-
- void Visit(FileReference* file) override {
- pb_item()->mutable_file()->set_path(*file->path);
- }
-
- void Visit(Id* /*id*/) override {
- pb_item()->mutable_id();
- }
-
- void Visit(BinaryPrimitive* prim) override {
- android::Res_value val = {};
- prim->Flatten(&val);
-
- pb::Primitive* pb_prim = pb_item()->mutable_prim();
- pb_prim->set_type(val.dataType);
- pb_prim->set_data(val.data);
- }
-
- void VisitItem(Item* item) override {
- LOG(FATAL) << "unimplemented item";
- }
-
- void Visit(Attribute* attr) override {
- pb::Attribute* pb_attr = pb_compound_value()->mutable_attr();
- pb_attr->set_format_flags(attr->type_mask);
- pb_attr->set_min_int(attr->min_int);
- pb_attr->set_max_int(attr->max_int);
-
- for (auto& symbol : attr->symbols) {
- pb::Attribute_Symbol* pb_symbol = pb_attr->add_symbol();
- SerializeItemCommonToPb(symbol.symbol, pb_symbol);
- SerializeReferenceToPb(symbol.symbol, pb_symbol->mutable_name());
- pb_symbol->set_value(symbol.value);
- }
- }
-
- void Visit(Style* style) override {
- pb::Style* pb_style = pb_compound_value()->mutable_style();
- if (style->parent) {
- SerializeReferenceToPb(style->parent.value(), pb_style->mutable_parent());
- SerializeSourceToPb(style->parent.value().GetSource(), source_pool_,
- pb_style->mutable_parent_source());
- }
-
- for (Style::Entry& entry : style->entries) {
- pb::Style_Entry* pb_entry = pb_style->add_entry();
- SerializeReferenceToPb(entry.key, pb_entry->mutable_key());
-
- pb::Item* pb_item = pb_entry->mutable_item();
- SerializeItemCommonToPb(entry.key, pb_entry);
- PbSerializerVisitor sub_visitor(source_pool_, pb_item);
- entry.value->Accept(&sub_visitor);
- }
- }
-
- void Visit(Styleable* styleable) override {
- pb::Styleable* pb_styleable = pb_compound_value()->mutable_styleable();
- for (Reference& entry : styleable->entries) {
- pb::Styleable_Entry* pb_entry = pb_styleable->add_entry();
- SerializeItemCommonToPb(entry, pb_entry);
- SerializeReferenceToPb(entry, pb_entry->mutable_attr());
- }
- }
-
- void Visit(Array* array) override {
- pb::Array* pb_array = pb_compound_value()->mutable_array();
- for (auto& value : array->elements) {
- pb::Array_Element* pb_element = pb_array->add_element();
- SerializeItemCommonToPb(*value, pb_element);
- PbSerializerVisitor sub_visitor(source_pool_, pb_element->mutable_item());
- value->Accept(&sub_visitor);
- }
- }
-
- void Visit(Plural* plural) override {
- pb::Plural* pb_plural = pb_compound_value()->mutable_plural();
- const size_t count = plural->values.size();
- for (size_t i = 0; i < count; i++) {
- if (!plural->values[i]) {
- // No plural value set here.
- continue;
- }
-
- pb::Plural_Entry* pb_entry = pb_plural->add_entry();
- pb_entry->set_arity(SerializePluralEnumToPb(i));
- pb::Item* pb_element = pb_entry->mutable_item();
- SerializeItemCommonToPb(*plural->values[i], pb_entry);
- PbSerializerVisitor sub_visitor(source_pool_, pb_element);
- plural->values[i]->Accept(&sub_visitor);
- }
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PbSerializerVisitor);
-
- pb::Item* pb_item() {
- if (out_pb_value_) {
- return out_pb_value_->mutable_item();
- }
- return out_pb_item_;
- }
-
- pb::CompoundValue* pb_compound_value() {
- CHECK(out_pb_value_ != nullptr);
- return out_pb_value_->mutable_compound_value();
- }
-
- template <typename T>
- void SerializeItemCommonToPb(const Item& item, T* pb_item) {
- SerializeSourceToPb(item.GetSource(), source_pool_, pb_item->mutable_source());
- if (!item.GetComment().empty()) {
- pb_item->set_comment(item.GetComment());
- }
- }
-
- void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) {
- if (ref.id) {
- pb_ref->set_id(ref.id.value().id);
- }
-
- if (ref.name) {
- pb_ref->set_name(ref.name.value().ToString());
- }
-
- pb_ref->set_private_(ref.private_reference);
- pb_ref->set_type(SerializeReferenceTypeToPb(ref.reference_type));
- }
-
- StringPool* source_pool_;
- pb::Value* out_pb_value_;
- pb::Item* out_pb_item_;
-};
-
-} // namespace
-
-std::unique_ptr<pb::ResourceTable> SerializeTableToPb(ResourceTable* table) {
- // We must do this before writing the resources, since the string pool IDs may change.
- table->string_pool.Prune();
- table->string_pool.Sort([](const StringPool::Context& a, const StringPool::Context& b) -> int {
- int diff = util::compare(a.priority, b.priority);
- if (diff == 0) {
- diff = a.config.compare(b.config);
- }
- return diff;
- });
-
- auto pb_table = util::make_unique<pb::ResourceTable>();
- StringPool source_pool;
-
- for (auto& package : table->packages) {
- pb::Package* pb_package = pb_table->add_package();
- if (package->id) {
- pb_package->set_package_id(package->id.value());
- }
- pb_package->set_package_name(package->name);
-
- for (auto& type : package->types) {
- pb::Type* pb_type = pb_package->add_type();
- if (type->id) {
- pb_type->set_id(type->id.value());
- }
- pb_type->set_name(ToString(type->type).to_string());
-
- for (auto& entry : type->entries) {
- pb::Entry* pb_entry = pb_type->add_entry();
- if (entry->id) {
- pb_entry->set_id(entry->id.value());
- }
- pb_entry->set_name(entry->name);
-
- // Write the SymbolStatus struct.
- pb::SymbolStatus* pb_status = pb_entry->mutable_symbol_status();
- pb_status->set_visibility(SerializeVisibilityToPb(entry->symbol_status.state));
- SerializeSourceToPb(entry->symbol_status.source, &source_pool, pb_status->mutable_source());
- pb_status->set_comment(entry->symbol_status.comment);
- pb_status->set_allow_new(entry->symbol_status.allow_new);
-
- for (auto& config_value : entry->values) {
- pb::ConfigValue* pb_config_value = pb_entry->add_config_value();
- SerializeConfig(config_value->config, pb_config_value->mutable_config());
- if (!config_value->product.empty()) {
- pb_config_value->mutable_config()->set_product(config_value->product);
- }
-
- pb::Value* pb_value = pb_config_value->mutable_value();
- SerializeSourceToPb(config_value->value->GetSource(), &source_pool,
- pb_value->mutable_source());
- if (!config_value->value->GetComment().empty()) {
- pb_value->set_comment(config_value->value->GetComment());
- }
-
- if (config_value->value->IsWeak()) {
- pb_value->set_weak(true);
- }
-
- PbSerializerVisitor visitor(&source_pool, pb_value);
- config_value->value->Accept(&visitor);
- }
- }
- }
- }
-
- SerializeStringPoolToPb(source_pool, pb_table->mutable_source_pool());
- return pb_table;
-}
-
-std::unique_ptr<pb::internal::CompiledFile> SerializeCompiledFileToPb(const ResourceFile& file) {
- auto pb_file = util::make_unique<pb::internal::CompiledFile>();
- pb_file->set_resource_name(file.name.ToString());
- pb_file->set_source_path(file.source.path);
- SerializeConfig(file.config, pb_file->mutable_config());
-
- for (const SourcedResourceName& exported : file.exported_symbols) {
- pb::internal::CompiledFile_Symbol* pb_symbol = pb_file->add_exported_symbol();
- pb_symbol->set_resource_name(exported.name.ToString());
- pb_symbol->mutable_source()->set_line_number(exported.line);
- }
- return pb_file;
-}
-
-CompiledFileOutputStream::CompiledFileOutputStream(ZeroCopyOutputStream* out) : out_(out) {
-}
-
-void CompiledFileOutputStream::EnsureAlignedWrite() {
- const int padding = out_.ByteCount() % 4;
- if (padding > 0) {
- uint32_t zero = 0u;
- out_.WriteRaw(&zero, padding);
- }
-}
-
-void CompiledFileOutputStream::WriteLittleEndian32(uint32_t val) {
- EnsureAlignedWrite();
- out_.WriteLittleEndian32(val);
-}
-
-void CompiledFileOutputStream::WriteCompiledFile(const pb::internal::CompiledFile* compiled_file) {
- EnsureAlignedWrite();
- out_.WriteLittleEndian64(static_cast<uint64_t>(compiled_file->ByteSize()));
- compiled_file->SerializeWithCachedSizes(&out_);
-}
-
-void CompiledFileOutputStream::WriteData(const BigBuffer* buffer) {
- EnsureAlignedWrite();
- out_.WriteLittleEndian64(static_cast<uint64_t>(buffer->size()));
- for (const BigBuffer::Block& block : *buffer) {
- out_.WriteRaw(block.buffer.get(), block.size);
- }
-}
-
-void CompiledFileOutputStream::WriteData(const void* data, size_t len) {
- EnsureAlignedWrite();
- out_.WriteLittleEndian64(static_cast<uint64_t>(len));
- out_.WriteRaw(data, len);
-}
-
-bool CompiledFileOutputStream::HadError() {
- return out_.HadError();
-}
-
-CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size)
- : in_(static_cast<const uint8_t*>(data), size) {}
-
-void CompiledFileInputStream::EnsureAlignedRead() {
- const int padding = in_.CurrentPosition() % 4;
- if (padding > 0) {
- // Reads are always 4 byte aligned.
- in_.Skip(padding);
- }
-}
-
-bool CompiledFileInputStream::ReadLittleEndian32(uint32_t* out_val) {
- EnsureAlignedRead();
- return in_.ReadLittleEndian32(out_val);
-}
-
-bool CompiledFileInputStream::ReadCompiledFile(pb::internal::CompiledFile* out_val) {
- EnsureAlignedRead();
-
- google::protobuf::uint64 pb_size = 0u;
- if (!in_.ReadLittleEndian64(&pb_size)) {
- return false;
- }
-
- CodedInputStream::Limit l = in_.PushLimit(static_cast<int>(pb_size));
-
- // Check that we haven't tried to read past the end.
- if (static_cast<uint64_t>(in_.BytesUntilLimit()) != pb_size) {
- in_.PopLimit(l);
- in_.PushLimit(0);
- return false;
- }
-
- if (!out_val->ParsePartialFromCodedStream(&in_)) {
- in_.PopLimit(l);
- in_.PushLimit(0);
- return false;
- }
-
- in_.PopLimit(l);
- return true;
-}
-
-bool CompiledFileInputStream::ReadDataMetaData(uint64_t* out_offset, uint64_t* out_len) {
- EnsureAlignedRead();
-
- google::protobuf::uint64 pb_size = 0u;
- if (!in_.ReadLittleEndian64(&pb_size)) {
- return false;
- }
-
- // Check that we aren't trying to read past the end.
- if (pb_size > static_cast<uint64_t>(in_.BytesUntilLimit())) {
- in_.PushLimit(0);
- return false;
- }
-
- uint64_t offset = static_cast<uint64_t>(in_.CurrentPosition());
- if (!in_.Skip(pb_size)) {
- return false;
- }
-
- *out_offset = offset;
- *out_len = pb_size;
- return true;
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/proto/TableProtoSerializer_test.cpp b/tools/aapt2/proto/TableProtoSerializer_test.cpp
deleted file mode 100644
index 80608b3..0000000
--- a/tools/aapt2/proto/TableProtoSerializer_test.cpp
+++ /dev/null
@@ -1,242 +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.
- */
-
-#include "proto/ProtoSerialize.h"
-
-#include "ResourceTable.h"
-#include "test/Test.h"
-
-using ::google::protobuf::io::StringOutputStream;
-using ::testing::Eq;
-using ::testing::NotNull;
-using ::testing::SizeIs;
-
-namespace aapt {
-
-TEST(TableProtoSerializer, SerializeSinglePackage) {
- std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
- std::unique_ptr<ResourceTable> table =
- test::ResourceTableBuilder()
- .SetPackageId("com.app.a", 0x7f)
- .AddFileReference("com.app.a:layout/main", ResourceId(0x7f020000), "res/layout/main.xml")
- .AddReference("com.app.a:layout/other", ResourceId(0x7f020001), "com.app.a:layout/main")
- .AddString("com.app.a:string/text", {}, "hi")
- .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
- .SetSymbolState("com.app.a:bool/foo", {}, SymbolState::kUndefined, true /*allow_new*/)
- .Build();
-
- Symbol public_symbol;
- public_symbol.state = SymbolState::kPublic;
- ASSERT_TRUE(table->SetSymbolState(test::ParseNameOrDie("com.app.a:layout/main"),
- ResourceId(0x7f020000), public_symbol,
- context->GetDiagnostics()));
-
- Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
- ASSERT_THAT(id, NotNull());
-
- // Make a plural.
- std::unique_ptr<Plural> plural = util::make_unique<Plural>();
- plural->values[Plural::One] = util::make_unique<String>(table->string_pool.MakeRef("one"));
- ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:plurals/hey"),
- ConfigDescription{}, {}, std::move(plural),
- context->GetDiagnostics()));
-
- // Make a styled string.
- StyleString style_string;
- style_string.str = "hello";
- style_string.spans.push_back(Span{"b", 0u, 4u});
- ASSERT_TRUE(
- table->AddResource(test::ParseNameOrDie("com.app.a:string/styled"), ConfigDescription{}, {},
- util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)),
- context->GetDiagnostics()));
-
- // Make a resource with different products.
- ASSERT_TRUE(table->AddResource(
- test::ParseNameOrDie("com.app.a:integer/one"),
- test::ParseConfigOrDie("land"), {},
- test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u),
- context->GetDiagnostics()));
- ASSERT_TRUE(table->AddResource(
- test::ParseNameOrDie("com.app.a:integer/one"),
- test::ParseConfigOrDie("land"), "tablet",
- test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u),
- context->GetDiagnostics()));
-
- // Make a reference with both resource name and resource ID.
- // The reference should point to a resource outside of this table to test that both name and id
- // get serialized.
- Reference expected_ref;
- expected_ref.name = test::ParseNameOrDie("android:layout/main");
- expected_ref.id = ResourceId(0x01020000);
- ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:layout/abc"),
- ConfigDescription::DefaultConfig(), {},
- util::make_unique<Reference>(expected_ref),
- context->GetDiagnostics()));
-
- std::unique_ptr<pb::ResourceTable> pb_table = SerializeTableToPb(table.get());
- ASSERT_THAT(pb_table, NotNull());
-
- std::unique_ptr<ResourceTable> new_table = DeserializeTableFromPb(
- *pb_table, Source{"test"}, context->GetDiagnostics());
- ASSERT_THAT(new_table, NotNull());
-
- Id* new_id = test::GetValue<Id>(new_table.get(), "com.app.a:id/foo");
- ASSERT_THAT(new_id, NotNull());
- EXPECT_THAT(new_id->IsWeak(), Eq(id->IsWeak()));
-
- Maybe<ResourceTable::SearchResult> result =
- new_table->FindResource(test::ParseNameOrDie("com.app.a:layout/main"));
- ASSERT_TRUE(result);
-
- EXPECT_THAT(result.value().type->symbol_status.state, Eq(SymbolState::kPublic));
- EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kPublic));
-
- result = new_table->FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
- ASSERT_TRUE(result);
- EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kUndefined));
- EXPECT_TRUE(result.value().entry->symbol_status.allow_new);
-
- // Find the product-dependent values
- BinaryPrimitive* prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
- new_table.get(), "com.app.a:integer/one", test::ParseConfigOrDie("land"), "");
- ASSERT_THAT(prim, NotNull());
- EXPECT_THAT(prim->value.data, Eq(123u));
-
- prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
- new_table.get(), "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet");
- ASSERT_THAT(prim, NotNull());
- EXPECT_THAT(prim->value.data, Eq(321u));
-
- Reference* actual_ref = test::GetValue<Reference>(new_table.get(), "com.app.a:layout/abc");
- ASSERT_THAT(actual_ref, NotNull());
- ASSERT_TRUE(actual_ref->name);
- ASSERT_TRUE(actual_ref->id);
- EXPECT_THAT(*actual_ref, Eq(expected_ref));
-
- StyledString* actual_styled_str =
- test::GetValue<StyledString>(new_table.get(), "com.app.a:string/styled");
- ASSERT_THAT(actual_styled_str, NotNull());
- EXPECT_THAT(actual_styled_str->value->value, Eq("hello"));
- ASSERT_THAT(actual_styled_str->value->spans, SizeIs(1u));
- EXPECT_THAT(*actual_styled_str->value->spans[0].name, Eq("b"));
- EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u));
- EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
-}
-
-TEST(TableProtoSerializer, SerializeFileHeader) {
- std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-
- ResourceFile f;
- f.config = test::ParseConfigOrDie("hdpi-v9");
- f.name = test::ParseNameOrDie("com.app.a:layout/main");
- f.source.path = "res/layout-hdpi-v9/main.xml";
- f.exported_symbols.push_back(
- SourcedResourceName{test::ParseNameOrDie("id/unchecked"), 23u});
-
- const std::string expected_data1 = "123";
- const std::string expected_data2 = "1234";
-
- std::string output_str;
- {
- std::unique_ptr<pb::internal::CompiledFile> pb_file1 = SerializeCompiledFileToPb(f);
-
- f.name.entry = "__" + f.name.entry + "$0";
- std::unique_ptr<pb::internal::CompiledFile> pb_file2 = SerializeCompiledFileToPb(f);
-
- StringOutputStream out_stream(&output_str);
- CompiledFileOutputStream out_file_stream(&out_stream);
- out_file_stream.WriteLittleEndian32(2);
- out_file_stream.WriteCompiledFile(pb_file1.get());
- out_file_stream.WriteData(expected_data1.data(), expected_data1.size());
- out_file_stream.WriteCompiledFile(pb_file2.get());
- out_file_stream.WriteData(expected_data2.data(), expected_data2.size());
- ASSERT_FALSE(out_file_stream.HadError());
- }
-
- CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
- uint32_t num_files = 0;
- ASSERT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
- ASSERT_EQ(2u, num_files);
-
- // Read the first compiled file.
-
- pb::internal::CompiledFile new_pb_file;
- ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_file));
-
- std::unique_ptr<ResourceFile> file = DeserializeCompiledFileFromPb(
- new_pb_file, Source("test"), context->GetDiagnostics());
- ASSERT_THAT(file, NotNull());
-
- uint64_t offset, len;
- ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
-
- std::string actual_data(output_str.data() + offset, len);
- EXPECT_EQ(expected_data1, actual_data);
-
- // Expect the data to be aligned.
- EXPECT_EQ(0u, offset & 0x03);
-
- ASSERT_EQ(1u, file->exported_symbols.size());
- EXPECT_EQ(test::ParseNameOrDie("id/unchecked"), file->exported_symbols[0].name);
-
- // Read the second compiled file.
-
- ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_file));
-
- file = DeserializeCompiledFileFromPb(new_pb_file, Source("test"), context->GetDiagnostics());
- ASSERT_THAT(file, NotNull());
-
- ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
-
- actual_data = std::string(output_str.data() + offset, len);
- EXPECT_EQ(expected_data2, actual_data);
-
- // Expect the data to be aligned.
- EXPECT_EQ(0u, offset & 0x03);
-}
-
-TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) {
- ResourceFile f;
- std::unique_ptr<pb::internal::CompiledFile> pb_file = SerializeCompiledFileToPb(f);
-
- const std::string expected_data = "1234";
-
- std::string output_str;
- {
- StringOutputStream out_stream(&output_str);
- CompiledFileOutputStream out_file_stream(&out_stream);
- out_file_stream.WriteLittleEndian32(1);
- out_file_stream.WriteCompiledFile(pb_file.get());
- out_file_stream.WriteData(expected_data.data(), expected_data.size());
- ASSERT_FALSE(out_file_stream.HadError());
- }
-
- output_str[4] = 0xff;
-
- CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
-
- uint32_t num_files = 0;
- EXPECT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
- EXPECT_EQ(1u, num_files);
-
- pb::internal::CompiledFile new_pb_file;
- EXPECT_FALSE(in_file_stream.ReadCompiledFile(&new_pb_file));
-
- uint64_t offset, len;
- EXPECT_FALSE(in_file_stream.ReadDataMetaData(&offset, &len));
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp
index 892aee6..b87278b 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp
@@ -44,9 +44,9 @@
// Visitor that converts a reference's resource ID to a resource name, given a mapping from
// resource ID to resource name.
-class ReferenceIdToNameVisitor : public ValueVisitor {
+class ReferenceIdToNameVisitor : public DescendingValueVisitor {
public:
- using ValueVisitor::Visit;
+ using DescendingValueVisitor::Visit;
explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceName>* mapping)
: mapping_(mapping) {
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 32ec7bc..b3e0a92 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -461,6 +461,12 @@
visitor->AfterVisitElement(this);
}
+void Element::Accept(ConstVisitor* visitor) const {
+ visitor->BeforeVisitElement(this);
+ visitor->Visit(this);
+ visitor->AfterVisitElement(this);
+}
+
std::unique_ptr<Node> Text::Clone(const ElementCloneFunc&) const {
auto t = util::make_unique<Text>();
t->comment = comment;
@@ -474,6 +480,10 @@
visitor->Visit(this);
}
+void Text::Accept(ConstVisitor* visitor) const {
+ visitor->Visit(this);
+}
+
void PackageAwareVisitor::BeforeVisitElement(Element* el) {
std::vector<PackageDecl> decls;
for (const NamespaceDecl& decl : el->namespace_decls) {
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index 9a9151d..063d7b9 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -35,6 +35,7 @@
class Element;
class Visitor;
+class ConstVisitor;
// Base class for all XML nodes.
class Node {
@@ -47,6 +48,7 @@
std::string comment;
virtual void Accept(Visitor* visitor) = 0;
+ virtual void Accept(ConstVisitor* visitor) const = 0;
using ElementCloneFunc = std::function<void(const Element&, Element*)>;
@@ -112,6 +114,7 @@
std::unique_ptr<Node> Clone(const ElementCloneFunc& el_cloner) const override;
void Accept(Visitor* visitor) override;
+ void Accept(ConstVisitor* visitor) const override;
};
// A Text (CDATA) XML node. Can not have any children.
@@ -122,6 +125,7 @@
std::unique_ptr<Node> Clone(const ElementCloneFunc& el_cloner) const override;
void Accept(Visitor* visitor) override;
+ void Accept(ConstVisitor* visitor) const override;
};
// An XML resource with a source, name, and XML tree.
@@ -180,6 +184,38 @@
friend class Element;
};
+class ConstVisitor {
+ public:
+ virtual ~ConstVisitor() = default;
+
+ virtual void Visit(const Element* el) {
+ VisitChildren(el);
+ }
+
+ virtual void Visit(const Text* text) {
+ }
+
+ protected:
+ ConstVisitor() = default;
+
+ void VisitChildren(const Element* el) {
+ for (const auto& child : el->children) {
+ child->Accept(this);
+ }
+ }
+
+ virtual void BeforeVisitElement(const Element* el) {
+ }
+
+ virtual void AfterVisitElement(const Element* el) {
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConstVisitor);
+
+ friend class Element;
+};
+
// An XML DOM visitor that will record the package name for a namespace prefix.
class PackageAwareVisitor : public Visitor, public IPackageDeclStack {
public:
@@ -207,19 +243,19 @@
namespace internal {
// Base class that overrides the default behaviour and does not descend into child nodes.
-class NodeCastBase : public Visitor {
+class NodeCastBase : public ConstVisitor {
public:
- void Visit(Element* el) override {
+ void Visit(const Element* el) override {
}
- void Visit(Text* el) override {
+ void Visit(const Text* el) override {
}
protected:
NodeCastBase() = default;
- void BeforeVisitElement(Element* el) override {
+ void BeforeVisitElement(const Element* el) override {
}
- void AfterVisitElement(Element* el) override {
+ void AfterVisitElement(const Element* el) override {
}
private:
@@ -233,9 +269,9 @@
NodeCastImpl() = default;
- T* value = nullptr;
+ const T* value = nullptr;
- void Visit(T* v) override {
+ void Visit(const T* v) override {
value = v;
}
@@ -246,12 +282,17 @@
} // namespace internal
template <typename T>
-T* NodeCast(Node* node) {
+const T* NodeCast(const Node* node) {
internal::NodeCastImpl<T> visitor;
node->Accept(&visitor);
return visitor.value;
}
+template <typename T>
+T* NodeCast(Node* node) {
+ return const_cast<T*>(NodeCast<T>(static_cast<const T*>(node)));
+}
+
} // namespace xml
} // namespace aapt