Merge "Move apache specific portions of android.net.http to external/apache-http."
diff --git a/api/current.txt b/api/current.txt
index f45e019..d1b6ba0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2086,6 +2086,21 @@
field public static final int Theme_Light_Panel = 16973914; // 0x103005a
field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
field public static final int Theme_Material = 16974372; // 0x1030224
+ field public static final int Theme_Material_DayNight = 16974548; // 0x10302d4
+ field public static final int Theme_Material_DayNight_DarkActionBar = 16974549; // 0x10302d5
+ field public static final int Theme_Material_DayNight_Dialog = 16974550; // 0x10302d6
+ field public static final int Theme_Material_DayNight_DialogWhenLarge = 16974556; // 0x10302dc
+ field public static final int Theme_Material_DayNight_DialogWhenLarge_NoActionBar = 16974557; // 0x10302dd
+ field public static final int Theme_Material_DayNight_Dialog_Alert = 16974551; // 0x10302d7
+ field public static final int Theme_Material_DayNight_Dialog_MinWidth = 16974552; // 0x10302d8
+ field public static final int Theme_Material_DayNight_Dialog_NoActionBar = 16974553; // 0x10302d9
+ field public static final int Theme_Material_DayNight_Dialog_NoActionBar_MinWidth = 16974554; // 0x10302da
+ field public static final int Theme_Material_DayNight_Dialog_Presentation = 16974555; // 0x10302db
+ field public static final int Theme_Material_DayNight_NoActionBar = 16974558; // 0x10302de
+ field public static final int Theme_Material_DayNight_NoActionBar_Fullscreen = 16974559; // 0x10302df
+ field public static final int Theme_Material_DayNight_NoActionBar_Overscan = 16974560; // 0x10302e0
+ field public static final int Theme_Material_DayNight_NoActionBar_TranslucentDecor = 16974561; // 0x10302e1
+ field public static final int Theme_Material_DayNight_Panel = 16974562; // 0x10302e2
field public static final int Theme_Material_Dialog = 16974373; // 0x1030225
field public static final int Theme_Material_DialogWhenLarge = 16974379; // 0x103022b
field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974380; // 0x103022c
@@ -11985,8 +12000,10 @@
public class LayerDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
ctor public LayerDrawable(android.graphics.drawable.Drawable[]);
+ method public int addLayer(android.graphics.drawable.Drawable);
method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
+ method public int findIndexByLayerId(int);
method public android.graphics.drawable.Drawable getDrawable(int);
method public int getId(int);
method public int getLayerGravity(int);
@@ -11999,6 +12016,7 @@
method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
method public void setAlpha(int);
method public void setColorFilter(android.graphics.ColorFilter);
+ method public void setDrawable(int, android.graphics.drawable.Drawable);
method public boolean setDrawableByLayerId(int, android.graphics.drawable.Drawable);
method public void setId(int, int);
method public void setLayerGravity(int, int);
@@ -31765,6 +31783,7 @@
method public android.transition.Transition addTarget(java.lang.String);
method public android.transition.Transition addTarget(java.lang.Class);
method public android.transition.Transition addTarget(android.view.View);
+ method protected boolean areValuesChanged(android.transition.TransitionValues, android.transition.TransitionValues);
method public boolean canRemoveViews();
method public abstract void captureEndValues(android.transition.TransitionValues);
method public abstract void captureStartValues(android.transition.TransitionValues);
@@ -32019,6 +32038,7 @@
method public boolean equals(android.util.DisplayMetrics);
method public void setTo(android.util.DisplayMetrics);
method public void setToDefaults();
+ field public static final int DENSITY_280 = 280; // 0x118
field public static final int DENSITY_400 = 400; // 0x190
field public static final int DENSITY_560 = 560; // 0x230
field public static final int DENSITY_DEFAULT = 160; // 0xa0
diff --git a/api/system-current.txt b/api/system-current.txt
index 3011f2f..fd6e2c8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2165,6 +2165,21 @@
field public static final int Theme_Light_Panel = 16973914; // 0x103005a
field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
field public static final int Theme_Material = 16974372; // 0x1030224
+ field public static final int Theme_Material_DayNight = 16974548; // 0x10302d4
+ field public static final int Theme_Material_DayNight_DarkActionBar = 16974549; // 0x10302d5
+ field public static final int Theme_Material_DayNight_Dialog = 16974550; // 0x10302d6
+ field public static final int Theme_Material_DayNight_DialogWhenLarge = 16974556; // 0x10302dc
+ field public static final int Theme_Material_DayNight_DialogWhenLarge_NoActionBar = 16974557; // 0x10302dd
+ field public static final int Theme_Material_DayNight_Dialog_Alert = 16974551; // 0x10302d7
+ field public static final int Theme_Material_DayNight_Dialog_MinWidth = 16974552; // 0x10302d8
+ field public static final int Theme_Material_DayNight_Dialog_NoActionBar = 16974553; // 0x10302d9
+ field public static final int Theme_Material_DayNight_Dialog_NoActionBar_MinWidth = 16974554; // 0x10302da
+ field public static final int Theme_Material_DayNight_Dialog_Presentation = 16974555; // 0x10302db
+ field public static final int Theme_Material_DayNight_NoActionBar = 16974558; // 0x10302de
+ field public static final int Theme_Material_DayNight_NoActionBar_Fullscreen = 16974559; // 0x10302df
+ field public static final int Theme_Material_DayNight_NoActionBar_Overscan = 16974560; // 0x10302e0
+ field public static final int Theme_Material_DayNight_NoActionBar_TranslucentDecor = 16974561; // 0x10302e1
+ field public static final int Theme_Material_DayNight_Panel = 16974562; // 0x10302e2
field public static final int Theme_Material_Dialog = 16974373; // 0x1030225
field public static final int Theme_Material_DialogWhenLarge = 16974379; // 0x103022b
field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974380; // 0x103022c
@@ -12259,8 +12274,10 @@
public class LayerDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
ctor public LayerDrawable(android.graphics.drawable.Drawable[]);
+ method public int addLayer(android.graphics.drawable.Drawable);
method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
+ method public int findIndexByLayerId(int);
method public android.graphics.drawable.Drawable getDrawable(int);
method public int getId(int);
method public int getLayerGravity(int);
@@ -12273,6 +12290,7 @@
method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
method public void setAlpha(int);
method public void setColorFilter(android.graphics.ColorFilter);
+ method public void setDrawable(int, android.graphics.drawable.Drawable);
method public boolean setDrawableByLayerId(int, android.graphics.drawable.Drawable);
method public void setId(int, int);
method public void setLayerGravity(int, int);
@@ -33924,6 +33942,7 @@
method public android.transition.Transition addTarget(java.lang.String);
method public android.transition.Transition addTarget(java.lang.Class);
method public android.transition.Transition addTarget(android.view.View);
+ method protected boolean areValuesChanged(android.transition.TransitionValues, android.transition.TransitionValues);
method public boolean canRemoveViews();
method public abstract void captureEndValues(android.transition.TransitionValues);
method public abstract void captureStartValues(android.transition.TransitionValues);
@@ -34178,6 +34197,7 @@
method public boolean equals(android.util.DisplayMetrics);
method public void setTo(android.util.DisplayMetrics);
method public void setToDefaults();
+ field public static final int DENSITY_280 = 280; // 0x118
field public static final int DENSITY_400 = 400; // 0x190
field public static final int DENSITY_560 = 560; // 0x230
field public static final int DENSITY_DEFAULT = 160; // 0xa0
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index cf608a8..62081ee 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -132,6 +132,7 @@
" am stack start <DISPLAY_ID> <INTENT>\n" +
" am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
" am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+ " am stack split <STACK_ID> <v|h> [INTENT]\n" +
" am stack list\n" +
" am stack info <STACK_ID>\n" +
" am task lock <TASK_ID>\n" +
@@ -245,7 +246,14 @@
"am stack movetask: move <TASK_ID> from its current stack to the top (true) or" +
" bottom (false) of <STACK_ID>.\n" +
"\n" +
- "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.\n" +
+ "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>" +
+ ".\n" +
+ "\n" +
+ "am stack split: split <STACK_ID> into 2 stacks <v>ertically or <h>orizontally" +
+ " starting the new stack with [INTENT] if specified. If [INTENT] isn't" +
+ " specified and the current stack has more than one task, then the top task" +
+ " of the current task will be moved to the new stack. Command will also force" +
+ " all current tasks in both stacks to be resizeable." +
"\n" +
"am stack list: list all of the activity stacks and their sizes.\n" +
"\n" +
@@ -1687,6 +1695,8 @@
runStackList();
} else if (op.equals("info")) {
runStackInfo();
+ } else if (op.equals("split")) {
+ runStackSplit();
} else {
showError("Error: unknown command '" + op + "'");
return;
@@ -1783,6 +1793,64 @@
}
}
+ private void runStackSplit() throws Exception {
+ final int stackId = Integer.valueOf(nextArgRequired());
+ final String splitDirection = nextArgRequired();
+ Intent intent = null;
+ try {
+ intent = makeIntent(UserHandle.USER_CURRENT);
+ } catch (IllegalArgumentException e) {
+ // no intent supplied.
+ }
+
+ try {
+ final StackInfo currentStackInfo = mAm.getStackInfo(stackId);
+ // Calculate bounds for new and current stack.
+ final Rect currentStackBounds = new Rect(currentStackInfo.bounds);
+ final Rect newStackBounds = new Rect(currentStackInfo.bounds);
+ if ("v".equals(splitDirection)) {
+ currentStackBounds.right = newStackBounds.left = currentStackInfo.bounds.centerX();
+ } else if ("h".equals(splitDirection)) {
+ currentStackBounds.bottom = newStackBounds.top = currentStackInfo.bounds.centerY();
+ } else {
+ showError("Error: unknown split direction '" + splitDirection + "'");
+ return;
+ }
+
+ // Create new stack
+ IActivityContainer container = mAm.createStackOnDisplay(currentStackInfo.displayId);
+ if (container == null) {
+ showError("Error: Unable to create new stack...");
+ }
+
+ final int newStackId = container.getStackId();
+
+ if (intent != null) {
+ container.startActivity(intent);
+ } else if (currentStackInfo.taskIds != null && currentStackInfo.taskIds.length > 1) {
+ // Move top task over to new stack
+ mAm.moveTaskToStack(currentStackInfo.taskIds[currentStackInfo.taskIds.length - 1],
+ newStackId, true);
+ }
+
+ final StackInfo newStackInfo = mAm.getStackInfo(newStackId);
+
+ // Make all tasks in the stacks resizeable.
+ for (int taskId : currentStackInfo.taskIds) {
+ mAm.setTaskResizeable(taskId, true);
+ }
+
+ for (int taskId : newStackInfo.taskIds) {
+ mAm.setTaskResizeable(taskId, true);
+ }
+
+ // Resize stacks
+ mAm.resizeStack(currentStackInfo.stackId, currentStackBounds);
+ mAm.resizeStack(newStackInfo.stackId, newStackBounds);
+ } catch (RemoteException e) {
+ }
+ }
+
private void runTask() throws Exception {
String op = nextArgRequired();
if (op.equals("lock")) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e95fbfc..aa1c70e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -743,6 +743,7 @@
final FragmentManagerImpl mFragments = new FragmentManagerImpl();
final FragmentContainer mContainer = new FragmentContainer() {
@Override
+ @Nullable
public View findViewById(int id) {
return Activity.this.findViewById(id);
}
@@ -2068,6 +2069,7 @@
*
* @return The view if found or null otherwise.
*/
+ @Nullable
public View findViewById(int id) {
return getWindow().findViewById(id);
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e08fc5b..d781863 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4432,10 +4432,16 @@
if (cacheDir != null) {
// Provide a usable directory for temporary files
System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
-
- setupGraphicsSupport(data.info, cacheDir);
} else {
- Log.e(TAG, "Unable to setupGraphicsSupport due to missing cache directory");
+ Log.v(TAG, "Unable to initialize \"java.io.tmpdir\" property due to missing cache directory");
+ }
+
+ // Use codeCacheDir to store generated/compiled graphics code
+ final File codeCacheDir = appContext.getCodeCacheDir();
+ if (codeCacheDir != null) {
+ setupGraphicsSupport(data.info, codeCacheDir);
+ } else {
+ Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory");
}
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 70e6e5a..a3662b2 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -18,6 +18,7 @@
import com.android.internal.app.WindowDecorActionBar;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
@@ -476,6 +477,7 @@
* @param id the identifier of the view to find
* @return The view with the given id or null.
*/
+ @Nullable
public View findViewById(int id) {
return mWindow.findViewById(id);
}
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index ab28d95..f319309 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -2008,6 +2008,7 @@
mChildFragmentManager = new FragmentManagerImpl();
mChildFragmentManager.attachActivity(mActivity, new FragmentContainer() {
@Override
+ @Nullable
public View findViewById(int id) {
if (mView == null) {
throw new IllegalStateException("Fragment does not have a view");
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index ccceef4..afdc917 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
@@ -394,6 +395,7 @@
* Callbacks from FragmentManagerImpl to its container.
*/
interface FragmentContainer {
+ @Nullable
public View findViewById(int id);
public boolean hasView();
}
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 0a255f7..0f6ce12 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -219,10 +219,9 @@
}
/**
- * Returns the currently configured night mode.
- *
- * @return {@link #MODE_NIGHT_NO}, {@link #MODE_NIGHT_YES}, or
- * {@link #MODE_NIGHT_AUTO}. When an error occurred -1 is returned.
+ * @return the currently configured night mode. May be one of
+ * {@link #MODE_NIGHT_NO}, {@link #MODE_NIGHT_YES},
+ * {@link #MODE_NIGHT_AUTO}, or -1 on error.
*/
public int getNightMode() {
if (mService != null) {
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index e9cce51..381d851 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -170,10 +170,10 @@
* lock task mode from an authorized package. The extra {@link #EXTRA_LOCK_TASK_PACKAGE}
* will describe the authorized package using lock task mode.
*
- * @see DevicePolicyManager#isLockTaskPermitted(String)
- *
* <p>The calling device admin must be the device owner or profile
* owner to receive this broadcast.
+ *
+ * @see DevicePolicyManager#isLockTaskPermitted(String)
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_LOCK_TASK_ENTERING
@@ -183,20 +183,19 @@
* Action sent to a device administrator to notify that the device is exiting
* lock task mode from an authorized package.
*
- * @see DevicePolicyManager#isLockTaskPermitted(String)
- *
* <p>The calling device admin must be the device owner or profile
* owner to receive this broadcast.
+ *
+ * @see DevicePolicyManager#isLockTaskPermitted(String)
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_LOCK_TASK_EXITING
= "android.app.action.LOCK_TASK_EXITING";
/**
- * A boolean describing whether the device is currently entering or exiting
- * lock task mode.
+ * A string containing the name of the package entering lock task mode.
*
- * @see #ACTION_LOCK_TASK_CHANGED
+ * @see #ACTION_LOCK_TASK_ENTERING
*/
public static final String EXTRA_LOCK_TASK_PACKAGE =
"android.app.extra.LOCK_TASK_PACKAGE";
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index dec2524..df620d0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2149,17 +2149,21 @@
WIFI_PASSPOINT_SERVICE,
WIFI_P2P_SERVICE,
WIFI_SCANNING_SERVICE,
+ //@hide: WIFI_RTT_SERVICE,
//@hide: ETHERNET_SERVICE,
WIFI_RTT_SERVICE,
NSD_SERVICE,
AUDIO_SERVICE,
+ //@hide: FINGERPRINT_SERVICE,
MEDIA_ROUTER_SERVICE,
TELEPHONY_SERVICE,
+ TELEPHONY_SUBSCRIPTION_SERVICE,
TELECOM_SERVICE,
CLIPBOARD_SERVICE,
INPUT_METHOD_SERVICE,
TEXT_SERVICES_MANAGER_SERVICE,
APPWIDGET_SERVICE,
+ //@hide: VOICE_INTERACTION_MANAGER_SERVICE,
//@hide: BACKUP_SERVICE,
DROPBOX_SERVICE,
DEVICE_POLICY_SERVICE,
@@ -2171,16 +2175,23 @@
USB_SERVICE,
LAUNCHER_APPS_SERVICE,
//@hide: SERIAL_SERVICE,
+ //@hide: HDMI_CONTROL_SERVICE,
INPUT_SERVICE,
DISPLAY_SERVICE,
- //@hide: SCHEDULING_POLICY_SERVICE,
USER_SERVICE,
- //@hide: APP_OPS_SERVICE
+ RESTRICTIONS_SERVICE,
+ APP_OPS_SERVICE,
CAMERA_SERVICE,
PRINT_SERVICE,
+ CONSUMER_IR_SERVICE,
+ //@hide: TRUST_SERVICE,
+ TV_INPUT_SERVICE,
+ //@hide: NETWORK_SCORE_SERVICE,
+ USAGE_STATS_SERVICE,
MEDIA_SESSION_SERVICE,
BATTERY_SERVICE,
JOB_SCHEDULER_SERVICE,
+ //@hide: PERSISTENT_DATA_BLOCK_SERVICE,
MEDIA_PROJECTION_SERVICE,
MIDI_SERVICE,
})
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index e07edba..e822708 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -334,44 +334,6 @@
public static final int FLAG_FULL_BACKUP_ONLY = 1<<26;
/**
- * Value for {@link #flags}: true if the application is hidden via restrictions and for
- * most purposes is considered as not installed.
- * {@hide}
- */
- public static final int FLAG_HIDDEN = 1<<27;
-
- /**
- * Value for {@link #flags}: set to <code>true</code> if the application
- * has reported that it is heavy-weight, and thus can not participate in
- * the normal application lifecycle.
- *
- * <p>Comes from the
- * android.R.styleable#AndroidManifestApplication_cantSaveState
- * attribute of the <application> tag.
- *
- * {@hide}
- */
- public static final int FLAG_CANT_SAVE_STATE = 1<<28;
-
- /**
- * Value for {@link #flags}: Set to true if the application has been
- * installed using the forward lock option.
- *
- * NOTE: DO NOT CHANGE THIS VALUE! It is saved in packages.xml.
- *
- * {@hide}
- */
- public static final int FLAG_FORWARD_LOCK = 1<<29;
-
- /**
- * Value for {@link #flags}: set to {@code true} if the application
- * is permitted to hold privileged permissions.
- *
- * {@hide}
- */
- public static final int FLAG_PRIVILEGED = 1<<30;
-
- /**
* Value for {@link #flags}: true if code from this application will need to be
* loaded into other applications' processes. On devices that support multiple
* instruction sets, this implies the code might be loaded into a process that's
@@ -395,11 +357,60 @@
* {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_SUPPORTS_XLARGE_SCREENS},
* {@link #FLAG_RESIZEABLE_FOR_SCREENS},
* {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE},
- * {@link #FLAG_INSTALLED}, {@link #FLAG_IS_GAME}.
+ * {@link #FLAG_ALLOW_BACKUP}, {@link #FLAG_KILL_AFTER_RESTORE},
+ * {@link #FLAG_RESTORE_ANY_VERSION}, {@link #FLAG_EXTERNAL_STORAGE},
+ * {@link #FLAG_LARGE_HEAP}, {@link #FLAG_STOPPED},
+ * {@link #FLAG_SUPPORTS_RTL}, {@link #FLAG_INSTALLED},
+ * {@link #FLAG_IS_DATA_ONLY}, {@link #FLAG_IS_GAME},
+ * {@link #FLAG_FULL_BACKUP_ONLY}, {@link #FLAG_MULTIARCH}.
*/
public int flags = 0;
/**
+ * Value for {@link #privateFlags}: true if the application is hidden via restrictions and for
+ * most purposes is considered as not installed.
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_HIDDEN = 1<<0;
+
+ /**
+ * Value for {@link #privateFlags}: set to <code>true</code> if the application
+ * has reported that it is heavy-weight, and thus can not participate in
+ * the normal application lifecycle.
+ *
+ * <p>Comes from the
+ * android.R.styleable#AndroidManifestApplication_cantSaveState
+ * attribute of the <application> tag.
+ *
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_CANT_SAVE_STATE = 1<<1;
+
+ /**
+ * Value for {@link #privateFlags}: Set to true if the application has been
+ * installed using the forward lock option.
+ *
+ * NOTE: DO NOT CHANGE THIS VALUE! It is saved in packages.xml.
+ *
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_FORWARD_LOCK = 1<<2;
+
+ /**
+ * Value for {@link #privateFlags}: set to {@code true} if the application
+ * is permitted to hold privileged permissions.
+ *
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_PRIVILEGED = 1<<3;
+
+ /**
+ * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
+ * {@hide}
+ */
+ public int privateFlags;
+
+ /**
* The required smallest screen width the application can run on. If 0,
* nothing has been specified. Comes from
* {@link android.R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp
@@ -598,6 +609,7 @@
pw.println(prefix + "processName=" + processName);
pw.println(prefix + "taskAffinity=" + taskAffinity);
pw.println(prefix + "uid=" + uid + " flags=0x" + Integer.toHexString(flags)
+ + " privateFlags=0x" + Integer.toHexString(privateFlags)
+ " theme=0x" + Integer.toHexString(theme));
pw.println(prefix + "requiresSmallestWidthDp=" + requiresSmallestWidthDp
+ " compatibleWidthLimitDp=" + compatibleWidthLimitDp
@@ -680,6 +692,7 @@
className = orig.className;
theme = orig.theme;
flags = orig.flags;
+ privateFlags = orig.privateFlags;
requiresSmallestWidthDp = orig.requiresSmallestWidthDp;
compatibleWidthLimitDp = orig.compatibleWidthLimitDp;
largestWidthLimitDp = orig.largestWidthLimitDp;
@@ -730,6 +743,7 @@
dest.writeString(className);
dest.writeInt(theme);
dest.writeInt(flags);
+ dest.writeInt(privateFlags);
dest.writeInt(requiresSmallestWidthDp);
dest.writeInt(compatibleWidthLimitDp);
dest.writeInt(largestWidthLimitDp);
@@ -779,6 +793,7 @@
className = source.readString();
theme = source.readInt();
flags = source.readInt();
+ privateFlags = source.readInt();
requiresSmallestWidthDp = source.readInt();
compatibleWidthLimitDp = source.readInt();
largestWidthLimitDp = source.readInt();
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0dc86ad..b518498 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -111,6 +111,8 @@
int getFlagsForUid(int uid);
+ int getPrivateFlagsForUid(int uid);
+
boolean isUidPrivileged(int uid);
String[] getAppOpPermissionPackages(String permissionName);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index be41a7c..b0e0300 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -800,6 +800,7 @@
pkg.splitCodePaths = lite.splitCodePaths;
pkg.splitRevisionCodes = lite.splitRevisionCodes;
pkg.splitFlags = new int[num];
+ pkg.splitPrivateFlags = new int[num];
for (int i = 0; i < num; i++) {
parseSplitApk(pkg, i, assets, flags);
@@ -1405,7 +1406,7 @@
/* Set the global "forward lock" flag */
if ((flags & PARSE_FORWARD_LOCK) != 0) {
- pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK;
+ pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
}
/* Set the global "on SD card" flag */
@@ -2608,7 +2609,7 @@
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState,
false)) {
- ai.flags |= ApplicationInfo.FLAG_CANT_SAVE_STATE;
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
// A heavy-weight application can not be in a custom process.
// We can do direct compare because we intern all strings.
@@ -3136,7 +3137,8 @@
sa.recycle();
- if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+ if (receiver && (owner.applicationInfo.privateFlags
+ &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
// A heavy-weight application can not have receives in its main process
// We can do direct compare because we intern all strings.
if (a.info.processName == owner.packageName) {
@@ -3489,7 +3491,8 @@
sa.recycle();
- if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+ if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+ != 0) {
// A heavy-weight application can not have providers in its main process
// We can do direct compare because we intern all strings.
if (p.info.processName == owner.packageName) {
@@ -3768,7 +3771,8 @@
sa.recycle();
- if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+ if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+ != 0) {
// A heavy-weight application can not have services in its main process
// We can do direct compare because we intern all strings.
if (s.info.processName == owner.packageName) {
@@ -4186,6 +4190,13 @@
/** Flags of any split APKs; ordered by parsed splitName */
public int[] splitFlags;
+ /**
+ * Private flags of any split APKs; ordered by parsed splitName.
+ *
+ * {@hide}
+ */
+ public int[] splitPrivateFlags;
+
public boolean baseHardwareAccelerated;
// For now we only support one application per package.
@@ -4621,9 +4632,9 @@
ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
}
if (state.hidden) {
- ai.flags |= ApplicationInfo.FLAG_HIDDEN;
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
} else {
- ai.flags &= ~ApplicationInfo.FLAG_HIDDEN;
+ ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
}
if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
ai.enabled = true;
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index fa5e9d2..39f4cca 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -833,4 +833,96 @@
+ ", type=" + mType + ", maxRange=" + mMaxRange + ", resolution=" + mResolution
+ ", power=" + mPower + ", minDelay=" + mMinDelay + "}";
}
+
+ /**
+ * Sets the Type associated with the sensor.
+ * NOTE: to be used only by native bindings in SensorManager.
+ *
+ * This allows interned static strings to be used across all representations of the Sensor. If
+ * a sensor type is not referenced here, it will still be interned by the native SensorManager.
+ *
+ * @return {@code true} if the StringType was successfully set, {@code false} otherwise.
+ */
+ private boolean setType(int value) {
+ mType = value;
+ switch (mType) {
+ case TYPE_ACCELEROMETER:
+ mStringType = STRING_TYPE_ACCELEROMETER;
+ return true;
+ case TYPE_AMBIENT_TEMPERATURE:
+ mStringType = STRING_TYPE_AMBIENT_TEMPERATURE;
+ return true;
+ case TYPE_GAME_ROTATION_VECTOR:
+ mStringType = STRING_TYPE_GAME_ROTATION_VECTOR;
+ return true;
+ case TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+ mStringType = STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR;
+ return true;
+ case TYPE_GLANCE_GESTURE:
+ mStringType = STRING_TYPE_GLANCE_GESTURE;
+ return true;
+ case TYPE_GRAVITY:
+ mStringType = STRING_TYPE_GRAVITY;
+ return true;
+ case TYPE_GYROSCOPE:
+ mStringType = STRING_TYPE_GYROSCOPE;
+ return true;
+ case TYPE_GYROSCOPE_UNCALIBRATED:
+ mStringType = STRING_TYPE_GYROSCOPE_UNCALIBRATED;
+ return true;
+ case TYPE_HEART_RATE:
+ mStringType = STRING_TYPE_HEART_RATE;
+ return true;
+ case TYPE_LIGHT:
+ mStringType = STRING_TYPE_LIGHT;
+ return true;
+ case TYPE_LINEAR_ACCELERATION:
+ mStringType = STRING_TYPE_LINEAR_ACCELERATION;
+ return true;
+ case TYPE_MAGNETIC_FIELD:
+ mStringType = STRING_TYPE_MAGNETIC_FIELD;
+ return true;
+ case TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+ mStringType = STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED;
+ return true;
+ case TYPE_PICK_UP_GESTURE:
+ mStringType = STRING_TYPE_PICK_UP_GESTURE;
+ return true;
+ case TYPE_PRESSURE:
+ mStringType = STRING_TYPE_PRESSURE;
+ return true;
+ case TYPE_PROXIMITY:
+ mStringType = STRING_TYPE_PROXIMITY;
+ return true;
+ case TYPE_RELATIVE_HUMIDITY:
+ mStringType = STRING_TYPE_RELATIVE_HUMIDITY;
+ return true;
+ case TYPE_ROTATION_VECTOR:
+ mStringType = STRING_TYPE_ROTATION_VECTOR;
+ return true;
+ case TYPE_SIGNIFICANT_MOTION:
+ mStringType = STRING_TYPE_SIGNIFICANT_MOTION;
+ return true;
+ case TYPE_STEP_COUNTER:
+ mStringType = STRING_TYPE_STEP_COUNTER;
+ return true;
+ case TYPE_STEP_DETECTOR:
+ mStringType = STRING_TYPE_STEP_DETECTOR;
+ return true;
+ case TYPE_TILT_DETECTOR:
+ mStringType = SENSOR_STRING_TYPE_TILT_DETECTOR;
+ return true;
+ case TYPE_WAKE_GESTURE:
+ mStringType = STRING_TYPE_WAKE_GESTURE;
+ return true;
+ case TYPE_ORIENTATION:
+ mStringType = STRING_TYPE_ORIENTATION;
+ return true;
+ case TYPE_TEMPERATURE:
+ mStringType = STRING_TYPE_TEMPERATURE;
+ return true;
+ default:
+ return false;
+ }
+ }
}
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
index a0a0716..615b2c8 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -269,21 +269,23 @@
throw new IllegalStateException("Illegal intermediate texture with dimension of 0");
}
- // Letterbox or pillerbox output dimensions into intermediate dimensions.
+ // Letterbox or pillar-box output dimensions into intermediate dimensions.
RectF intermediate = new RectF(/*left*/0, /*top*/0, /*right*/texWidth, /*bottom*/texHeight);
RectF output = new RectF(/*left*/0, /*top*/0, /*right*/width, /*bottom*/height);
android.graphics.Matrix boxingXform = new android.graphics.Matrix();
boxingXform.setRectToRect(output, intermediate, android.graphics.Matrix.ScaleToFit.CENTER);
boxingXform.mapRect(output);
- // Find scaling factor from pillerboxed/letterboxed output dimensions to intermediate
+ // Find scaling factor from pillar-boxed/letter-boxed output dimensions to intermediate
// buffer dimensions.
float scaleX = intermediate.width() / output.width();
float scaleY = intermediate.height() / output.height();
- // Scale opposite dimension in clip coordinates so output is letterboxed/pillerboxed into
- // the intermediate dimensions (rather than vice-versa).
- Matrix.scaleM(mMVPMatrix, /*offset*/0, /*x*/scaleY, /*y*/scaleX, /*z*/1);
+ // Intermediate texture is implicitly scaled to 'fill' the output dimensions in clip space
+ // coordinates in the shader. To avoid stretching, we need to scale the larger dimension
+ // of the intermediate buffer so that the output buffer is actually letter-boxed
+ // or pillar-boxed into the intermediate buffer after clipping.
+ Matrix.scaleM(mMVPMatrix, /*offset*/0, /*x*/scaleX, /*y*/scaleY, /*z*/1);
if (DEBUG) {
Log.d(TAG, "Scaling factors (S_x = " + scaleX + ",S_y = " + scaleY + ") used for " +
diff --git a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
index 518a874..cc018e9 100644
--- a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
+++ b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
@@ -104,7 +104,7 @@
try {
ai = pm.getApplicationInfo(
ri.activityInfo.packageName, PackageManager.GET_META_DATA);
- if ((ai.flags & ApplicationInfo.FLAG_PRIVILEGED) == 0) {
+ if ((ai.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) == 0) {
// The application isn't privileged (/system/priv-app).
// The enrollment application needs to be a privileged system app.
Slog.w(TAG, ai.packageName + "is not a privileged system app");
diff --git a/core/java/android/midi/MidiDeviceServer.java b/core/java/android/midi/MidiDeviceServer.java
index 7499934..4a1995f 100644
--- a/core/java/android/midi/MidiDeviceServer.java
+++ b/core/java/android/midi/MidiDeviceServer.java
@@ -254,12 +254,12 @@
return new MidiReceiver() {
@Override
- public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException {
+ public void post(byte[] msg, int offset, int count, long timestamp) throws IOException {
ArrayList<MidiInputPort> receivers = mOutputPortReceivers[portNumberF];
synchronized (receivers) {
for (int i = 0; i < receivers.size(); i++) {
// FIXME catch errors and remove dead ones
- receivers.get(i).onPost(msg, offset, count, timestamp);
+ receivers.get(i).post(msg, offset, count, timestamp);
}
}
}
diff --git a/core/java/android/midi/MidiInputPort.java b/core/java/android/midi/MidiInputPort.java
index 51c47dd..735c68a 100644
--- a/core/java/android/midi/MidiInputPort.java
+++ b/core/java/android/midi/MidiInputPort.java
@@ -50,7 +50,7 @@
* @param timestamp future time to post the message (based on
* {@link java.lang.System#nanoTime}
*/
- public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException {
+ public void post(byte[] msg, int offset, int count, long timestamp) throws IOException {
assert(offset >= 0 && count >= 0 && offset + count <= msg.length);
synchronized (mBuffer) {
diff --git a/core/java/android/midi/MidiManager.java b/core/java/android/midi/MidiManager.java
index 8aa8395..3a0b064 100644
--- a/core/java/android/midi/MidiManager.java
+++ b/core/java/android/midi/MidiManager.java
@@ -66,22 +66,24 @@
}
/**
- * Callback interface used for clients to receive MIDI device added and removed notifications
+ * Callback class used for clients to receive MIDI device added and removed notifications
*/
- public interface DeviceCallback {
+ public static class DeviceCallback {
/**
* Called to notify when a new MIDI device has been added
*
* @param device a {@link MidiDeviceInfo} for the newly added device
*/
- void onDeviceAdded(MidiDeviceInfo device);
+ void onDeviceAdded(MidiDeviceInfo device) {
+ }
/**
* Called to notify when a MIDI device has been removed
*
* @param device a {@link MidiDeviceInfo} for the removed device
*/
- void onDeviceRemoved(MidiDeviceInfo device);
+ void onDeviceRemoved(MidiDeviceInfo device) {
+ }
}
/**
diff --git a/core/java/android/midi/MidiOutputPort.java b/core/java/android/midi/MidiOutputPort.java
index 332b431..b9512fd 100644
--- a/core/java/android/midi/MidiOutputPort.java
+++ b/core/java/android/midi/MidiOutputPort.java
@@ -65,7 +65,7 @@
for (int i = 0; i < mReceivers.size(); i++) {
MidiReceiver receiver = mReceivers.get(i);
try {
- receiver.onPost(buffer, offset, size, timestamp);
+ receiver.post(buffer, offset, size, timestamp);
} catch (IOException e) {
Log.e(TAG, "post failed");
deadReceivers.add(receiver);
diff --git a/core/java/android/midi/MidiReceiver.java b/core/java/android/midi/MidiReceiver.java
index fdfe51a..16c9bbb 100644
--- a/core/java/android/midi/MidiReceiver.java
+++ b/core/java/android/midi/MidiReceiver.java
@@ -32,7 +32,7 @@
* The msg bytes should be copied by the receiver rather than retaining a reference
* to this parameter.
* Also, modifying the contents of the msg array parameter may result in other receivers
- * in the same application receiving incorrect values in their onPost() method.
+ * in the same application receiving incorrect values in their post() method.
*
* @param msg a byte array containing the MIDI data
* @param offset the offset of the first byte of the data in the byte array
@@ -40,5 +40,5 @@
* @param timestamp the timestamp of the message (based on {@link java.lang.System#nanoTime}
* @throws IOException
*/
- public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException;
+ public void post(byte[] msg, int offset, int count, long timestamp) throws IOException;
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 1a51808..808be21 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2371,6 +2371,10 @@
* The lookup key for a {@link Network} object included with the intent after
* successfully finding a network for the applications request. Retrieve it with
* {@link android.content.Intent#getParcelableExtra(String)}.
+ * <p>
+ * Note that if you intend to invoke (@link #setProcessDefaultNetwork(Network)) or
+ * {@link Network#openConnection(java.net.URL)} then you must get a
+ * ConnectivityManager instance before doing so.
*/
public static final String EXTRA_NETWORK = "android.net.extra.NETWORK";
diff --git a/core/java/android/net/PacProxySelector.java b/core/java/android/net/PacProxySelector.java
index 8626d08..9bdf4f6 100644
--- a/core/java/android/net/PacProxySelector.java
+++ b/core/java/android/net/PacProxySelector.java
@@ -16,7 +16,6 @@
package android.net;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
@@ -74,8 +73,8 @@
}
try {
response = mProxyService.resolvePacFile(uri.getHost(), urlString);
- } catch (RemoteException e) {
- e.printStackTrace();
+ } catch (Exception e) {
+ Log.e(TAG, "Error resolving PAC File", e);
}
if (response == null) {
return mDefaultList;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 250e80f..c836a33 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -51,14 +51,21 @@
import android.speech.tts.TextToSpeech;
import android.text.TextUtils;
import android.util.AndroidException;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.ILockSettings;
import java.net.URISyntaxException;
+import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
/**
* The Settings provider contains global system-level device preferences.
@@ -1192,6 +1199,11 @@
public static final class System extends NameValueTable {
public static final String SYS_PROP_SETTING_VERSION = "sys.settings_system_version";
+ /** @hide */
+ public static interface Validator {
+ public boolean validate(String value);
+ }
+
/**
* The content:// style URL for this table
*/
@@ -1294,13 +1306,56 @@
MOVED_TO_GLOBAL.add(Settings.Global.CERT_PIN_UPDATE_METADATA_URL);
}
+ private static final Validator sBooleanValidator =
+ new DiscreteValueValidator(new String[] {"0", "1"});
+
+ private static final Validator sNonNegativeIntegerValidator = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ return Integer.parseInt(value) >= 0;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ };
+
+ private static final Validator sVolumeValidator =
+ new InclusiveFloatRangeValidator(0, 1);
+
+ private static final Validator sUriValidator = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ Uri.decode(value);
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+ };
+
+ private static final Validator sLenientIpAddressValidator = new Validator() {
+ private static final int MAX_IPV6_LENGTH = 45;
+
+ @Override
+ public boolean validate(String value) {
+ return value.length() <= MAX_IPV6_LENGTH;
+ }
+ };
+
/** @hide */
- public static void getMovedKeys(HashSet<String> outKeySet) {
+ public static void getMovedToGlobalSettings(Set<String> outKeySet) {
outKeySet.addAll(MOVED_TO_GLOBAL);
outKeySet.addAll(MOVED_TO_SECURE_THEN_GLOBAL);
}
/** @hide */
+ public static void getMovedToSecureSettings(Set<String> outKeySet) {
+ outKeySet.addAll(MOVED_TO_SECURE);
+ }
+
+ /** @hide */
public static void getNonLegacyMovedKeys(HashSet<String> outKeySet) {
outKeySet.addAll(MOVED_TO_GLOBAL);
}
@@ -1723,6 +1778,56 @@
putIntForUser(cr, SHOW_GTALK_SERVICE_STATUS, flag ? 1 : 0, userHandle);
}
+ private static final class DiscreteValueValidator implements Validator {
+ private final String[] mValues;
+
+ public DiscreteValueValidator(String[] values) {
+ mValues = values;
+ }
+
+ public boolean validate(String value) {
+ return ArrayUtils.contains(mValues, value);
+ }
+ }
+
+ private static final class InclusiveIntegerRangeValidator implements Validator {
+ private final int mMin;
+ private final int mMax;
+
+ public InclusiveIntegerRangeValidator(int min, int max) {
+ mMin = min;
+ mMax = max;
+ }
+
+ public boolean validate(String value) {
+ try {
+ final int intValue = Integer.parseInt(value);
+ return intValue >= mMin && intValue <= mMax;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ }
+
+ private static final class InclusiveFloatRangeValidator implements Validator {
+ private final float mMin;
+ private final float mMax;
+
+ public InclusiveFloatRangeValidator(float min, float max) {
+ mMin = min;
+ mMax = max;
+ }
+
+ public boolean validate(String value) {
+ try {
+ final float floatValue = Float.parseFloat(value);
+ return floatValue >= mMin && floatValue <= mMax;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ }
+
/**
* @deprecated Use {@link android.provider.Settings.Global#STAY_ON_WHILE_PLUGGED_IN} instead
*/
@@ -1741,6 +1846,9 @@
*/
public static final String END_BUTTON_BEHAVIOR = "end_button_behavior";
+ private static final Validator END_BUTTON_BEHAVIOR_VALIDATOR =
+ new InclusiveIntegerRangeValidator(0, 3);
+
/**
* END_BUTTON_BEHAVIOR value for "go home".
* @hide
@@ -1765,6 +1873,8 @@
*/
public static final String ADVANCED_SETTINGS = "advanced_settings";
+ private static final Validator ADVANCED_SETTINGS_VALIDATOR = sBooleanValidator;
+
/**
* ADVANCED_SETTINGS default value.
* @hide
@@ -1864,6 +1974,8 @@
@Deprecated
public static final String WIFI_USE_STATIC_IP = "wifi_use_static_ip";
+ private static final Validator WIFI_USE_STATIC_IP_VALIDATOR = sBooleanValidator;
+
/**
* The static IP address.
* <p>
@@ -1874,6 +1986,8 @@
@Deprecated
public static final String WIFI_STATIC_IP = "wifi_static_ip";
+ private static final Validator WIFI_STATIC_IP_VALIDATOR = sLenientIpAddressValidator;
+
/**
* If using static IP, the gateway's IP address.
* <p>
@@ -1884,6 +1998,8 @@
@Deprecated
public static final String WIFI_STATIC_GATEWAY = "wifi_static_gateway";
+ private static final Validator WIFI_STATIC_GATEWAY_VALIDATOR = sLenientIpAddressValidator;
+
/**
* If using static IP, the net mask.
* <p>
@@ -1894,6 +2010,8 @@
@Deprecated
public static final String WIFI_STATIC_NETMASK = "wifi_static_netmask";
+ private static final Validator WIFI_STATIC_NETMASK_VALIDATOR = sLenientIpAddressValidator;
+
/**
* If using static IP, the primary DNS's IP address.
* <p>
@@ -1904,6 +2022,8 @@
@Deprecated
public static final String WIFI_STATIC_DNS1 = "wifi_static_dns1";
+ private static final Validator WIFI_STATIC_DNS1_VALIDATOR = sLenientIpAddressValidator;
+
/**
* If using static IP, the secondary DNS's IP address.
* <p>
@@ -1914,6 +2034,7 @@
@Deprecated
public static final String WIFI_STATIC_DNS2 = "wifi_static_dns2";
+ private static final Validator WIFI_STATIC_DNS2_VALIDATOR = sLenientIpAddressValidator;
/**
* Determines whether remote devices may discover and/or connect to
@@ -1926,6 +2047,9 @@
public static final String BLUETOOTH_DISCOVERABILITY =
"bluetooth_discoverability";
+ private static final Validator BLUETOOTH_DISCOVERABILITY_VALIDATOR =
+ new InclusiveIntegerRangeValidator(0, 2);
+
/**
* Bluetooth discoverability timeout. If this value is nonzero, then
* Bluetooth becomes discoverable for a certain number of seconds,
@@ -1934,6 +2058,9 @@
public static final String BLUETOOTH_DISCOVERABILITY_TIMEOUT =
"bluetooth_discoverability_timeout";
+ private static final Validator BLUETOOTH_DISCOVERABILITY_TIMEOUT_VALIDATOR =
+ sNonNegativeIntegerValidator;
+
/**
* @deprecated Use {@link android.provider.Settings.Secure#LOCK_PATTERN_ENABLED}
* instead
@@ -1957,7 +2084,6 @@
public static final String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED =
"lock_pattern_tactile_feedback_enabled";
-
/**
* A formatted string of the next alarm that is set, or the empty string
* if there is no alarm set.
@@ -1967,11 +2093,31 @@
@Deprecated
public static final String NEXT_ALARM_FORMATTED = "next_alarm_formatted";
+ private static final Validator NEXT_ALARM_FORMATTED_VALIDATOR = new Validator() {
+ private static final int MAX_LENGTH = 1000;
+ @Override
+ public boolean validate(String value) {
+ // TODO: No idea what the correct format is.
+ return value == null || value.length() < MAX_LENGTH;
+ }
+ };
+
/**
* Scaling factor for fonts, float.
*/
public static final String FONT_SCALE = "font_scale";
+ private static final Validator FONT_SCALE_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ return Float.parseFloat(value) >= 0;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ };
+
/**
* Name of an application package to be debugged.
*
@@ -1996,6 +2142,8 @@
@Deprecated
public static final String DIM_SCREEN = "dim_screen";
+ private static final Validator DIM_SCREEN_VALIDATOR = sBooleanValidator;
+
/**
* The amount of time in milliseconds before the device goes to sleep or begins
* to dream after a period of inactivity. This value is also known as the
@@ -2004,16 +2152,23 @@
*/
public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
+ private static final Validator SCREEN_OFF_TIMEOUT_VALIDATOR = sNonNegativeIntegerValidator;
+
/**
* The screen backlight brightness between 0 and 255.
*/
public static final String SCREEN_BRIGHTNESS = "screen_brightness";
+ private static final Validator SCREEN_BRIGHTNESS_VALIDATOR =
+ new InclusiveIntegerRangeValidator(0, 255);
+
/**
* Control whether to enable automatic brightness mode.
*/
public static final String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
+ private static final Validator SCREEN_BRIGHTNESS_MODE_VALIDATOR = sBooleanValidator;
+
/**
* Adjustment to auto-brightness to make it generally more (>0.0 <1.0)
* or less (<0.0 >-1.0) bright.
@@ -2021,6 +2176,9 @@
*/
public static final String SCREEN_AUTO_BRIGHTNESS_ADJ = "screen_auto_brightness_adj";
+ private static final Validator SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR =
+ new InclusiveFloatRangeValidator(-1, 1);
+
/**
* SCREEN_BRIGHTNESS_MODE value for manual mode.
*/
@@ -2056,12 +2214,18 @@
*/
public static final String MODE_RINGER_STREAMS_AFFECTED = "mode_ringer_streams_affected";
- /**
+ private static final Validator MODE_RINGER_STREAMS_AFFECTED_VALIDATOR =
+ sNonNegativeIntegerValidator;
+
+ /**
* Determines which streams are affected by mute. The
* stream type's bit should be set to 1 if it should be muted when a mute request
* is received.
*/
- public static final String MUTE_STREAMS_AFFECTED = "mute_streams_affected";
+ public static final String MUTE_STREAMS_AFFECTED = "mute_streams_affected";
+
+ private static final Validator MUTE_STREAMS_AFFECTED_VALIDATOR =
+ sNonNegativeIntegerValidator;
/**
* Whether vibrate is on for different events. This is used internally,
@@ -2069,6 +2233,8 @@
*/
public static final String VIBRATE_ON = "vibrate_on";
+ private static final Validator VIBRATE_ON_VALIDATOR = sBooleanValidator;
+
/**
* If 1, redirects the system vibrator to all currently attached input devices
* that support vibration. If there are no such input devices, then the system
@@ -2083,54 +2249,72 @@
*/
public static final String VIBRATE_INPUT_DEVICES = "vibrate_input_devices";
+ private static final Validator VIBRATE_INPUT_DEVICES_VALIDATOR = sBooleanValidator;
+
/**
* Ringer volume. This is used internally, changing this value will not
* change the volume. See AudioManager.
*/
public static final String VOLUME_RING = "volume_ring";
+ private static final Validator VOLUME_RING_VALIDATOR = sVolumeValidator;
+
/**
* System/notifications volume. This is used internally, changing this
* value will not change the volume. See AudioManager.
*/
public static final String VOLUME_SYSTEM = "volume_system";
+ private static final Validator VOLUME_SYSTEM_VALIDATOR = sVolumeValidator;
+
/**
* Voice call volume. This is used internally, changing this value will
* not change the volume. See AudioManager.
*/
public static final String VOLUME_VOICE = "volume_voice";
+ private static final Validator VOLUME_VOICE_VALIDATOR = sVolumeValidator;
+
/**
* Music/media/gaming volume. This is used internally, changing this
* value will not change the volume. See AudioManager.
*/
public static final String VOLUME_MUSIC = "volume_music";
+ private static final Validator VOLUME_MUSIC_VALIDATOR = sVolumeValidator;
+
/**
* Alarm volume. This is used internally, changing this
* value will not change the volume. See AudioManager.
*/
public static final String VOLUME_ALARM = "volume_alarm";
+ private static final Validator VOLUME_ALARM_VALIDATOR = sVolumeValidator;
+
/**
* Notification volume. This is used internally, changing this
* value will not change the volume. See AudioManager.
*/
public static final String VOLUME_NOTIFICATION = "volume_notification";
+ private static final Validator VOLUME_NOTIFICATION_VALIDATOR = sVolumeValidator;
+
/**
* Bluetooth Headset volume. This is used internally, changing this value will
* not change the volume. See AudioManager.
*/
public static final String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
+ private static final Validator VOLUME_BLUETOOTH_SCO_VALIDATOR = sVolumeValidator;
+
/**
* Master volume (float in the range 0.0f to 1.0f).
* @hide
*/
public static final String VOLUME_MASTER = "volume_master";
+ private static final Validator VOLUME_MASTER_VALIDATOR = sVolumeValidator;
+
/**
* Master volume mute (int 1 = mute, 0 = not muted).
*
@@ -2138,6 +2322,8 @@
*/
public static final String VOLUME_MASTER_MUTE = "volume_master_mute";
+ private static final Validator VOLUME_MASTER_MUTE_VALIDATOR = sBooleanValidator;
+
/**
* Microphone mute (int 1 = mute, 0 = not muted).
*
@@ -2145,6 +2331,8 @@
*/
public static final String MICROPHONE_MUTE = "microphone_mute";
+ private static final Validator MICROPHONE_MUTE_VALIDATOR = sBooleanValidator;
+
/**
* Whether the notifications should use the ring volume (value of 1) or
* a separate notification volume (value of 0). In most cases, users
@@ -2163,6 +2351,8 @@
public static final String NOTIFICATIONS_USE_RING_VOLUME =
"notifications_use_ring_volume";
+ private static final Validator NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR = sBooleanValidator;
+
/**
* Whether silent mode should allow vibration feedback. This is used
* internally in AudioService and the Sound settings activity to
@@ -2177,6 +2367,8 @@
*/
public static final String VIBRATE_IN_SILENT = "vibrate_in_silent";
+ private static final Validator VIBRATE_IN_SILENT_VALIDATOR = sBooleanValidator;
+
/**
* The mapping of stream type (integer) to its setting.
*/
@@ -2203,6 +2395,8 @@
*/
public static final String RINGTONE = "ringtone";
+ private static final Validator RINGTONE_VALIDATOR = sUriValidator;
+
/**
* A {@link Uri} that will point to the current default ringtone at any
* given time.
@@ -2221,6 +2415,8 @@
*/
public static final String NOTIFICATION_SOUND = "notification_sound";
+ private static final Validator NOTIFICATION_SOUND_VALIDATOR = sUriValidator;
+
/**
* A {@link Uri} that will point to the current default notification
* sound at any given time.
@@ -2237,6 +2433,8 @@
*/
public static final String ALARM_ALERT = "alarm_alert";
+ private static final Validator ALARM_ALERT_VALIDATOR = sUriValidator;
+
/**
* A {@link Uri} that will point to the current default alarm alert at
* any given time.
@@ -2252,30 +2450,52 @@
*/
public static final String MEDIA_BUTTON_RECEIVER = "media_button_receiver";
+ private static final Validator MEDIA_BUTTON_RECEIVER_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ ComponentName.unflattenFromString(value);
+ return true;
+ } catch (NullPointerException e) {
+ return false;
+ }
+ }
+ };
+
/**
* Setting to enable Auto Replace (AutoText) in text editors. 1 = On, 0 = Off
*/
public static final String TEXT_AUTO_REPLACE = "auto_replace";
+ private static final Validator TEXT_AUTO_REPLACE_VALIDATOR = sBooleanValidator;
+
/**
* Setting to enable Auto Caps in text editors. 1 = On, 0 = Off
*/
public static final String TEXT_AUTO_CAPS = "auto_caps";
+ private static final Validator TEXT_AUTO_CAPS_VALIDATOR = sBooleanValidator;
+
/**
* Setting to enable Auto Punctuate in text editors. 1 = On, 0 = Off. This
* feature converts two spaces to a "." and space.
*/
public static final String TEXT_AUTO_PUNCTUATE = "auto_punctuate";
+ private static final Validator TEXT_AUTO_PUNCTUATE_VALIDATOR = sBooleanValidator;
+
/**
* Setting to showing password characters in text editors. 1 = On, 0 = Off
*/
public static final String TEXT_SHOW_PASSWORD = "show_password";
+ private static final Validator TEXT_SHOW_PASSWORD_VALIDATOR = sBooleanValidator;
+
public static final String SHOW_GTALK_SERVICE_STATUS =
"SHOW_GTALK_SERVICE_STATUS";
+ private static final Validator SHOW_GTALK_SERVICE_STATUS_VALIDATOR = sBooleanValidator;
+
/**
* Name of activity to use for wallpaper on the home screen.
*
@@ -2284,6 +2504,18 @@
@Deprecated
public static final String WALLPAPER_ACTIVITY = "wallpaper_activity";
+ private static final Validator WALLPAPER_ACTIVITY_VALIDATOR = new Validator() {
+ private static final int MAX_LENGTH = 1000;
+
+ @Override
+ public boolean validate(String value) {
+ if (value != null && value.length() > MAX_LENGTH) {
+ return false;
+ }
+ return ComponentName.unflattenFromString(value) != null;
+ }
+ };
+
/**
* @deprecated Use {@link android.provider.Settings.Global#AUTO_TIME}
* instead
@@ -2305,6 +2537,10 @@
*/
public static final String TIME_12_24 = "time_12_24";
+ /** @hide */
+ public static final Validator TIME_12_24_VALIDATOR =
+ new DiscreteValueValidator(new String[] {"12", "24"});
+
/**
* Date format string
* mm/dd/yyyy
@@ -2313,6 +2549,19 @@
*/
public static final String DATE_FORMAT = "date_format";
+ /** @hide */
+ public static final Validator DATE_FORMAT_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ new SimpleDateFormat(value);
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+ };
+
/**
* Whether the setup wizard has been run before (on first boot), or if
* it still needs to be run.
@@ -2322,6 +2571,9 @@
*/
public static final String SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run";
+ /** @hide */
+ public static final Validator SETUP_WIZARD_HAS_RUN_VALIDATOR = sBooleanValidator;
+
/**
* Scaling factor for normal window animations. Setting to 0 will disable window
* animations.
@@ -2358,6 +2610,9 @@
*/
public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation";
+ /** @hide */
+ public static final Validator ACCELEROMETER_ROTATION_VALIDATOR = sBooleanValidator;
+
/**
* Default screen rotation when no other policy applies.
* When {@link #ACCELEROMETER_ROTATION} is zero and no on-screen Activity expresses a
@@ -2368,6 +2623,10 @@
*/
public static final String USER_ROTATION = "user_rotation";
+ /** @hide */
+ public static final Validator USER_ROTATION_VALIDATOR =
+ new InclusiveIntegerRangeValidator(0, 3);
+
/**
* Control whether the rotation lock toggle in the System UI should be hidden.
* Typically this is done for accessibility purposes to make it harder for
@@ -2382,6 +2641,10 @@
public static final String HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY =
"hide_rotation_lock_toggle_for_accessibility";
+ /** @hide */
+ public static final Validator HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY_VALIDATOR =
+ sBooleanValidator;
+
/**
* Whether the phone vibrates when it is ringing due to an incoming call. This will
* be used by Phone and Setting apps; it shouldn't affect other apps.
@@ -2396,12 +2659,18 @@
*/
public static final String VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
+ /** @hide */
+ public static final Validator VIBRATE_WHEN_RINGING_VALIDATOR = sBooleanValidator;
+
/**
* Whether the audible DTMF tones are played by the dialer when dialing. The value is
* boolean (1 or 0).
*/
public static final String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
+ /** @hide */
+ public static final Validator DTMF_TONE_WHEN_DIALING_VALIDATOR = sBooleanValidator;
+
/**
* CDMA only settings
* DTMF tone type played by the dialer when dialing.
@@ -2411,6 +2680,9 @@
*/
public static final String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
+ /** @hide */
+ public static final Validator DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR = sBooleanValidator;
+
/**
* Whether the hearing aid is enabled. The value is
* boolean (1 or 0).
@@ -2418,6 +2690,9 @@
*/
public static final String HEARING_AID = "hearing_aid";
+ /** @hide */
+ public static final Validator HEARING_AID_VALIDATOR = sBooleanValidator;
+
/**
* CDMA only settings
* TTY Mode
@@ -2429,18 +2704,27 @@
*/
public static final String TTY_MODE = "tty_mode";
+ /** @hide */
+ public static final Validator TTY_MODE_VALIDATOR = new InclusiveIntegerRangeValidator(0, 3);
+
/**
* Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
* boolean (1 or 0).
*/
public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
+ /** @hide */
+ public static final Validator SOUND_EFFECTS_ENABLED_VALIDATOR = sBooleanValidator;
+
/**
* Whether the haptic feedback (long presses, ...) are enabled. The value is
* boolean (1 or 0).
*/
public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled";
+ /** @hide */
+ public static final Validator HAPTIC_FEEDBACK_ENABLED_VALIDATOR = sBooleanValidator;
+
/**
* @deprecated Each application that shows web suggestions should have its own
* setting for this.
@@ -2448,6 +2732,9 @@
@Deprecated
public static final String SHOW_WEB_SUGGESTIONS = "show_web_suggestions";
+ /** @hide */
+ public static final Validator SHOW_WEB_SUGGESTIONS_VALIDATOR = sBooleanValidator;
+
/**
* Whether the notification LED should repeatedly flash when a notification is
* pending. The value is boolean (1 or 0).
@@ -2455,6 +2742,9 @@
*/
public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse";
+ /** @hide */
+ public static final Validator NOTIFICATION_LIGHT_PULSE_VALIDATOR = sBooleanValidator;
+
/**
* Show pointer location on screen?
* 0 = no
@@ -2463,6 +2753,9 @@
*/
public static final String POINTER_LOCATION = "pointer_location";
+ /** @hide */
+ public static final Validator POINTER_LOCATION_VALIDATOR = sBooleanValidator;
+
/**
* Show touch positions on screen?
* 0 = no
@@ -2471,6 +2764,9 @@
*/
public static final String SHOW_TOUCHES = "show_touches";
+ /** @hide */
+ public static final Validator SHOW_TOUCHES_VALIDATOR = sBooleanValidator;
+
/**
* Log raw orientation data from
* {@link com.android.server.policy.WindowOrientationListener} for use with the
@@ -2482,6 +2778,9 @@
public static final String WINDOW_ORIENTATION_LISTENER_LOG =
"window_orientation_listener_log";
+ /** @hide */
+ public static final Validator WINDOW_ORIENTATION_LISTENER_LOG_VALIDATOR = sBooleanValidator;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#POWER_SOUNDS_ENABLED}
* instead
@@ -2504,12 +2803,18 @@
*/
public static final String LOCKSCREEN_SOUNDS_ENABLED = "lockscreen_sounds_enabled";
+ /** @hide */
+ public static final Validator LOCKSCREEN_SOUNDS_ENABLED_VALIDATOR = sBooleanValidator;
+
/**
* Whether the lockscreen should be completely disabled.
* @hide
*/
public static final String LOCKSCREEN_DISABLED = "lockscreen.disabled";
+ /** @hide */
+ public static final Validator LOCKSCREEN_DISABLED_VALIDATOR = sBooleanValidator;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#LOW_BATTERY_SOUND}
* instead
@@ -2574,6 +2879,9 @@
*/
public static final String SIP_RECEIVE_CALLS = "sip_receive_calls";
+ /** @hide */
+ public static final Validator SIP_RECEIVE_CALLS_VALIDATOR = sBooleanValidator;
+
/**
* Call Preference String.
* "SIP_ALWAYS" : Always use SIP with network access
@@ -2582,18 +2890,28 @@
*/
public static final String SIP_CALL_OPTIONS = "sip_call_options";
+ /** @hide */
+ public static final Validator SIP_CALL_OPTIONS_VALIDATOR = new DiscreteValueValidator(
+ new String[] {"SIP_ALWAYS", "SIP_ADDRESS_ONLY"});
+
/**
* One of the sip call options: Always use SIP with network access.
* @hide
*/
public static final String SIP_ALWAYS = "SIP_ALWAYS";
+ /** @hide */
+ public static final Validator SIP_ALWAYS_VALIDATOR = sBooleanValidator;
+
/**
* One of the sip call options: Only if destination is a SIP address.
* @hide
*/
public static final String SIP_ADDRESS_ONLY = "SIP_ADDRESS_ONLY";
+ /** @hide */
+ public static final Validator SIP_ADDRESS_ONLY_VALIDATOR = sBooleanValidator;
+
/**
* @deprecated Use SIP_ALWAYS or SIP_ADDRESS_ONLY instead. Formerly used to indicate that
* the user should be prompted each time a call is made whether it should be placed using
@@ -2604,6 +2922,9 @@
@Deprecated
public static final String SIP_ASK_ME_EACH_TIME = "SIP_ASK_ME_EACH_TIME";
+ /** @hide */
+ public static final Validator SIP_ASK_ME_EACH_TIME_VALIDATOR = sBooleanValidator;
+
/**
* Pointer speed setting.
* This is an integer value in a range between -7 and +7, so there are 15 possible values.
@@ -2614,12 +2935,19 @@
*/
public static final String POINTER_SPEED = "pointer_speed";
+ /** @hide */
+ public static final Validator POINTER_SPEED_VALIDATOR =
+ new InclusiveFloatRangeValidator(-7, 7);
+
/**
* Whether lock-to-app will be triggered by long-press on recents.
* @hide
*/
public static final String LOCK_TO_APP_ENABLED = "lock_to_app_enabled";
+ /** @hide */
+ public static final Validator LOCK_TO_APP_ENABLED_VALIDATOR = sBooleanValidator;
+
/**
* I am the lolrus.
* <p>
@@ -2629,6 +2957,16 @@
*/
public static final String EGG_MODE = "egg_mode";
+ /** @hide */
+ public static final Validator EGG_MODE_VALIDATOR = sBooleanValidator;
+
+ /**
+ * IMPORTANT: If you add a new public settings you also have to add it to
+ * PUBLIC_SETTINGS below. If the new setting is hidden you have to add
+ * it to PRIVATE_SETTINGS below. Also add a validator that can validate
+ * the setting value. See an example above.
+ */
+
/**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
@@ -2699,17 +3037,207 @@
};
/**
- * These entries are considered common between the personal and the managed profile,
- * since the managed profile doesn't get to change them.
+ * These are all pulbic system settings
+ *
* @hide
*/
- public static final String[] CLONE_TO_MANAGED_PROFILE = {
- DATE_FORMAT,
- HAPTIC_FEEDBACK_ENABLED,
- SOUND_EFFECTS_ENABLED,
- TEXT_SHOW_PASSWORD,
- TIME_12_24
- };
+ public static final Set<String> PUBLIC_SETTINGS = new ArraySet<>();
+ static {
+ PUBLIC_SETTINGS.add(END_BUTTON_BEHAVIOR);
+ PUBLIC_SETTINGS.add(WIFI_USE_STATIC_IP);
+ PUBLIC_SETTINGS.add(WIFI_STATIC_IP);
+ PUBLIC_SETTINGS.add(WIFI_STATIC_GATEWAY);
+ PUBLIC_SETTINGS.add(WIFI_STATIC_NETMASK);
+ PUBLIC_SETTINGS.add(WIFI_STATIC_DNS1);
+ PUBLIC_SETTINGS.add(WIFI_STATIC_DNS2);
+ PUBLIC_SETTINGS.add(BLUETOOTH_DISCOVERABILITY);
+ PUBLIC_SETTINGS.add(BLUETOOTH_DISCOVERABILITY_TIMEOUT);
+ PUBLIC_SETTINGS.add(NEXT_ALARM_FORMATTED);
+ PUBLIC_SETTINGS.add(FONT_SCALE);
+ PUBLIC_SETTINGS.add(DIM_SCREEN);
+ PUBLIC_SETTINGS.add(SCREEN_OFF_TIMEOUT);
+ PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS);
+ PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS_MODE);
+ PUBLIC_SETTINGS.add(MODE_RINGER_STREAMS_AFFECTED);
+ PUBLIC_SETTINGS.add(MUTE_STREAMS_AFFECTED);
+ PUBLIC_SETTINGS.add(VIBRATE_ON);
+ PUBLIC_SETTINGS.add(VOLUME_RING);
+ PUBLIC_SETTINGS.add(VOLUME_SYSTEM);
+ PUBLIC_SETTINGS.add(VOLUME_VOICE);
+ PUBLIC_SETTINGS.add(VOLUME_MUSIC);
+ PUBLIC_SETTINGS.add(VOLUME_ALARM);
+ PUBLIC_SETTINGS.add(VOLUME_NOTIFICATION);
+ PUBLIC_SETTINGS.add(VOLUME_BLUETOOTH_SCO);
+ PUBLIC_SETTINGS.add(RINGTONE);
+ PUBLIC_SETTINGS.add(NOTIFICATION_SOUND);
+ PUBLIC_SETTINGS.add(ALARM_ALERT);
+ PUBLIC_SETTINGS.add(TEXT_AUTO_REPLACE);
+ PUBLIC_SETTINGS.add(TEXT_AUTO_CAPS);
+ PUBLIC_SETTINGS.add(TEXT_AUTO_PUNCTUATE);
+ PUBLIC_SETTINGS.add(TEXT_SHOW_PASSWORD);
+ PUBLIC_SETTINGS.add(SHOW_GTALK_SERVICE_STATUS);
+ PUBLIC_SETTINGS.add(WALLPAPER_ACTIVITY);
+ PUBLIC_SETTINGS.add(TIME_12_24);
+ PUBLIC_SETTINGS.add(DATE_FORMAT);
+ PUBLIC_SETTINGS.add(SETUP_WIZARD_HAS_RUN);
+ PUBLIC_SETTINGS.add(ACCELEROMETER_ROTATION);
+ PUBLIC_SETTINGS.add(USER_ROTATION);
+ PUBLIC_SETTINGS.add(DTMF_TONE_WHEN_DIALING);
+ PUBLIC_SETTINGS.add(SOUND_EFFECTS_ENABLED);
+ PUBLIC_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
+ PUBLIC_SETTINGS.add(SHOW_WEB_SUGGESTIONS);
+ }
+
+ /**
+ * These are all hidden system settings.
+ *
+ * @hide
+ */
+ public static final Set<String> PRIVATE_SETTINGS = new ArraySet<>();
+ static {
+ PRIVATE_SETTINGS.add(WIFI_USE_STATIC_IP);
+ PRIVATE_SETTINGS.add(END_BUTTON_BEHAVIOR);
+ PRIVATE_SETTINGS.add(ADVANCED_SETTINGS);
+ PRIVATE_SETTINGS.add(SCREEN_AUTO_BRIGHTNESS_ADJ);
+ PRIVATE_SETTINGS.add(VIBRATE_INPUT_DEVICES);
+ PRIVATE_SETTINGS.add(VOLUME_MASTER);
+ PRIVATE_SETTINGS.add(VOLUME_MASTER_MUTE);
+ PRIVATE_SETTINGS.add(MICROPHONE_MUTE);
+ PRIVATE_SETTINGS.add(NOTIFICATIONS_USE_RING_VOLUME);
+ PRIVATE_SETTINGS.add(VIBRATE_IN_SILENT);
+ PRIVATE_SETTINGS.add(MEDIA_BUTTON_RECEIVER);
+ PRIVATE_SETTINGS.add(HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY);
+ PRIVATE_SETTINGS.add(VIBRATE_WHEN_RINGING);
+ PRIVATE_SETTINGS.add(DTMF_TONE_TYPE_WHEN_DIALING);
+ PRIVATE_SETTINGS.add(HEARING_AID);
+ PRIVATE_SETTINGS.add(TTY_MODE);
+ PRIVATE_SETTINGS.add(NOTIFICATION_LIGHT_PULSE);
+ PRIVATE_SETTINGS.add(POINTER_LOCATION);
+ PRIVATE_SETTINGS.add(SHOW_TOUCHES);
+ PRIVATE_SETTINGS.add(WINDOW_ORIENTATION_LISTENER_LOG);
+ PRIVATE_SETTINGS.add(POWER_SOUNDS_ENABLED);
+ PRIVATE_SETTINGS.add(DOCK_SOUNDS_ENABLED);
+ PRIVATE_SETTINGS.add(LOCKSCREEN_SOUNDS_ENABLED);
+ PRIVATE_SETTINGS.add(LOCKSCREEN_DISABLED);
+ PRIVATE_SETTINGS.add(LOW_BATTERY_SOUND);
+ PRIVATE_SETTINGS.add(DESK_DOCK_SOUND);
+ PRIVATE_SETTINGS.add(DESK_UNDOCK_SOUND);
+ PRIVATE_SETTINGS.add(CAR_DOCK_SOUND);
+ PRIVATE_SETTINGS.add(CAR_UNDOCK_SOUND);
+ PRIVATE_SETTINGS.add(LOCK_SOUND);
+ PRIVATE_SETTINGS.add(UNLOCK_SOUND);
+ PRIVATE_SETTINGS.add(SIP_RECEIVE_CALLS);
+ PRIVATE_SETTINGS.add(SIP_CALL_OPTIONS);
+ PRIVATE_SETTINGS.add(SIP_ALWAYS);
+ PRIVATE_SETTINGS.add(SIP_ADDRESS_ONLY);
+ PRIVATE_SETTINGS.add(SIP_ASK_ME_EACH_TIME);
+ PRIVATE_SETTINGS.add(POINTER_SPEED);
+ PRIVATE_SETTINGS.add(LOCK_TO_APP_ENABLED);
+ PRIVATE_SETTINGS.add(EGG_MODE);
+ }
+
+ /**
+ * These are all pulbic system settings
+ *
+ * @hide
+ */
+ public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
+ static {
+ VALIDATORS.put(END_BUTTON_BEHAVIOR,END_BUTTON_BEHAVIOR_VALIDATOR);
+ VALIDATORS.put(WIFI_USE_STATIC_IP, WIFI_USE_STATIC_IP_VALIDATOR);
+ VALIDATORS.put(BLUETOOTH_DISCOVERABILITY, BLUETOOTH_DISCOVERABILITY_VALIDATOR);
+ VALIDATORS.put(BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+ BLUETOOTH_DISCOVERABILITY_TIMEOUT_VALIDATOR);
+ VALIDATORS.put(NEXT_ALARM_FORMATTED, NEXT_ALARM_FORMATTED_VALIDATOR);
+ VALIDATORS.put(FONT_SCALE, FONT_SCALE_VALIDATOR);
+ VALIDATORS.put(DIM_SCREEN, DIM_SCREEN_VALIDATOR);
+ VALIDATORS.put(SCREEN_OFF_TIMEOUT, SCREEN_OFF_TIMEOUT_VALIDATOR);
+ VALIDATORS.put(SCREEN_BRIGHTNESS, SCREEN_BRIGHTNESS_VALIDATOR);
+ VALIDATORS.put(SCREEN_BRIGHTNESS_MODE, SCREEN_BRIGHTNESS_MODE_VALIDATOR);
+ VALIDATORS.put(MODE_RINGER_STREAMS_AFFECTED, MODE_RINGER_STREAMS_AFFECTED_VALIDATOR);
+ VALIDATORS.put(MUTE_STREAMS_AFFECTED, MUTE_STREAMS_AFFECTED_VALIDATOR);
+ VALIDATORS.put(VIBRATE_ON, VIBRATE_ON_VALIDATOR);
+ VALIDATORS.put(VOLUME_RING, VOLUME_RING_VALIDATOR);
+ VALIDATORS.put(VOLUME_SYSTEM, VOLUME_SYSTEM_VALIDATOR);
+ VALIDATORS.put(VOLUME_VOICE, VOLUME_VOICE_VALIDATOR);
+ VALIDATORS.put(VOLUME_MUSIC, VOLUME_MUSIC_VALIDATOR);
+ VALIDATORS.put(VOLUME_ALARM, VOLUME_ALARM_VALIDATOR);
+ VALIDATORS.put(VOLUME_NOTIFICATION, VOLUME_NOTIFICATION_VALIDATOR);
+ VALIDATORS.put(VOLUME_BLUETOOTH_SCO, VOLUME_BLUETOOTH_SCO_VALIDATOR);
+ VALIDATORS.put(RINGTONE, RINGTONE_VALIDATOR);
+ VALIDATORS.put(NOTIFICATION_SOUND, NOTIFICATION_SOUND_VALIDATOR);
+ VALIDATORS.put(ALARM_ALERT, ALARM_ALERT_VALIDATOR);
+ VALIDATORS.put(TEXT_AUTO_REPLACE, TEXT_AUTO_REPLACE_VALIDATOR);
+ VALIDATORS.put(TEXT_AUTO_CAPS, TEXT_AUTO_CAPS_VALIDATOR);
+ VALIDATORS.put(TEXT_AUTO_PUNCTUATE, TEXT_AUTO_PUNCTUATE_VALIDATOR);
+ VALIDATORS.put(TEXT_SHOW_PASSWORD, TEXT_SHOW_PASSWORD_VALIDATOR);
+ VALIDATORS.put(SHOW_GTALK_SERVICE_STATUS, SHOW_GTALK_SERVICE_STATUS_VALIDATOR);
+ VALIDATORS.put(WALLPAPER_ACTIVITY, WALLPAPER_ACTIVITY_VALIDATOR);
+ VALIDATORS.put(TIME_12_24, TIME_12_24_VALIDATOR);
+ VALIDATORS.put(DATE_FORMAT, DATE_FORMAT_VALIDATOR);
+ VALIDATORS.put(SETUP_WIZARD_HAS_RUN, SETUP_WIZARD_HAS_RUN_VALIDATOR);
+ VALIDATORS.put(ACCELEROMETER_ROTATION, ACCELEROMETER_ROTATION_VALIDATOR);
+ VALIDATORS.put(USER_ROTATION, USER_ROTATION_VALIDATOR);
+ VALIDATORS.put(DTMF_TONE_WHEN_DIALING, DTMF_TONE_WHEN_DIALING_VALIDATOR);
+ VALIDATORS.put(SOUND_EFFECTS_ENABLED, SOUND_EFFECTS_ENABLED_VALIDATOR);
+ VALIDATORS.put(HAPTIC_FEEDBACK_ENABLED, HAPTIC_FEEDBACK_ENABLED_VALIDATOR);
+ VALIDATORS.put(SHOW_WEB_SUGGESTIONS, SHOW_WEB_SUGGESTIONS_VALIDATOR);
+ VALIDATORS.put(WIFI_USE_STATIC_IP, WIFI_USE_STATIC_IP_VALIDATOR);
+ VALIDATORS.put(END_BUTTON_BEHAVIOR, END_BUTTON_BEHAVIOR_VALIDATOR);
+ VALIDATORS.put(ADVANCED_SETTINGS, ADVANCED_SETTINGS_VALIDATOR);
+ VALIDATORS.put(SCREEN_AUTO_BRIGHTNESS_ADJ, SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR);
+ VALIDATORS.put(VIBRATE_INPUT_DEVICES, VIBRATE_INPUT_DEVICES_VALIDATOR);
+ VALIDATORS.put(VOLUME_MASTER, VOLUME_MASTER_VALIDATOR);
+ VALIDATORS.put(VOLUME_MASTER_MUTE, VOLUME_MASTER_MUTE_VALIDATOR);
+ VALIDATORS.put(MICROPHONE_MUTE, MICROPHONE_MUTE_VALIDATOR);
+ VALIDATORS.put(NOTIFICATIONS_USE_RING_VOLUME, NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR);
+ VALIDATORS.put(VIBRATE_IN_SILENT, VIBRATE_IN_SILENT_VALIDATOR);
+ VALIDATORS.put(MEDIA_BUTTON_RECEIVER, MEDIA_BUTTON_RECEIVER_VALIDATOR);
+ VALIDATORS.put(HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY,
+ HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY_VALIDATOR);
+ VALIDATORS.put(VIBRATE_WHEN_RINGING, VIBRATE_WHEN_RINGING_VALIDATOR);
+ VALIDATORS.put(DTMF_TONE_TYPE_WHEN_DIALING, DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR);
+ VALIDATORS.put(HEARING_AID, HEARING_AID_VALIDATOR);
+ VALIDATORS.put(TTY_MODE, TTY_MODE_VALIDATOR);
+ VALIDATORS.put(NOTIFICATION_LIGHT_PULSE, NOTIFICATION_LIGHT_PULSE_VALIDATOR);
+ VALIDATORS.put(POINTER_LOCATION, POINTER_LOCATION_VALIDATOR);
+ VALIDATORS.put(SHOW_TOUCHES, SHOW_TOUCHES_VALIDATOR);
+ VALIDATORS.put(WINDOW_ORIENTATION_LISTENER_LOG,
+ WINDOW_ORIENTATION_LISTENER_LOG_VALIDATOR);
+ VALIDATORS.put(LOCKSCREEN_SOUNDS_ENABLED, LOCKSCREEN_SOUNDS_ENABLED_VALIDATOR);
+ VALIDATORS.put(LOCKSCREEN_DISABLED, LOCKSCREEN_DISABLED_VALIDATOR);
+ VALIDATORS.put(SIP_RECEIVE_CALLS, SIP_RECEIVE_CALLS_VALIDATOR);
+ VALIDATORS.put(SIP_CALL_OPTIONS, SIP_CALL_OPTIONS_VALIDATOR);
+ VALIDATORS.put(SIP_ALWAYS, SIP_ALWAYS_VALIDATOR);
+ VALIDATORS.put(SIP_ADDRESS_ONLY, SIP_ADDRESS_ONLY_VALIDATOR);
+ VALIDATORS.put(SIP_ASK_ME_EACH_TIME, SIP_ASK_ME_EACH_TIME_VALIDATOR);
+ VALIDATORS.put(POINTER_SPEED, POINTER_SPEED_VALIDATOR);
+ VALIDATORS.put(LOCK_TO_APP_ENABLED, LOCK_TO_APP_ENABLED_VALIDATOR);
+ VALIDATORS.put(EGG_MODE, EGG_MODE_VALIDATOR);
+ VALIDATORS.put(WIFI_STATIC_IP, WIFI_STATIC_IP_VALIDATOR);
+ VALIDATORS.put(WIFI_STATIC_GATEWAY, WIFI_STATIC_GATEWAY_VALIDATOR);
+ VALIDATORS.put(WIFI_STATIC_NETMASK, WIFI_STATIC_NETMASK_VALIDATOR);
+ VALIDATORS.put(WIFI_STATIC_DNS1, WIFI_STATIC_DNS1_VALIDATOR);
+ VALIDATORS.put(WIFI_STATIC_DNS2, WIFI_STATIC_DNS2_VALIDATOR);
+ }
+
+ /**
+ * These entries are considered common between the personal and the managed profile,
+ * since the managed profile doesn't get to change them.
+ */
+ private static final Set<String> CLONE_TO_MANAGED_PROFILE = new ArraySet<>();
+ static {
+ CLONE_TO_MANAGED_PROFILE.add(DATE_FORMAT);
+ CLONE_TO_MANAGED_PROFILE.add(HAPTIC_FEEDBACK_ENABLED);
+ CLONE_TO_MANAGED_PROFILE.add(SOUND_EFFECTS_ENABLED);
+ CLONE_TO_MANAGED_PROFILE.add(TEXT_SHOW_PASSWORD);
+ CLONE_TO_MANAGED_PROFILE.add(TIME_12_24);
+ }
+
+ /** @hide */
+ public static void getCloneToManagedProfileSettings(Set<String> outKeySet) {
+ outKeySet.addAll(CLONE_TO_MANAGED_PROFILE);
+ }
/**
* When to use Wi-Fi calling
@@ -3099,7 +3627,7 @@
}
/** @hide */
- public static void getMovedKeys(HashSet<String> outKeySet) {
+ public static void getMovedToGlobalSettings(Set<String> outKeySet) {
outKeySet.addAll(MOVED_TO_GLOBAL);
}
@@ -4896,22 +5424,27 @@
/**
* These entries are considered common between the personal and the managed profile,
* since the managed profile doesn't get to change them.
- * @hide
*/
- public static final String[] CLONE_TO_MANAGED_PROFILE = {
- ACCESSIBILITY_ENABLED,
- ALLOW_MOCK_LOCATION,
- ALLOWED_GEOLOCATION_ORIGINS,
- DEFAULT_INPUT_METHOD,
- ENABLED_ACCESSIBILITY_SERVICES,
- ENABLED_INPUT_METHODS,
- LOCATION_MODE,
- LOCATION_PROVIDERS_ALLOWED,
- LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
- SELECTED_INPUT_METHOD_SUBTYPE,
- SELECTED_SPELL_CHECKER,
- SELECTED_SPELL_CHECKER_SUBTYPE
- };
+ private static final Set<String> CLONE_TO_MANAGED_PROFILE = new ArraySet<>();
+ static {
+ CLONE_TO_MANAGED_PROFILE.add(ACCESSIBILITY_ENABLED);
+ CLONE_TO_MANAGED_PROFILE.add(ALLOW_MOCK_LOCATION);
+ CLONE_TO_MANAGED_PROFILE.add(ALLOWED_GEOLOCATION_ORIGINS);
+ CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD);
+ CLONE_TO_MANAGED_PROFILE.add(ENABLED_ACCESSIBILITY_SERVICES);
+ CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
+ CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
+ CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED);
+ CLONE_TO_MANAGED_PROFILE.add(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
+ CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
+ CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER);
+ CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER_SUBTYPE);
+ }
+
+ /** @hide */
+ public static void getCloneToManagedProfileSettings(Set<String> outKeySet) {
+ outKeySet.addAll(CLONE_TO_MANAGED_PROFILE);
+ }
/**
* Helper method for determining if a location provider is enabled.
@@ -6693,6 +7226,11 @@
MOVED_TO_SECURE.add(Settings.Global.INSTALL_NON_MARKET_APPS);
}
+ /** @hide */
+ public static void getMovedToSecureSettings(Set<String> outKeySet) {
+ outKeySet.addAll(MOVED_TO_SECURE);
+ }
+
/**
* Look up a name in the database.
* @param resolver to access the database with
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 3c57dda..fa5ac42 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -18,6 +18,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.AlarmManager;
@@ -442,6 +443,7 @@
*
* @return The view if found or null otherwise.
*/
+ @Nullable
public View findViewById(int id) {
return getWindow().findViewById(id);
}
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 06df683..7ce44e1 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -26,6 +26,7 @@
import libcore.util.EmptyArray;
import java.lang.reflect.Array;
+import java.util.IdentityHashMap;
/**
* This is the class for text whose content and markup can both be changed.
@@ -68,6 +69,7 @@
mSpanStarts = EmptyArray.INT;
mSpanEnds = EmptyArray.INT;
mSpanFlags = EmptyArray.INT;
+ mSpanMax = EmptyArray.INT;
if (text instanceof Spanned) {
Spanned sp = (Spanned) text;
@@ -94,6 +96,7 @@
setSpan(false, spans[i], st, en, fl);
}
+ restoreInvariants();
}
}
@@ -147,9 +150,12 @@
if (mGapLength < 1)
new Exception("mGapLength < 1").printStackTrace();
- for (int i = 0; i < mSpanCount; i++) {
- if (mSpanStarts[i] > mGapStart) mSpanStarts[i] += delta;
- if (mSpanEnds[i] > mGapStart) mSpanEnds[i] += delta;
+ if (mSpanCount != 0) {
+ for (int i = 0; i < mSpanCount; i++) {
+ if (mSpanStarts[i] > mGapStart) mSpanStarts[i] += delta;
+ if (mSpanEnds[i] > mGapStart) mSpanEnds[i] += delta;
+ }
+ calcMax(treeRoot());
}
}
@@ -167,35 +173,38 @@
System.arraycopy(mText, where + mGapLength - overlap, mText, mGapStart, overlap);
}
- // XXX be more clever
- for (int i = 0; i < mSpanCount; i++) {
- int start = mSpanStarts[i];
- int end = mSpanEnds[i];
+ // TODO: be more clever (although the win really isn't that big)
+ if (mSpanCount != 0) {
+ for (int i = 0; i < mSpanCount; i++) {
+ int start = mSpanStarts[i];
+ int end = mSpanEnds[i];
- if (start > mGapStart)
- start -= mGapLength;
- if (start > where)
- start += mGapLength;
- else if (start == where) {
- int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
-
- if (flag == POINT || (atEnd && flag == PARAGRAPH))
+ if (start > mGapStart)
+ start -= mGapLength;
+ if (start > where)
start += mGapLength;
- }
+ else if (start == where) {
+ int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
- if (end > mGapStart)
- end -= mGapLength;
- if (end > where)
- end += mGapLength;
- else if (end == where) {
- int flag = (mSpanFlags[i] & END_MASK);
+ if (flag == POINT || (atEnd && flag == PARAGRAPH))
+ start += mGapLength;
+ }
- if (flag == POINT || (atEnd && flag == PARAGRAPH))
+ if (end > mGapStart)
+ end -= mGapLength;
+ if (end > where)
end += mGapLength;
- }
+ else if (end == where) {
+ int flag = (mSpanFlags[i] & END_MASK);
- mSpanStarts[i] = start;
- mSpanEnds[i] = end;
+ if (flag == POINT || (atEnd && flag == PARAGRAPH))
+ end += mGapLength;
+ }
+
+ mSpanStarts[i] = start;
+ mSpanEnds[i] = end;
+ }
+ calcMax(treeRoot());
}
mGapStart = where;
@@ -243,6 +252,9 @@
sendSpanRemoved(what, ostart, oend);
}
+ if (mIndexOfSpan != null) {
+ mIndexOfSpan.clear();
+ }
}
// Documentation from interface
@@ -277,12 +289,39 @@
return append(String.valueOf(text));
}
+ // Returns true if a node was removed (so we can restart search from root)
+ private boolean removeSpansForChange(int start, int end, boolean textIsRemoved, int i) {
+ if ((i & 1) != 0) {
+ // internal tree node
+ if (resolveGap(mSpanMax[i]) >= start &&
+ removeSpansForChange(start, end, textIsRemoved, leftChild(i))) {
+ return true;
+ }
+ }
+ if (i < mSpanCount) {
+ if ((mSpanFlags[i] & Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) ==
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE &&
+ mSpanStarts[i] >= start && mSpanStarts[i] < mGapStart + mGapLength &&
+ mSpanEnds[i] >= start && mSpanEnds[i] < mGapStart + mGapLength &&
+ // The following condition indicates that the span would become empty
+ (textIsRemoved || mSpanStarts[i] > start || mSpanEnds[i] < mGapStart)) {
+ mIndexOfSpan.remove(mSpans[i]);
+ removeSpan(i);
+ return true;
+ }
+ return resolveGap(mSpanStarts[i]) <= end && (i & 1) != 0 &&
+ removeSpansForChange(start, end, textIsRemoved, rightChild(i));
+ }
+ return false;
+ }
+
private void change(int start, int end, CharSequence cs, int csStart, int csEnd) {
// Can be negative
final int replacedLength = end - start;
final int replacementLength = csEnd - csStart;
final int nbNewChars = replacementLength - replacedLength;
+ boolean changed = false;
for (int i = mSpanCount - 1; i >= 0; i--) {
int spanStart = mSpanStarts[i];
if (spanStart > mGapStart)
@@ -309,8 +348,10 @@
break;
}
- if (spanStart != ost || spanEnd != oen)
+ if (spanStart != ost || spanEnd != oen) {
setSpan(false, mSpans[i], spanStart, spanEnd, mSpanFlags[i]);
+ changed = true;
+ }
}
int flags = 0;
@@ -320,6 +361,9 @@
else if (spanEnd == end + nbNewChars) flags |= SPAN_END_AT_END;
mSpanFlags[i] |= flags;
}
+ if (changed) {
+ restoreInvariants();
+ }
moveGapTo(end);
@@ -331,23 +375,10 @@
// The removal pass needs to be done before the gap is updated in order to broadcast the
// correct previous positions to the correct intersecting SpanWatchers
if (replacedLength > 0) { // no need for span fixup on pure insertion
- // A for loop will not work because the array is being modified
- // Do not iterate in reverse to keep the SpanWatchers notified in ordering
- // Also, a removed SpanWatcher should not get notified of removed spans located
- // further in the span array.
- int i = 0;
- while (i < mSpanCount) {
- if ((mSpanFlags[i] & Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) ==
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE &&
- mSpanStarts[i] >= start && mSpanStarts[i] < mGapStart + mGapLength &&
- mSpanEnds[i] >= start && mSpanEnds[i] < mGapStart + mGapLength &&
- // This condition indicates that the span would become empty
- (textIsRemoved || mSpanStarts[i] > start || mSpanEnds[i] < mGapStart)) {
- removeSpan(i);
- continue; // do not increment i, spans will be shifted left in the array
- }
-
- i++;
+ while (mSpanCount > 0 &&
+ removeSpansForChange(start, end, textIsRemoved, treeRoot())) {
+ // keep deleting spans as needed, and restart from root after every deletion
+ // because deletion can invalidate an index.
}
}
@@ -360,6 +391,7 @@
TextUtils.getChars(cs, csStart, csEnd, mText, start);
if (replacedLength > 0) { // no need for span fixup on pure insertion
+ // TODO potential optimization: only update bounds on intersecting spans
final boolean atEnd = (mGapStart + mGapLength == mText.length);
for (int i = 0; i < mSpanCount; i++) {
@@ -371,10 +403,10 @@
mSpanEnds[i] = updatedIntervalBound(mSpanEnds[i], start, nbNewChars, endFlag,
atEnd, textIsRemoved);
}
+ // TODO potential optimization: only fix up invariants when bounds actually changed
+ restoreInvariants();
}
- mSpanCountBeforeAdd = mSpanCount;
-
if (cs instanceof Spanned) {
Spanned sp = (Spanned) cs;
Object[] spans = sp.getSpans(csStart, csEnd, Object.class);
@@ -389,9 +421,10 @@
// Add span only if this object is not yet used as a span in this string
if (getSpanStart(spans[i]) < 0) {
setSpan(false, spans[i], st - csStart + start, en - csStart + start,
- sp.getSpanFlags(spans[i]));
+ sp.getSpanFlags(spans[i]) | SPAN_ADDED);
}
}
+ restoreInvariants();
}
}
@@ -427,6 +460,7 @@
return offset;
}
+ // Note: caller is responsible for removing the mIndexOfSpan entry.
private void removeSpan(int i) {
Object object = mSpans[i];
@@ -444,8 +478,12 @@
mSpanCount--;
+ invalidateIndex(i);
mSpans[mSpanCount] = null;
+ // Invariants must be restored before sending span removed notifications.
+ restoreInvariants();
+
sendSpanRemoved(object, start, end);
}
@@ -496,10 +534,12 @@
change(start, end, tb, tbstart, tbend);
if (adjustSelection) {
+ boolean changed = false;
if (selectionStart > start && selectionStart < end) {
final int offset = (selectionStart - start) * newLen / origLen;
selectionStart = start + offset;
+ changed = true;
setSpan(false, Selection.SELECTION_START, selectionStart, selectionStart,
Spanned.SPAN_POINT_POINT);
}
@@ -507,9 +547,13 @@
final int offset = (selectionEnd - start) * newLen / origLen;
selectionEnd = start + offset;
+ changed = true;
setSpan(false, Selection.SELECTION_END, selectionEnd, selectionEnd,
Spanned.SPAN_POINT_POINT);
}
+ if (changed) {
+ restoreInvariants();
+ }
}
sendTextChanged(textWatchers, start, origLen, newLen);
@@ -536,12 +580,15 @@
}
private void sendToSpanWatchers(int replaceStart, int replaceEnd, int nbNewChars) {
- for (int i = 0; i < mSpanCountBeforeAdd; i++) {
+ for (int i = 0; i < mSpanCount; i++) {
+ int spanFlags = mSpanFlags[i];
+
+ // This loop handles only modified (not added) spans.
+ if ((spanFlags & SPAN_ADDED) != 0) continue;
int spanStart = mSpanStarts[i];
int spanEnd = mSpanEnds[i];
if (spanStart > mGapStart) spanStart -= mGapLength;
if (spanEnd > mGapStart) spanEnd -= mGapLength;
- int spanFlags = mSpanFlags[i];
int newReplaceEnd = replaceEnd + nbNewChars;
boolean spanChanged = false;
@@ -588,13 +635,17 @@
mSpanFlags[i] &= ~SPAN_START_END_MASK;
}
- // The spans starting at mIntermediateSpanCount were added from the replacement text
- for (int i = mSpanCountBeforeAdd; i < mSpanCount; i++) {
- int spanStart = mSpanStarts[i];
- int spanEnd = mSpanEnds[i];
- if (spanStart > mGapStart) spanStart -= mGapLength;
- if (spanEnd > mGapStart) spanEnd -= mGapLength;
- sendSpanAdded(mSpans[i], spanStart, spanEnd);
+ // Handle added spans
+ for (int i = 0; i < mSpanCount; i++) {
+ int spanFlags = mSpanFlags[i];
+ if ((spanFlags & SPAN_ADDED) != 0) {
+ mSpanFlags[i] &= ~SPAN_ADDED;
+ int spanStart = mSpanStarts[i];
+ int spanEnd = mSpanEnds[i];
+ if (spanStart > mGapStart) spanStart -= mGapLength;
+ if (spanEnd > mGapStart) spanEnd -= mGapLength;
+ sendSpanAdded(mSpans[i], spanStart, spanEnd);
+ }
}
}
@@ -607,6 +658,9 @@
setSpan(true, what, start, end, flags);
}
+ // Note: if send is false, then it is the caller's responsibility to restore
+ // invariants. If send is false and the span already exists, then this method
+ // will not change the index of any spans.
private void setSpan(boolean send, Object what, int start, int end, int flags) {
checkRange("setSpan", start, end);
@@ -661,8 +715,10 @@
int count = mSpanCount;
Object[] spans = mSpans;
- for (int i = 0; i < count; i++) {
- if (spans[i] == what) {
+ if (mIndexOfSpan != null) {
+ Integer index = mIndexOfSpan.get(what);
+ if (index != null) {
+ int i = index;
int ostart = mSpanStarts[i];
int oend = mSpanEnds[i];
@@ -675,7 +731,10 @@
mSpanEnds[i] = end;
mSpanFlags[i] = flags;
- if (send) sendSpanChanged(what, ostart, oend, nstart, nend);
+ if (send) {
+ restoreInvariants();
+ sendSpanChanged(what, ostart, oend, nstart, nend);
+ }
return;
}
@@ -685,43 +744,48 @@
mSpanStarts = GrowingArrayUtils.append(mSpanStarts, mSpanCount, start);
mSpanEnds = GrowingArrayUtils.append(mSpanEnds, mSpanCount, end);
mSpanFlags = GrowingArrayUtils.append(mSpanFlags, mSpanCount, flags);
+ invalidateIndex(mSpanCount);
mSpanCount++;
+ // Make sure there is enough room for empty interior nodes.
+ // This magic formula computes the size of the smallest perfect binary
+ // tree no smaller than mSpanCount.
+ int sizeOfMax = 2 * treeRoot() + 1;
+ if (mSpanMax.length < sizeOfMax) {
+ mSpanMax = new int[sizeOfMax];
+ }
- if (send) sendSpanAdded(what, nstart, nend);
+ if (send) {
+ restoreInvariants();
+ sendSpanAdded(what, nstart, nend);
+ }
}
/**
* Remove the specified markup object from the buffer.
*/
public void removeSpan(Object what) {
- for (int i = mSpanCount - 1; i >= 0; i--) {
- if (mSpans[i] == what) {
- removeSpan(i);
- return;
- }
+ if (mIndexOfSpan == null) return;
+ Integer i = mIndexOfSpan.remove(what);
+ if (i != null) {
+ removeSpan(i.intValue());
}
}
/**
+ * Return externally visible offset given offset into gapped buffer.
+ */
+ private int resolveGap(int i) {
+ return i > mGapStart ? i - mGapLength : i;
+ }
+
+ /**
* Return the buffer offset of the beginning of the specified
* markup object, or -1 if it is not attached to this buffer.
*/
public int getSpanStart(Object what) {
- int count = mSpanCount;
- Object[] spans = mSpans;
-
- for (int i = count - 1; i >= 0; i--) {
- if (spans[i] == what) {
- int where = mSpanStarts[i];
-
- if (where > mGapStart)
- where -= mGapLength;
-
- return where;
- }
- }
-
- return -1;
+ if (mIndexOfSpan == null) return -1;
+ Integer i = mIndexOfSpan.get(what);
+ return i == null ? -1 : resolveGap(mSpanStarts[i]);
}
/**
@@ -729,21 +793,9 @@
* markup object, or -1 if it is not attached to this buffer.
*/
public int getSpanEnd(Object what) {
- int count = mSpanCount;
- Object[] spans = mSpans;
-
- for (int i = count - 1; i >= 0; i--) {
- if (spans[i] == what) {
- int where = mSpanEnds[i];
-
- if (where > mGapStart)
- where -= mGapLength;
-
- return where;
- }
- }
-
- return -1;
+ if (mIndexOfSpan == null) return -1;
+ Integer i = mIndexOfSpan.get(what);
+ return i == null ? -1 : resolveGap(mSpanEnds[i]);
}
/**
@@ -751,16 +803,9 @@
* markup object, or 0 if it is not attached to this buffer.
*/
public int getSpanFlags(Object what) {
- int count = mSpanCount;
- Object[] spans = mSpans;
-
- for (int i = count - 1; i >= 0; i--) {
- if (spans[i] == what) {
- return mSpanFlags[i];
- }
- }
-
- return 0;
+ if (mIndexOfSpan == null) return 0;
+ Integer i = mIndexOfSpan.get(what);
+ return i == null ? 0 : mSpanFlags[i];
}
/**
@@ -770,59 +815,84 @@
*/
@SuppressWarnings("unchecked")
public <T> T[] getSpans(int queryStart, int queryEnd, Class<T> kind) {
- if (kind == null) return ArrayUtils.emptyArray(kind);
+ if (kind == null || mSpanCount == 0) return ArrayUtils.emptyArray(kind);
+ int count = countSpans(queryStart, queryEnd, kind, treeRoot());
+ if (count == 0) {
+ return ArrayUtils.emptyArray(kind);
+ }
- int spanCount = mSpanCount;
- Object[] spans = mSpans;
- int[] starts = mSpanStarts;
- int[] ends = mSpanEnds;
- int[] flags = mSpanFlags;
- int gapstart = mGapStart;
- int gaplen = mGapLength;
+ // Safe conversion, but requires a suppressWarning
+ T[] ret = (T[]) Array.newInstance(kind, count);
+ getSpansRec(queryStart, queryEnd, kind, treeRoot(), ret, 0);
+ return ret;
+ }
+ private int countSpans(int queryStart, int queryEnd, Class kind, int i) {
int count = 0;
- T[] ret = null;
- T ret1 = null;
-
- for (int i = 0; i < spanCount; i++) {
- int spanStart = starts[i];
- if (spanStart > gapstart) {
- spanStart -= gaplen;
+ if ((i & 1) != 0) {
+ // internal tree node
+ int left = leftChild(i);
+ int spanMax = mSpanMax[left];
+ if (spanMax > mGapStart) {
+ spanMax -= mGapLength;
}
- if (spanStart > queryEnd) {
- continue;
+ if (spanMax >= queryStart) {
+ count = countSpans(queryStart, queryEnd, kind, left);
}
-
- int spanEnd = ends[i];
- if (spanEnd > gapstart) {
- spanEnd -= gaplen;
+ }
+ if (i < mSpanCount) {
+ int spanStart = mSpanStarts[i];
+ if (spanStart > mGapStart) {
+ spanStart -= mGapLength;
}
- if (spanEnd < queryStart) {
- continue;
- }
-
- if (spanStart != spanEnd && queryStart != queryEnd) {
- if (spanStart == queryEnd)
- continue;
- if (spanEnd == queryStart)
- continue;
- }
-
- // Expensive test, should be performed after the previous tests
- if (!kind.isInstance(spans[i])) continue;
-
- if (count == 0) {
- // Safe conversion thanks to the isInstance test above
- ret1 = (T) spans[i];
- count++;
- } else {
- if (count == 1) {
- // Safe conversion, but requires a suppressWarning
- ret = (T[]) Array.newInstance(kind, spanCount - i + 1);
- ret[0] = ret1;
+ if (spanStart <= queryEnd) {
+ int spanEnd = mSpanEnds[i];
+ if (spanEnd > mGapStart) {
+ spanEnd -= mGapLength;
}
+ if (spanEnd >= queryStart &&
+ (spanStart == spanEnd || queryStart == queryEnd ||
+ (spanStart != queryEnd && spanEnd != queryStart)) &&
+ kind.isInstance(mSpans[i])) {
+ count++;
+ }
+ if ((i & 1) != 0) {
+ count += countSpans(queryStart, queryEnd, kind, rightChild(i));
+ }
+ }
+ }
+ return count;
+ }
- int prio = flags[i] & SPAN_PRIORITY;
+ @SuppressWarnings("unchecked")
+ private <T> int getSpansRec(int queryStart, int queryEnd, Class<T> kind,
+ int i, T[] ret, int count) {
+ if ((i & 1) != 0) {
+ // internal tree node
+ int left = leftChild(i);
+ int spanMax = mSpanMax[left];
+ if (spanMax > mGapStart) {
+ spanMax -= mGapLength;
+ }
+ if (spanMax >= queryStart) {
+ count = getSpansRec(queryStart, queryEnd, kind, left, ret, count);
+ }
+ }
+ if (i >= mSpanCount) return count;
+ int spanStart = mSpanStarts[i];
+ if (spanStart > mGapStart) {
+ spanStart -= mGapLength;
+ }
+ if (spanStart <= queryEnd) {
+ int spanEnd = mSpanEnds[i];
+ if (spanEnd > mGapStart) {
+ spanEnd -= mGapLength;
+ }
+ if (spanEnd >= queryStart &&
+ (spanStart == spanEnd || queryStart == queryEnd ||
+ (spanStart != queryEnd && spanEnd != queryStart)) &&
+ kind.isInstance(mSpans[i])) {
+ int prio = mSpanFlags[i] & SPAN_PRIORITY;
if (prio != 0) {
int j;
@@ -836,32 +906,18 @@
System.arraycopy(ret, j, ret, j + 1, count - j);
// Safe conversion thanks to the isInstance test above
- ret[j] = (T) spans[i];
- count++;
+ ret[j] = (T) mSpans[i];
} else {
// Safe conversion thanks to the isInstance test above
- ret[count++] = (T) spans[i];
+ ret[count] = (T) mSpans[i];
}
+ count++;
+ }
+ if (count < ret.length && (i & 1) != 0) {
+ count = getSpansRec(queryStart, queryEnd, kind, rightChild(i), ret, count);
}
}
-
- if (count == 0) {
- return ArrayUtils.emptyArray(kind);
- }
- if (count == 1) {
- // Safe conversion, but requires a suppressWarning
- ret = (T[]) Array.newInstance(kind, 1);
- ret[0] = ret1;
- return ret;
- }
- if (count == ret.length) {
- return ret;
- }
-
- // Safe conversion, but requires a suppressWarning
- T[] nret = (T[]) Array.newInstance(kind, count);
- System.arraycopy(ret, 0, nret, 0, count);
- return nret;
+ return count;
}
/**
@@ -870,30 +926,31 @@
* begins or ends.
*/
public int nextSpanTransition(int start, int limit, Class kind) {
- int count = mSpanCount;
- Object[] spans = mSpans;
- int[] starts = mSpanStarts;
- int[] ends = mSpanEnds;
- int gapstart = mGapStart;
- int gaplen = mGapLength;
-
+ if (mSpanCount == 0) return limit;
if (kind == null) {
kind = Object.class;
}
+ return nextSpanTransitionRec(start, limit, kind, treeRoot());
+ }
- for (int i = 0; i < count; i++) {
- int st = starts[i];
- int en = ends[i];
-
- if (st > gapstart)
- st -= gaplen;
- if (en > gapstart)
- en -= gaplen;
-
- if (st > start && st < limit && kind.isInstance(spans[i]))
+ private int nextSpanTransitionRec(int start, int limit, Class kind, int i) {
+ if ((i & 1) != 0) {
+ // internal tree node
+ int left = leftChild(i);
+ if (resolveGap(mSpanMax[left]) > start) {
+ limit = nextSpanTransitionRec(start, limit, kind, left);
+ }
+ }
+ if (i < mSpanCount) {
+ int st = resolveGap(mSpanStarts[i]);
+ int en = resolveGap(mSpanEnds[i]);
+ if (st > start && st < limit && kind.isInstance(mSpans[i]))
limit = st;
- if (en > start && en < limit && kind.isInstance(spans[i]))
+ if (en > start && en < limit && kind.isInstance(mSpans[i]))
limit = en;
+ if (st < limit && (i & 1) != 0) {
+ limit = nextSpanTransitionRec(start, limit, kind, rightChild(i));
+ }
}
return limit;
@@ -1339,6 +1396,118 @@
return hash;
}
+ // Primitives for treating span list as binary tree
+
+ // The spans (along with start and end offsets and flags) are stored in linear arrays sorted
+ // by start offset. For fast searching, there is a binary search structure imposed over these
+ // arrays. This structure is inorder traversal of a perfect binary tree, a slightly unusual
+ // but advantageous approach.
+
+ // The value-containing nodes are indexed 0 <= i < n (where n = mSpanCount), thus preserving
+ // logic that accesses the values as a contiguous array. Other balanced binary tree approaches
+ // (such as a complete binary tree) would require some shuffling of node indices.
+
+ // Basic properties of this structure: For a perfect binary tree of height m:
+ // The tree has 2^(m+1) - 1 total nodes.
+ // The root of the tree has index 2^m - 1.
+ // All leaf nodes have even index, all interior nodes odd.
+ // The height of a node of index i is the number of trailing ones in i's binary representation.
+ // The left child of a node i of height h is i - 2^(h - 1).
+ // The right child of a node i of height h is i + 2^(h - 1).
+
+ // Note that for arbitrary n, interior nodes of this tree may be >= n. Thus, the general
+ // structure of a recursive traversal of node i is:
+ // * traverse left child if i is an interior node
+ // * process i if i < n
+ // * traverse right child if i is an interior node and i < n
+
+ private int treeRoot() {
+ return Integer.highestOneBit(mSpanCount) - 1;
+ }
+
+ // (i+1) & ~i is equal to 2^(the number of trailing ones in i)
+ private static int leftChild(int i) {
+ return i - (((i + 1) & ~i) >> 1);
+ }
+
+ private static int rightChild(int i) {
+ return i + (((i + 1) & ~i) >> 1);
+ }
+
+ // The span arrays are also augmented by an mSpanMax[] array that represents an interval tree
+ // over the binary tree structure described above. For each node, the mSpanMax[] array contains
+ // the maximum value of mSpanEnds of that node and its descendants. Thus, traversals can
+ // easily reject subtrees that contain no spans overlapping the area of interest.
+
+ // Note that mSpanMax[] also has a valid valuefor interior nodes of index >= n, but which have
+ // descendants of index < n. In these cases, it simply represents the maximum span end of its
+ // descendants. This is a consequence of the perfect binary tree structure.
+ private int calcMax(int i) {
+ int max = 0;
+ if ((i & 1) != 0) {
+ // internal tree node
+ max = calcMax(leftChild(i));
+ }
+ if (i < mSpanCount) {
+ max = Math.max(max, mSpanEnds[i]);
+ if ((i & 1) != 0) {
+ max = Math.max(max, calcMax(rightChild(i)));
+ }
+ }
+ mSpanMax[i] = max;
+ return max;
+ }
+
+ // restores binary interval tree invariants after any mutation of span structure
+ private void restoreInvariants() {
+ if (mSpanCount == 0) return;
+
+ // invariant 1: span starts are nondecreasing
+
+ // This is a simple insertion sort because we expect it to be mostly sorted.
+ for (int i = 1; i < mSpanCount; i++) {
+ if (mSpanStarts[i] < mSpanStarts[i - 1]) {
+ Object span = mSpans[i];
+ int start = mSpanStarts[i];
+ int end = mSpanEnds[i];
+ int flags = mSpanFlags[i];
+ int j = i;
+ do {
+ mSpans[j] = mSpans[j - 1];
+ mSpanStarts[j] = mSpanStarts[j - 1];
+ mSpanEnds[j] = mSpanEnds[j - 1];
+ mSpanFlags[j] = mSpanFlags[j - 1];
+ j--;
+ } while (j > 0 && start < mSpanStarts[j - 1]);
+ mSpans[j] = span;
+ mSpanStarts[j] = start;
+ mSpanEnds[j] = end;
+ mSpanFlags[j] = flags;
+ invalidateIndex(j);
+ }
+ }
+
+ // invariant 2: max is max span end for each node and its descendants
+ calcMax(treeRoot());
+
+ // invariant 3: mIndexOfSpan maps spans back to indices
+ if (mIndexOfSpan == null) {
+ mIndexOfSpan = new IdentityHashMap<Object, Integer>();
+ }
+ for (int i = mLowWaterMark; i < mSpanCount; i++) {
+ Integer existing = mIndexOfSpan.get(mSpans[i]);
+ if (existing == null || existing != i) {
+ mIndexOfSpan.put(mSpans[i], i);
+ }
+ }
+ mLowWaterMark = Integer.MAX_VALUE;
+ }
+
+ // Call this on any update to mSpans[], so that mIndexOfSpan can be updated
+ private void invalidateIndex(int i) {
+ mLowWaterMark = Math.min(i, mLowWaterMark);
+ }
+
private static final InputFilter[] NO_FILTERS = new InputFilter[0];
private InputFilter[] mFilters = NO_FILTERS;
@@ -1349,9 +1518,11 @@
private Object[] mSpans;
private int[] mSpanStarts;
private int[] mSpanEnds;
+ private int[] mSpanMax; // see calcMax() for an explanation of what this array stores
private int[] mSpanFlags;
private int mSpanCount;
- private int mSpanCountBeforeAdd;
+ private IdentityHashMap<Object, Integer> mIndexOfSpan;
+ private int mLowWaterMark; // indices below this have not been touched
// TODO These value are tightly related to the public SPAN_MARK/POINT values in {@link Spanned}
private static final int MARK = 1;
@@ -1363,6 +1534,7 @@
private static final int START_SHIFT = 4;
// These bits are not (currently) used by SPANNED flags
+ private static final int SPAN_ADDED = 0x800;
private static final int SPAN_START_AT_START = 0x1000;
private static final int SPAN_START_AT_END = 0x2000;
private static final int SPAN_END_AT_START = 0x4000;
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index d0ed871..ac98e8a 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -28,9 +28,11 @@
import java.util.Formatter;
import java.util.GregorianCalendar;
import java.util.Locale;
+import java.util.TimeZone;
import libcore.icu.DateIntervalFormat;
import libcore.icu.LocaleData;
+import libcore.icu.RelativeDateTimeFormatter;
/**
* This class contains various date-related utilities for creating text for things like
@@ -242,6 +244,8 @@
/**
* Returns a string describing the elapsed time since startTime.
+ * <p>
+ * The minimum timespan to report is set to {@link #MINUTE_IN_MILLIS}.
* @param startTime some time in the past.
* @return a String object containing the elapsed time.
* @see #getRelativeTimeSpanString(long, long, long)
@@ -289,69 +293,8 @@
*/
public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution,
int flags) {
- Resources r = Resources.getSystem();
- boolean abbrevRelative = (flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0;
-
- boolean past = (now >= time);
- long duration = Math.abs(now - time);
-
- int resId;
- long count;
- if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) {
- count = duration / SECOND_IN_MILLIS;
- if (past) {
- if (abbrevRelative) {
- resId = com.android.internal.R.plurals.abbrev_num_seconds_ago;
- } else {
- resId = com.android.internal.R.plurals.num_seconds_ago;
- }
- } else {
- if (abbrevRelative) {
- resId = com.android.internal.R.plurals.abbrev_in_num_seconds;
- } else {
- resId = com.android.internal.R.plurals.in_num_seconds;
- }
- }
- } else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) {
- count = duration / MINUTE_IN_MILLIS;
- if (past) {
- if (abbrevRelative) {
- resId = com.android.internal.R.plurals.abbrev_num_minutes_ago;
- } else {
- resId = com.android.internal.R.plurals.num_minutes_ago;
- }
- } else {
- if (abbrevRelative) {
- resId = com.android.internal.R.plurals.abbrev_in_num_minutes;
- } else {
- resId = com.android.internal.R.plurals.in_num_minutes;
- }
- }
- } else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) {
- count = duration / HOUR_IN_MILLIS;
- if (past) {
- if (abbrevRelative) {
- resId = com.android.internal.R.plurals.abbrev_num_hours_ago;
- } else {
- resId = com.android.internal.R.plurals.num_hours_ago;
- }
- } else {
- if (abbrevRelative) {
- resId = com.android.internal.R.plurals.abbrev_in_num_hours;
- } else {
- resId = com.android.internal.R.plurals.in_num_hours;
- }
- }
- } else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) {
- return getRelativeDayString(r, time, now);
- } else {
- // We know that we won't be showing the time, so it is safe to pass
- // in a null context.
- return formatDateRange(null, time, time, flags);
- }
-
- String format = r.getQuantityString(resId, (int) count);
- return String.format(format, count);
+ return RelativeDateTimeFormatter.getRelativeTimeSpanString(Locale.getDefault(),
+ TimeZone.getDefault(), time, now, minResolution, flags);
}
/**
@@ -360,8 +303,8 @@
* <p>
* Example output strings for the US date format.
* <ul>
- * <li>3 mins ago, 10:15 AM</li>
- * <li>yesterday, 12:20 PM</li>
+ * <li>3 min. ago, 10:15 AM</li>
+ * <li>Yesterday, 12:20 PM</li>
* <li>Dec 12, 4:12 AM</li>
* <li>11/14/2007, 8:20 AM</li>
* </ul>
@@ -374,86 +317,19 @@
* @param transitionResolution the elapsed time (in milliseconds) at which
* to stop reporting relative measurements. Elapsed times greater
* than this resolution will default to normal date formatting.
- * For example, will transition from "6 days ago" to "Dec 12"
+ * For example, will transition from "7 days ago" to "Dec 12"
* when using {@link #WEEK_IN_MILLIS}.
*/
public static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution,
long transitionResolution, int flags) {
- Resources r = Resources.getSystem();
-
- long now = System.currentTimeMillis();
- long duration = Math.abs(now - time);
-
- // getRelativeTimeSpanString() doesn't correctly format relative dates
- // above a week or exact dates below a day, so clamp
- // transitionResolution as needed.
- if (transitionResolution > WEEK_IN_MILLIS) {
- transitionResolution = WEEK_IN_MILLIS;
- } else if (transitionResolution < DAY_IN_MILLIS) {
- transitionResolution = DAY_IN_MILLIS;
+ // Same reason as in formatDateRange() to explicitly indicate 12- or 24-hour format.
+ if ((flags & (FORMAT_SHOW_TIME | FORMAT_12HOUR | FORMAT_24HOUR)) == FORMAT_SHOW_TIME) {
+ flags |= DateFormat.is24HourFormat(c) ? FORMAT_24HOUR : FORMAT_12HOUR;
}
- CharSequence timeClause = formatDateRange(c, time, time, FORMAT_SHOW_TIME);
-
- String result;
- if (duration < transitionResolution) {
- CharSequence relativeClause = getRelativeTimeSpanString(time, now, minResolution, flags);
- result = r.getString(com.android.internal.R.string.relative_time, relativeClause, timeClause);
- } else {
- CharSequence dateClause = getRelativeTimeSpanString(c, time, false);
- result = r.getString(com.android.internal.R.string.date_time, dateClause, timeClause);
- }
-
- return result;
- }
-
- /**
- * Returns a string describing a day relative to the current day. For example if the day is
- * today this function returns "Today", if the day was a week ago it returns "7 days ago", and
- * if the day is in 2 weeks it returns "in 14 days".
- *
- * @param r the resources
- * @param day the relative day to describe in UTC milliseconds
- * @param today the current time in UTC milliseconds
- */
- private static final String getRelativeDayString(Resources r, long day, long today) {
- Locale locale = r.getConfiguration().locale;
- if (locale == null) {
- locale = Locale.getDefault();
- }
-
- // TODO: use TimeZone.getOffset instead.
- Time startTime = new Time();
- startTime.set(day);
- int startDay = Time.getJulianDay(day, startTime.gmtoff);
-
- Time currentTime = new Time();
- currentTime.set(today);
- int currentDay = Time.getJulianDay(today, currentTime.gmtoff);
-
- int days = Math.abs(currentDay - startDay);
- boolean past = (today > day);
-
- // TODO: some locales name other days too, such as de_DE's "Vorgestern" (today - 2).
- if (days == 1) {
- if (past) {
- return LocaleData.get(locale).yesterday;
- } else {
- return LocaleData.get(locale).tomorrow;
- }
- } else if (days == 0) {
- return LocaleData.get(locale).today;
- }
-
- int resId;
- if (past) {
- resId = com.android.internal.R.plurals.num_days_ago;
- } else {
- resId = com.android.internal.R.plurals.in_num_days;
- }
-
- String format = r.getQuantityString(resId, days);
- return String.format(format, days);
+ return RelativeDateTimeFormatter.getRelativeDateTimeString(Locale.getDefault(),
+ TimeZone.getDefault(), time, System.currentTimeMillis(), minResolution,
+ transitionResolution, flags);
}
private static void initFormatStrings() {
diff --git a/core/java/android/transition/ArcMotion.java b/core/java/android/transition/ArcMotion.java
index f95fb49..70dfe7f 100644
--- a/core/java/android/transition/ArcMotion.java
+++ b/core/java/android/transition/ArcMotion.java
@@ -21,7 +21,6 @@
import android.content.res.TypedArray;
import android.graphics.Path;
import android.util.AttributeSet;
-import android.util.FloatMath;
/**
* A PathMotion that generates a curved path along an arc on an imaginary circle containing
@@ -257,7 +256,7 @@
}
if (newArcDistance2 != 0) {
float ratio2 = newArcDistance2 / arcDist2;
- float ratio = FloatMath.sqrt(ratio2);
+ float ratio = (float) Math.sqrt(ratio2);
ex = dx + (ratio * (ex - dx));
ey = dy + (ratio * (ey - dy));
}
diff --git a/core/java/android/transition/CircularPropagation.java b/core/java/android/transition/CircularPropagation.java
index 51beb51..1e44cfa 100644
--- a/core/java/android/transition/CircularPropagation.java
+++ b/core/java/android/transition/CircularPropagation.java
@@ -16,7 +16,6 @@
package android.transition;
import android.graphics.Rect;
-import android.util.FloatMath;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -87,9 +86,9 @@
epicenterY = Math.round(loc[1] + (sceneRoot.getHeight() / 2)
+ sceneRoot.getTranslationY());
}
- float distance = distance(viewCenterX, viewCenterY, epicenterX, epicenterY);
- float maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight());
- float distanceFraction = distance/maxDistance;
+ double distance = distance(viewCenterX, viewCenterY, epicenterX, epicenterY);
+ double maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight());
+ double distanceFraction = distance/maxDistance;
long duration = transition.getDuration();
if (duration < 0) {
@@ -99,9 +98,9 @@
return Math.round(duration * directionMultiplier / mPropagationSpeed * distanceFraction);
}
- private static float distance(float x1, float y1, float x2, float y2) {
- float x = x2 - x1;
- float y = y2 - y1;
- return FloatMath.sqrt((x * x) + (y * y));
+ private static double distance(float x1, float y1, float x2, float y2) {
+ double x = x2 - x1;
+ double y = y2 - y1;
+ return Math.hypot(x, y);
}
}
diff --git a/core/java/android/transition/Explode.java b/core/java/android/transition/Explode.java
index 0ccdf15..788676a 100644
--- a/core/java/android/transition/Explode.java
+++ b/core/java/android/transition/Explode.java
@@ -22,7 +22,6 @@
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.util.FloatMath;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
@@ -143,32 +142,29 @@
int centerX = bounds.centerX();
int centerY = bounds.centerY();
- float xVector = centerX - focalX;
- float yVector = centerY - focalY;
+ double xVector = centerX - focalX;
+ double yVector = centerY - focalY;
if (xVector == 0 && yVector == 0) {
// Random direction when View is centered on focal View.
- xVector = (float) (Math.random() * 2) - 1;
- yVector = (float) (Math.random() * 2) - 1;
+ xVector = (Math.random() * 2) - 1;
+ yVector = (Math.random() * 2) - 1;
}
- float vectorSize = calculateDistance(xVector, yVector);
+ double vectorSize = Math.hypot(xVector, yVector);
xVector /= vectorSize;
yVector /= vectorSize;
- float maxDistance =
+ double maxDistance =
calculateMaxDistance(sceneRoot, focalX - sceneRootX, focalY - sceneRootY);
- outVector[0] = Math.round(maxDistance * xVector);
- outVector[1] = Math.round(maxDistance * yVector);
+ outVector[0] = (int) Math.round(maxDistance * xVector);
+ outVector[1] = (int) Math.round(maxDistance * yVector);
}
- private static float calculateMaxDistance(View sceneRoot, int focalX, int focalY) {
+ private static double calculateMaxDistance(View sceneRoot, int focalX, int focalY) {
int maxX = Math.max(focalX, sceneRoot.getWidth() - focalX);
int maxY = Math.max(focalY, sceneRoot.getHeight() - focalY);
- return calculateDistance(maxX, maxY);
+ return Math.hypot(maxX, maxY);
}
- private static float calculateDistance(float x, float y) {
- return FloatMath.sqrt((x * x) + (y * y));
- }
}
diff --git a/core/java/android/transition/PatternPathMotion.java b/core/java/android/transition/PatternPathMotion.java
index a609df6..773c387 100644
--- a/core/java/android/transition/PatternPathMotion.java
+++ b/core/java/android/transition/PatternPathMotion.java
@@ -23,7 +23,6 @@
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.util.AttributeSet;
-import android.util.FloatMath;
import android.util.PathParser;
/**
@@ -119,7 +118,7 @@
mTempMatrix.setTranslate(-startX, -startY);
float dx = endX - startX;
float dy = endY - startY;
- float distance = distance(dx, dy);
+ float distance = (float) Math.hypot(dx, dy);
float scale = 1 / distance;
mTempMatrix.postScale(scale, scale);
double angle = Math.atan2(dy, dx);
@@ -130,9 +129,9 @@
@Override
public Path getPath(float startX, float startY, float endX, float endY) {
- float dx = endX - startX;
- float dy = endY - startY;
- float length = distance(dx, dy);
+ double dx = endX - startX;
+ double dy = endY - startY;
+ float length = (float) Math.hypot(dx, dy);
double angle = Math.atan2(dy, dx);
mTempMatrix.setScale(length, length);
@@ -143,7 +142,4 @@
return path;
}
- private static float distance(float x, float y) {
- return FloatMath.sqrt((x * x) + (y * y));
- }
}
diff --git a/core/java/android/transition/SidePropagation.java b/core/java/android/transition/SidePropagation.java
index ad6c2dd..5dd1fff 100644
--- a/core/java/android/transition/SidePropagation.java
+++ b/core/java/android/transition/SidePropagation.java
@@ -16,7 +16,6 @@
package android.transition;
import android.graphics.Rect;
-import android.util.FloatMath;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 2705bcf..c942042 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -1762,7 +1762,17 @@
runAnimators();
}
- boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) {
+ /**
+ * Returns whether transition values have changed between the start scene and the end scene
+ * (thus determining whether animation is required). The default implementation compares the
+ * property values returned from {@link #getTransitionProperties()}, or all property values if
+ * {@code getTransitionProperties()} returns null. Subclasses may override this method to
+ * provide logic more specific to their transition implementation.
+ *
+ * @param oldValues the first set of values, may be {@code null}
+ * @param newValues the second set of values, may be {@code null}
+ */
+ protected boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) {
boolean valuesChanged = false;
// if oldValues null, then transition didn't care to stash values,
// and won't get canceled
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 8779229..26dca43 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -182,7 +182,7 @@
return visibility == View.VISIBLE && parent != null;
}
- private VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
+ private static VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
TransitionValues endValues) {
final VisibilityInfo visInfo = new VisibilityInfo();
visInfo.visibilityChange = false;
@@ -484,7 +484,7 @@
}
@Override
- boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) {
+ protected boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) {
if (oldValues == null && newValues == null) {
return false;
}
diff --git a/core/java/android/util/AtomicFile.java b/core/java/android/util/AtomicFile.java
index a6466fc..3aa3447 100644
--- a/core/java/android/util/AtomicFile.java
+++ b/core/java/android/util/AtomicFile.java
@@ -102,7 +102,7 @@
str = new FileOutputStream(mBaseName);
} catch (FileNotFoundException e) {
File parent = mBaseName.getParentFile();
- if (!parent.mkdir()) {
+ if (!parent.mkdirs()) {
throw new IOException("Couldn't create directory " + mBaseName);
}
FileUtils.setPermissions(
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index c855e57..d0e5b9e 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -62,6 +62,13 @@
public static final int DENSITY_HIGH = 240;
/**
+ * Intermediate density for screens that sit between {@link #DENSITY_HIGH} (240dpi) and
+ * {@link #DENSITY_XHIGH} (320dpi). This is not a density that applications should target,
+ * instead relying on the system to scale their {@link #DENSITY_XHIGH} assets for them.
+ */
+ public static final int DENSITY_280 = 280;
+
+ /**
* Standard quantized DPI for extra-high-density screens.
*/
public static final int DENSITY_XHIGH = 320;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f60e2f8..ad5d651 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3582,7 +3582,7 @@
* @param attrs The attributes of the XML tag that is inflating the view.
* @see #View(Context, AttributeSet, int)
*/
- public View(Context context, AttributeSet attrs) {
+ public View(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -3603,7 +3603,7 @@
* the view. Can be 0 to not look for defaults.
* @see #View(Context, AttributeSet)
*/
- public View(Context context, AttributeSet attrs, int defStyleAttr) {
+ public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
@@ -3640,7 +3640,7 @@
* to not look for defaults.
* @see #View(Context, AttributeSet, int)
*/
- public View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
this(context);
final TypedArray a = context.obtainStyledAttributes(
@@ -17109,6 +17109,7 @@
* @param id The id to search for.
* @return The view that has the given id in the hierarchy or null
*/
+ @Nullable
public final View findViewById(int id) {
if (id < 0) {
return null;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index e1cee1e..504a758 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1208,7 +1208,7 @@
* {@inheritDoc}
*/
public void bringChildToFront(View child) {
- int index = indexOfChild(child);
+ final int index = indexOfChild(child);
if (index >= 0) {
removeFromArray(index);
addInArray(child, mChildrenCount);
@@ -3771,7 +3771,7 @@
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
*
* @param child the child view to add
- * @param index the position at which to add the child
+ * @param index the position at which to add the child or -1 to add last
* @param params the layout parameters to set on the child
*/
public void addView(View child, int index, LayoutParams params) {
@@ -3887,7 +3887,7 @@
* If index is negative, it means put it at the end of the list.
*
* @param child the view to add to the group
- * @param index the index at which the child must be added
+ * @param index the index at which the child must be added or -1 to add last
* @param params the layout parameters to associate with the child
* @return true if the child was added, false otherwise
*/
@@ -3902,7 +3902,7 @@
* If index is negative, it means put it at the end of the list.
*
* @param child the view to add to the group
- * @param index the index at which the child must be added
+ * @param index the index at which the child must be added or -1 to add last
* @param params the layout parameters to associate with the child
* @param preventRequestLayout if true, calling this method will not trigger a
* layout request on child
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 1456b52..8964862 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -984,6 +984,7 @@
*
* @return The view if found or null otherwise.
*/
+ @Nullable
public View findViewById(int id) {
return getDecorView().findViewById(id);
}
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index 52912b1..d0dde00 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -40,6 +40,9 @@
private final Object mLock = new Object();
+ private long mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+ private long mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+
private final SparseArray<AccessibilityWindowInfo> mWindowCache =
new SparseArray<>();
@@ -73,9 +76,29 @@
synchronized (mLock) {
final int eventType = event.getEventType();
switch (eventType) {
- case AccessibilityEvent.TYPE_VIEW_FOCUSED:
- case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED:
- case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED:
+ case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
+ if (mAccessibilityFocus != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+ refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+ }
+ mAccessibilityFocus = event.getSourceNodeId();
+ refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+ } break;
+
+ case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
+ if (mAccessibilityFocus == event.getSourceNodeId()) {
+ refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+ mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+ }
+ } break;
+
+ case AccessibilityEvent.TYPE_VIEW_FOCUSED: {
+ if (mInputFocus != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+ refreshCachedNodeLocked(event.getWindowId(), mInputFocus);
+ }
+ mInputFocus = event.getSourceNodeId();
+ refreshCachedNodeLocked(event.getWindowId(), mInputFocus);
+ } break;
+
case AccessibilityEvent.TYPE_VIEW_SELECTED:
case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
case AccessibilityEvent.TYPE_VIEW_CLICKED:
@@ -268,6 +291,9 @@
final int windowId = mNodeCache.keyAt(i);
clearNodesForWindowLocked(windowId);
}
+
+ mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+ mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index b56378f..325ffdd 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -494,19 +494,17 @@
mIInputContext.finishComposingText();
} catch (RemoteException e) {
}
- // Check focus again in case that "onWindowFocus" is called before
- // handling this message.
- if (mServedView != null && mServedView.hasWindowFocus()) {
- // "finishComposingText" has been already called above. So we
- // should not call mServedInputConnection.finishComposingText here.
- // Also, please note that this handler thread could be different
- // from a thread that created mServedView. That could happen
- // the current activity is running in the system process.
- // In that case, we really should not call
- // mServedInputConnection.finishComposingText.
- if (checkFocusNoStartInput(mHasBeenInactive, false)) {
- startInputInner(null, 0, 0, 0);
- }
+ }
+ // Check focus again in case that "onWindowFocus" is called before
+ // handling this message.
+ if (mServedView != null && mServedView.hasWindowFocus()) {
+ // Please note that this handler thread could be different
+ // from a thread that created mServedView. That could happen
+ // the current activity is running in the system process.
+ // In that case, we really should not call
+ // mServedInputConnection.finishComposingText.
+ if (checkFocusNoStartInput(mHasBeenInactive, false)) {
+ startInputInner(null, 0, 0, 0);
}
}
}
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 4f6ea23..78344ac 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -381,8 +381,8 @@
}
@Override
- void onProgressRefresh(float scale, boolean fromUser) {
- super.onProgressRefresh(scale, fromUser);
+ void onProgressRefresh(float scale, boolean fromUser, int progress) {
+ super.onProgressRefresh(scale, fromUser, progress);
final Drawable thumb = mThumb;
if (thumb != null) {
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 6925756..391347e 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -24,7 +24,6 @@
import android.content.Context;
import android.graphics.Canvas;
-import android.util.FloatMath;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
@@ -220,8 +219,8 @@
if (mPullDistance == 0) {
mGlowScaleY = mGlowScaleYStart = 0;
} else {
- final float scale = Math.max(0, 1 - 1 /
- FloatMath.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3f) / 0.7f;
+ final float scale = (float) (Math.max(0, 1 - 1 /
+ Math.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3d) / 0.7d);
mGlowScaleY = mGlowScaleYStart = scale;
}
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 757038c..dd9bdb66 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -127,15 +127,16 @@
initImageView();
}
- public ImageView(Context context, AttributeSet attrs) {
+ public ImageView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
- public ImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+ public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
- public ImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initImageView();
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 9c3296b..5b0745e 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
import android.graphics.PorterDuff;
+
import com.android.internal.R;
import android.content.Context;
@@ -64,8 +65,8 @@
/**
* <p>
* Visual indicator of progress in some operation. Displays a bar to the user
- * representing how far the operation has progressed; the application can
- * change the amount of progress (modifying the length of the bar) as it moves
+ * representing how far the operation has progressed; the application can
+ * change the amount of progress (modifying the length of the bar) as it moves
* forward. There is also a secondary progress displayable on a progress bar
* which is useful for displaying intermediate progress, such as the buffer
* level during a streaming playback progress bar.
@@ -81,7 +82,7 @@
* <p>The following code example shows how a progress bar can be used from
* a worker thread to update the user interface to notify the user of progress:
* </p>
- *
+ *
* <pre>
* public class MyActivity extends Activity {
* private static final int PROGRESS = 0x1;
@@ -169,13 +170,13 @@
* </ul>
* <p>The "inverse" styles provide an inverse color scheme for the spinner, which may be necessary
* if your application uses a light colored theme (a white background).</p>
- *
- * <p><strong>XML attributes</b></strong>
- * <p>
- * See {@link android.R.styleable#ProgressBar ProgressBar Attributes},
+ *
+ * <p><strong>XML attributes</b></strong>
+ * <p>
+ * See {@link android.R.styleable#ProgressBar ProgressBar Attributes},
* {@link android.R.styleable#View View Attributes}
* </p>
- *
+ *
* @attr ref android.R.styleable#ProgressBar_animationResolution
* @attr ref android.R.styleable#ProgressBar_indeterminate
* @attr ref android.R.styleable#ProgressBar_indeterminateBehavior
@@ -244,7 +245,7 @@
public ProgressBar(Context context) {
this(context, null);
}
-
+
public ProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.progressBarStyle);
}
@@ -261,9 +262,9 @@
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.ProgressBar, defStyleAttr, defStyleRes);
-
+
mNoInvalidate = true;
-
+
final Drawable progressDrawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
if (progressDrawable != null) {
// Calling this method can set mMaxHeight, make sure the corresponding
@@ -282,11 +283,11 @@
mBehavior = a.getInt(R.styleable.ProgressBar_indeterminateBehavior, mBehavior);
final int resID = a.getResourceId(
- com.android.internal.R.styleable.ProgressBar_interpolator,
+ com.android.internal.R.styleable.ProgressBar_interpolator,
android.R.anim.linear_interpolator); // default to linear interpolator
if (resID > 0) {
setInterpolator(context, resID);
- }
+ }
setMax(a.getInt(R.styleable.ProgressBar_max, mMax));
@@ -399,12 +400,12 @@
* traverse layer and state list drawables.
*/
private Drawable tileify(Drawable drawable, boolean clip) {
-
+
if (drawable instanceof LayerDrawable) {
LayerDrawable background = (LayerDrawable) drawable;
final int N = background.getNumberOfLayers();
Drawable[] outDrawables = new Drawable[N];
-
+
for (int i = 0; i < N; i++) {
int id = background.getId(i);
outDrawables[i] = tileify(background.getDrawable(i),
@@ -412,13 +413,13 @@
}
LayerDrawable newBg = new LayerDrawable(outDrawables);
-
+
for (int i = 0; i < N; i++) {
newBg.setId(i, background.getId(i));
}
-
+
return newBg;
-
+
} else if (drawable instanceof StateListDrawable) {
StateListDrawable in = (StateListDrawable) drawable;
StateListDrawable out = new StateListDrawable();
@@ -427,7 +428,7 @@
out.addState(in.getStateSet(i), tileify(in.getStateDrawable(i), clip));
}
return out;
-
+
} else if (drawable instanceof BitmapDrawable) {
final BitmapDrawable bitmap = (BitmapDrawable) drawable;
final Bitmap tileBitmap = bitmap.getBitmap();
@@ -448,7 +449,7 @@
return clip ? new ClipDrawable(
shapeDrawable, Gravity.LEFT, ClipDrawable.HORIZONTAL) : shapeDrawable;
}
-
+
return drawable;
}
@@ -456,7 +457,7 @@
final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
return new RoundRectShape(roundedCorners, null, null);
}
-
+
/**
* Convert a AnimationDrawable for use as a barberpole animation.
* Each frame of the animation is wrapped in a ClipDrawable and
@@ -468,7 +469,7 @@
final int N = background.getNumberOfFrames();
AnimationDrawable newBg = new AnimationDrawable();
newBg.setOneShot(background.isOneShot());
-
+
for (int i = 0; i < N; i++) {
Drawable frame = tileify(background.getFrame(i), true);
frame.setLevel(10000);
@@ -479,7 +480,7 @@
}
return drawable;
}
-
+
/**
* <p>
* Initialize the progress bar's default values:
@@ -520,7 +521,7 @@
* <p>Change the indeterminate mode for this progress bar. In indeterminate
* mode, the progress is ignored and the progress bar shows an infinite
* animation instead.</p>
- *
+ *
* If this progress bar's style only supports indeterminate mode (such as the circular
* progress bars), then this will be ignored.
*
@@ -699,7 +700,7 @@
setIndeterminateDrawable(d);
}
-
+
/**
* <p>Get the drawable used to draw the progress bar in
* progress mode.</p>
@@ -1135,7 +1136,7 @@
setProgressDrawable(d);
}
-
+
/**
* @return The drawable currently used to draw the progress bar
*/
@@ -1214,7 +1215,7 @@
rd.fromUser = fromUser;
return rd;
}
-
+
public void recycle() {
sPool.release(this);
}
@@ -1257,13 +1258,13 @@
} else {
invalidate();
}
-
+
if (callBackToApp && id == R.id.progress) {
- onProgressRefresh(scale, fromUser);
+ onProgressRefresh(scale, fromUser, progress);
}
}
- void onProgressRefresh(float scale, boolean fromUser) {
+ void onProgressRefresh(float scale, boolean fromUser, int progress) {
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
scheduleAccessibilityEventSender();
}
@@ -1285,7 +1286,7 @@
}
}
}
-
+
/**
* <p>Set the current progress to the specified value. Does not do anything
* if the progress bar is in indeterminate mode.</p>
@@ -1295,13 +1296,13 @@
* @see #setIndeterminate(boolean)
* @see #isIndeterminate()
* @see #getProgress()
- * @see #incrementProgressBy(int)
+ * @see #incrementProgressBy(int)
*/
@android.view.RemotableViewMethod
public synchronized void setProgress(int progress) {
setProgress(progress, false);
}
-
+
@android.view.RemotableViewMethod
synchronized void setProgress(int progress, boolean fromUser) {
if (mIndeterminate) {
@@ -1327,7 +1328,7 @@
* Set the current secondary progress to the specified value. Does not do
* anything if the progress bar is in indeterminate mode.
* </p>
- *
+ *
* @param secondaryProgress the new secondary progress, between 0 and {@link #getMax()}
* @see #setIndeterminate(boolean)
* @see #isIndeterminate()
@@ -1408,8 +1409,8 @@
* @param max the upper range of this progress bar
*
* @see #getMax()
- * @see #setProgress(int)
- * @see #setSecondaryProgress(int)
+ * @see #setProgress(int)
+ * @see #setSecondaryProgress(int)
*/
@android.view.RemotableViewMethod
public synchronized void setMax(int max) {
@@ -1426,13 +1427,13 @@
refreshProgress(R.id.progress, mProgress, false);
}
}
-
+
/**
* <p>Increase the progress bar's progress by the specified amount.</p>
*
* @param diff the amount by which the progress must be increased
*
- * @see #setProgress(int)
+ * @see #setProgress(int)
*/
public synchronized final void incrementProgressBy(int diff) {
setProgress(mProgress + diff);
@@ -1443,7 +1444,7 @@
*
* @param diff the amount by which the secondary progress must be increased
*
- * @see #setSecondaryProgress(int)
+ * @see #setSecondaryProgress(int)
*/
public synchronized final void incrementSecondaryProgressBy(int diff) {
setSecondaryProgress(mSecondaryProgress + diff);
@@ -1466,13 +1467,13 @@
if (mInterpolator == null) {
mInterpolator = new LinearInterpolator();
}
-
+
if (mTransformation == null) {
mTransformation = new Transformation();
} else {
mTransformation.clear();
}
-
+
if (mAnimation == null) {
mAnimation = new AlphaAnimation(0.0f, 1.0f);
} else {
@@ -1623,7 +1624,7 @@
}
mIndeterminateDrawable.setBounds(left, top, right, bottom);
}
-
+
if (mProgressDrawable != null) {
mProgressDrawable.setBounds(0, 0, right, bottom);
}
@@ -1693,20 +1694,20 @@
setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
resolveSizeAndState(dh, heightMeasureSpec, 0));
}
-
+
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
updateDrawableState();
}
-
+
private void updateDrawableState() {
int[] state = getDrawableState();
-
+
if (mProgressDrawable != null && mProgressDrawable.isStateful()) {
mProgressDrawable.setState(state);
}
-
+
if (mIndeterminateDrawable != null && mIndeterminateDrawable.isStateful()) {
mIndeterminateDrawable.setState(state);
}
@@ -1728,14 +1729,14 @@
static class SavedState extends BaseSavedState {
int progress;
int secondaryProgress;
-
+
/**
* Constructor called from {@link ProgressBar#onSaveInstanceState()}
*/
SavedState(Parcelable superState) {
super(superState);
}
-
+
/**
* Constructor called from {@link #CREATOR}
*/
@@ -1769,10 +1770,10 @@
// Force our ancestor class to save its state
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
-
+
ss.progress = mProgress;
ss.secondaryProgress = mSecondaryProgress;
-
+
return ss;
}
@@ -1780,7 +1781,7 @@
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
-
+
setProgress(ss.progress);
setSecondaryProgress(ss.secondaryProgress);
}
diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java
index 4268961..f18e372 100644
--- a/core/java/android/widget/RatingBar.java
+++ b/core/java/android/widget/RatingBar.java
@@ -43,7 +43,7 @@
* <p>
* The secondary progress should not be modified by the client as it is used
* internally as the background for a fractionally filled star.
- *
+ *
* @attr ref android.R.styleable#RatingBar_numStars
* @attr ref android.R.styleable#RatingBar_rating
* @attr ref android.R.styleable#RatingBar_stepSize
@@ -58,14 +58,14 @@
* programmatically.
*/
public interface OnRatingBarChangeListener {
-
+
/**
* Notification that the rating has changed. Clients can use the
* fromUser parameter to distinguish user-initiated changes from those
* that occurred programmatically. This will not be called continuously
* while the user is dragging, only when the user finalizes a rating by
* lifting the touch.
- *
+ *
* @param ratingBar The RatingBar whose rating has changed.
* @param rating The current rating. This will be in the range
* 0..numStars.
@@ -79,9 +79,9 @@
private int mNumStars = 5;
private int mProgressOnStartTracking;
-
+
private OnRatingBarChangeListener mOnRatingBarChangeListener;
-
+
public RatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
@@ -98,19 +98,19 @@
a.recycle();
if (numStars > 0 && numStars != mNumStars) {
- setNumStars(numStars);
+ setNumStars(numStars);
}
-
+
if (stepSize >= 0) {
setStepSize(stepSize);
} else {
setStepSize(0.5f);
}
-
+
if (rating >= 0) {
setRating(rating);
}
-
+
// A touch inside a star fill up to that fractional area (slightly more
// than 1 so boundaries round up).
mTouchProgressOffset = 1.1f;
@@ -123,16 +123,16 @@
public RatingBar(Context context) {
this(context, null);
}
-
+
/**
* Sets the listener to be called when the rating changes.
- *
+ *
* @param listener The listener.
*/
public void setOnRatingBarChangeListener(OnRatingBarChangeListener listener) {
mOnRatingBarChangeListener = listener;
}
-
+
/**
* @return The listener (may be null) that is listening for rating change
* events.
@@ -144,7 +144,7 @@
/**
* Whether this rating bar should only be an indicator (thus non-changeable
* by the user).
- *
+ *
* @param isIndicator Whether it should be an indicator.
*
* @attr ref android.R.styleable#RatingBar_isIndicator
@@ -153,7 +153,7 @@
mIsUserSeekable = !isIndicator;
setFocusable(!isIndicator);
}
-
+
/**
* @return Whether this rating bar is only an indicator.
*
@@ -162,21 +162,21 @@
public boolean isIndicator() {
return !mIsUserSeekable;
}
-
+
/**
* Sets the number of stars to show. In order for these to be shown
* properly, it is recommended the layout width of this widget be wrap
* content.
- *
+ *
* @param numStars The number of stars.
*/
public void setNumStars(final int numStars) {
if (numStars <= 0) {
return;
}
-
+
mNumStars = numStars;
-
+
// This causes the width to change, so re-layout
requestLayout();
}
@@ -188,10 +188,10 @@
public int getNumStars() {
return mNumStars;
}
-
+
/**
* Sets the rating (the number of stars filled).
- *
+ *
* @param rating The rating to set.
*/
public void setRating(float rating) {
@@ -200,16 +200,16 @@
/**
* Gets the current rating (number of stars filled).
- *
+ *
* @return The current rating.
*/
public float getRating() {
- return getProgress() / getProgressPerStar();
+ return getProgress() / getProgressPerStar();
}
/**
* Sets the step size (granularity) of this rating bar.
- *
+ *
* @param stepSize The step size of this rating bar. For example, if
* half-star granularity is wanted, this would be 0.5.
*/
@@ -217,7 +217,7 @@
if (stepSize <= 0) {
return;
}
-
+
final float newMax = mNumStars / stepSize;
final int newProgress = (int) (newMax / getMax() * getProgress());
setMax((int) newMax);
@@ -226,13 +226,13 @@
/**
* Gets the step size of this rating bar.
- *
+ *
* @return The step size.
*/
public float getStepSize() {
return (float) getNumStars() / getMax();
}
-
+
/**
* @return The amount of progress that fits into a star
*/
@@ -251,12 +251,12 @@
}
@Override
- void onProgressRefresh(float scale, boolean fromUser) {
- super.onProgressRefresh(scale, fromUser);
+ void onProgressRefresh(float scale, boolean fromUser, int progress) {
+ super.onProgressRefresh(scale, fromUser, progress);
// Keep secondary progress in sync with primary
- updateSecondaryProgress(getProgress());
-
+ updateSecondaryProgress(progress);
+
if (!fromUser) {
// Callback for non-user rating changes
dispatchRatingChange(false);
@@ -267,7 +267,7 @@
* The secondary progress is used to differentiate the background of a
* partially filled star. This method keeps the secondary progress in sync
* with the progress.
- *
+ *
* @param progress The primary progress level.
*/
private void updateSecondaryProgress(int progress) {
@@ -278,11 +278,11 @@
setSecondaryProgress(secondaryProgress);
}
}
-
+
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
+
if (mSampleTile != null) {
// TODO: Once ProgressBar's TODOs are gone, this can be done more
// cleanly than mSampleTile
@@ -295,7 +295,7 @@
@Override
void onStartTrackingTouch() {
mProgressOnStartTracking = getProgress();
-
+
super.onStartTrackingTouch();
}
@@ -327,7 +327,7 @@
if (max <= 0) {
return;
}
-
+
super.setMax(max);
}
diff --git a/core/java/android/widget/SeekBar.java b/core/java/android/widget/SeekBar.java
index e97bdf25..fc070e7 100644
--- a/core/java/android/widget/SeekBar.java
+++ b/core/java/android/widget/SeekBar.java
@@ -26,7 +26,7 @@
/**
* A SeekBar is an extension of ProgressBar that adds a draggable thumb. The user can touch
* the thumb and drag left or right to set the current progress level or use the arrow keys.
- * Placing focusable widgets to the left or right of a SeekBar is discouraged.
+ * Placing focusable widgets to the left or right of a SeekBar is discouraged.
* <p>
* Clients of the SeekBar can attach a {@link SeekBar.OnSeekBarChangeListener} to
* be notified of the user's actions.
@@ -42,39 +42,39 @@
* programmatically.
*/
public interface OnSeekBarChangeListener {
-
+
/**
* Notification that the progress level has changed. Clients can use the fromUser parameter
* to distinguish user-initiated changes from those that occurred programmatically.
- *
+ *
* @param seekBar The SeekBar whose progress has changed
* @param progress The current progress level. This will be in the range 0..max where max
* was set by {@link ProgressBar#setMax(int)}. (The default value for max is 100.)
* @param fromUser True if the progress change was initiated by the user.
*/
void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser);
-
+
/**
* Notification that the user has started a touch gesture. Clients may want to use this
- * to disable advancing the seekbar.
+ * to disable advancing the seekbar.
* @param seekBar The SeekBar in which the touch gesture began
*/
void onStartTrackingTouch(SeekBar seekBar);
-
+
/**
* Notification that the user has finished a touch gesture. Clients may want to use this
- * to re-enable advancing the seekbar.
+ * to re-enable advancing the seekbar.
* @param seekBar The SeekBar in which the touch gesture began
*/
void onStopTrackingTouch(SeekBar seekBar);
}
private OnSeekBarChangeListener mOnSeekBarChangeListener;
-
+
public SeekBar(Context context) {
this(context, null);
}
-
+
public SeekBar(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.seekBarStyle);
}
@@ -88,26 +88,26 @@
}
@Override
- void onProgressRefresh(float scale, boolean fromUser) {
- super.onProgressRefresh(scale, fromUser);
+ void onProgressRefresh(float scale, boolean fromUser, int progress) {
+ super.onProgressRefresh(scale, fromUser, progress);
if (mOnSeekBarChangeListener != null) {
- mOnSeekBarChangeListener.onProgressChanged(this, getProgress(), fromUser);
+ mOnSeekBarChangeListener.onProgressChanged(this, progress, fromUser);
}
}
/**
* Sets a listener to receive notifications of changes to the SeekBar's progress level. Also
* provides notifications of when the user starts and stops a touch gesture within the SeekBar.
- *
+ *
* @param l The seek bar notification listener
- *
+ *
* @see SeekBar.OnSeekBarChangeListener
*/
public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) {
mOnSeekBarChangeListener = l;
}
-
+
@Override
void onStartTrackingTouch() {
super.onStartTrackingTouch();
@@ -115,7 +115,7 @@
mOnSeekBarChangeListener.onStartTrackingTouch(this);
}
}
-
+
@Override
void onStopTrackingTouch() {
super.onStopTrackingTouch();
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 8107985..2477d94 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -355,7 +355,7 @@
Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
}
if (id != 0) {
- if (mResources.getColorStateList(id) == null) {
+ if (mResources.getColorStateList(id, null) == null) {
throw new IllegalArgumentException(
"Unable to find preloaded color resource #0x"
+ Integer.toHexString(id)
diff --git a/core/java/com/android/internal/widget/ButtonBarLayout.java b/core/java/com/android/internal/widget/ButtonBarLayout.java
new file mode 100644
index 0000000..64e6c69
--- /dev/null
+++ b/core/java/com/android/internal/widget/ButtonBarLayout.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.internal.R;
+
+/**
+ * An extension of LinearLayout that automatically switches to vertical
+ * orientation when it can't fit its child views horizontally.
+ */
+public class ButtonBarLayout extends LinearLayout {
+ /** Spacer used in horizontal orientation. */
+ private final View mSpacer;
+
+ /** Whether the current configuration allows stacking. */
+ private final boolean mAllowStacked;
+
+ /** Whether the layout is currently stacked. */
+ private boolean mStacked;
+
+ public ButtonBarLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ mAllowStacked = context.getResources().getBoolean(R.bool.allow_stacked_button_bar);
+ mSpacer = findViewById(R.id.spacer);
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+
+ // Maybe we can fit the content now?
+ if (w > oldw && mStacked) {
+ setStacked(false);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ if (mAllowStacked && getOrientation() == LinearLayout.HORIZONTAL) {
+ final int measuredWidth = getMeasuredWidthAndState();
+ final int measuredWidthState = measuredWidth & MEASURED_STATE_MASK;
+ if (measuredWidthState == MEASURED_STATE_TOO_SMALL) {
+ setStacked(true);
+
+ // Measure again in the new orientation.
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+ }
+
+ private void setStacked(boolean stacked) {
+ setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
+ setGravity(stacked ? Gravity.RIGHT : Gravity.BOTTOM);
+
+ if (mSpacer != null) {
+ mSpacer.setVisibility(stacked ? View.GONE : View.INVISIBLE);
+ }
+
+ // Reverse the child order. This is specific to the Material button
+ // bar's layout XML and will probably not generalize.
+ final int childCount = getChildCount();
+ for (int i = childCount - 2; i >= 0; i--) {
+ bringChildToFront(getChildAt(i));
+ }
+
+ mStacked = stacked;
+ }
+}
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index d1b1a1a..0b737a7 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "SensorManager"
+#include <map>
+
#include <utils/Log.h>
#include <utils/Looper.h>
@@ -44,7 +46,6 @@
jfieldID vendor;
jfieldID version;
jfieldID handle;
- jfieldID type;
jfieldID range;
jfieldID resolution;
jfieldID power;
@@ -55,6 +56,7 @@
jfieldID requiredPermission;
jfieldID maxDelay;
jfieldID flags;
+ jmethodID setType;
} gSensorOffsets;
@@ -71,7 +73,6 @@
sensorOffsets.vendor = _env->GetFieldID(sensorClass, "mVendor", "Ljava/lang/String;");
sensorOffsets.version = _env->GetFieldID(sensorClass, "mVersion", "I");
sensorOffsets.handle = _env->GetFieldID(sensorClass, "mHandle", "I");
- sensorOffsets.type = _env->GetFieldID(sensorClass, "mType", "I");
sensorOffsets.range = _env->GetFieldID(sensorClass, "mMaxRange", "F");
sensorOffsets.resolution = _env->GetFieldID(sensorClass, "mResolution","F");
sensorOffsets.power = _env->GetFieldID(sensorClass, "mPower", "F");
@@ -84,6 +85,47 @@
"Ljava/lang/String;");
sensorOffsets.maxDelay = _env->GetFieldID(sensorClass, "mMaxDelay", "I");
sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags", "I");
+ sensorOffsets.setType = _env->GetMethodID(sensorClass, "setType", "(I)Z");
+}
+
+/**
+ * A key comparator predicate.
+ * It is used to intern strings associated with Sensor data.
+ * It defines a 'Strict weak ordering' for the interned strings.
+ */
+class InternedStringCompare {
+public:
+ bool operator()(const String8* string1, const String8* string2) const {
+ if (string1 == NULL) {
+ return string2 != NULL;
+ }
+ return string1->compare(*string2) < 0;
+ }
+};
+
+/**
+ * A localized interning mechanism for Sensor strings.
+ * We implement our own interning to avoid the overhead of using java.lang.String#intern().
+ * It is common that Vendor, StringType, and RequirePermission data is common between many of the
+ * Sensors, by interning the memory usage to represent Sensors is optimized.
+ */
+static jstring
+getInternedString(JNIEnv *env, const String8* string) {
+ static std::map<const String8*, jstring, InternedStringCompare> internedStrings;
+
+ jstring internedString;
+ std::map<const String8*, jstring>::iterator iterator = internedStrings.find(string);
+ if (iterator != internedStrings.end()) {
+ internedString = iterator->second;
+ } else {
+ jstring localString = env->NewStringUTF(string->string());
+ // we are implementing our own interning so expect these strings to be backed by global refs
+ internedString = (jstring) env->NewGlobalRef(localString);
+ internedStrings.insert(std::make_pair(string, internedString));
+ env->DeleteLocalRef(localString);
+ }
+
+ return internedString;
}
static jint
@@ -93,20 +135,19 @@
Sensor const* const* sensorList;
size_t count = mgr.getSensorList(&sensorList);
- if (size_t(next) >= count)
+ if (size_t(next) >= count) {
return -1;
+ }
Sensor const* const list = sensorList[next];
const SensorOffsets& sensorOffsets(gSensorOffsets);
- jstring name = env->NewStringUTF(list->getName().string());
- jstring vendor = env->NewStringUTF(list->getVendor().string());
- jstring stringType = env->NewStringUTF(list->getStringType().string());
- jstring requiredPermission = env->NewStringUTF(list->getRequiredPermission().string());
+ jstring name = getInternedString(env, &list->getName());
+ jstring vendor = getInternedString(env, &list->getVendor());
+ jstring requiredPermission = getInternedString(env, &list->getRequiredPermission());
env->SetObjectField(sensor, sensorOffsets.name, name);
env->SetObjectField(sensor, sensorOffsets.vendor, vendor);
env->SetIntField(sensor, sensorOffsets.version, list->getVersion());
env->SetIntField(sensor, sensorOffsets.handle, list->getHandle());
- env->SetIntField(sensor, sensorOffsets.type, list->getType());
env->SetFloatField(sensor, sensorOffsets.range, list->getMaxValue());
env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution());
env->SetFloatField(sensor, sensorOffsets.power, list->getPowerUsage());
@@ -115,11 +156,14 @@
list->getFifoReservedEventCount());
env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
list->getFifoMaxEventCount());
- env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
env->SetObjectField(sensor, sensorOffsets.requiredPermission,
requiredPermission);
env->SetIntField(sensor, sensorOffsets.maxDelay, list->getMaxDelay());
env->SetIntField(sensor, sensorOffsets.flags, list->getFlags());
+ if (env->CallBooleanMethod(sensor, sensorOffsets.setType, list->getType()) == JNI_FALSE) {
+ jstring stringType = getInternedString(env, &list->getStringType());
+ env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
+ }
next++;
return size_t(next) < count ? next : 0;
}
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index aabf320..7497d8b 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -598,15 +598,10 @@
ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
return BAD_VALUE;
}
- status_t err = native_window_set_buffers_dimensions(anw.get(), width, height);
- if (err != NO_ERROR) {
- ALOGE("%s: Error while setting surface dimens %s (%d).", __FUNCTION__, strerror(-err), err);
- return err;
- }
- // WAR - Set user dimensions also to avoid incorrect scaling after TextureView orientation
- // change.
- err = native_window_set_buffers_user_dimensions(anw.get(), width, height);
+ // Set user dimensions only
+ // The producer dimensions are owned by GL
+ status_t err = native_window_set_buffers_user_dimensions(anw.get(), width, height);
if (err != NO_ERROR) {
ALOGE("%s: Error while setting surface user dimens %s (%d).", __FUNCTION__, strerror(-err),
err);
@@ -750,4 +745,3 @@
gCameraDeviceMethods,
NELEM(gCameraDeviceMethods));
}
-
diff --git a/core/res/res/layout/alert_dialog_button_bar_material.xml b/core/res/res/layout/alert_dialog_button_bar_material.xml
new file mode 100644
index 0000000..891bcd5
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_button_bar_material.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+
+<com.android.internal.widget.ButtonBarLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/buttonPanel"
+ style="?attr/buttonBarStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layoutDirection="locale"
+ android:orientation="horizontal"
+ android:paddingStart="12dp"
+ android:paddingEnd="12dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:gravity="bottom">
+
+ <Button
+ android:id="@+id/button3"
+ style="?attr/buttonBarNeutralButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Space
+ android:id="@+id/spacer"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:visibility="invisible" />
+
+ <Button
+ android:id="@+id/button2"
+ style="?attr/buttonBarNegativeButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button
+ android:id="@+id/button1"
+ style="?attr/buttonBarPositiveButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+</com.android.internal.widget.ButtonBarLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml
index 29bfaa7..c8735b1 100644
--- a/core/res/res/layout/alert_dialog_material.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -101,33 +101,5 @@
android:layout_height="wrap_content" />
</FrameLayout>
- <LinearLayout android:id="@+id/buttonPanel"
- style="?attr/buttonBarStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layoutDirection="locale"
- android:orientation="horizontal"
- android:paddingStart="12dp"
- android:paddingEnd="12dp"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:gravity="bottom">
- <Button android:id="@+id/button3"
- style="?attr/buttonBarNeutralButtonStyle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:visibility="invisible" />
- <Button android:id="@+id/button2"
- style="?attr/buttonBarNegativeButtonStyle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <Button android:id="@+id/button1"
- style="?attr/buttonBarPositiveButtonStyle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- </LinearLayout>
+ <include layout="@layout/alert_dialog_button_bar_material" />
</LinearLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 7c4c2d0..13487d8 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wil Verken-met-raak aktiveer. Wanneer Verken-met-raak aangeskakel is, kan jy beskrywings van wat onder jou vinger is hoor of sien, of jy kan gebare uitvoer om interaksie met die foon te hê ."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 maand gelede"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Voor 1 maand gelede"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 sekonde gelede"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sekondes gelede"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minuut gelede"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minute gelede"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 uur gelede"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> uur gelede"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Verlede maand"</string>
<string name="older" msgid="5211975022815554840">"Ouer"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"gister"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dae gelede"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"oor 1 sekonde"</item>
- <item quantity="other" msgid="1241926116443974687">"oor <xliff:g id="COUNT">%d</xliff:g> sekondes"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"oor 1 minuut"</item>
- <item quantity="other" msgid="3330713936399448749">"oor <xliff:g id="COUNT">%d</xliff:g> minute"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"oor 1 uur"</item>
- <item quantity="other" msgid="547290677353727389">"oor <xliff:g id="COUNT">%d</xliff:g> uur"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"môre"</item>
- <item quantity="other" msgid="5109449375100953247">"oor <xliff:g id="COUNT">%d</xliff:g> dae"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 sek. gelede"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sek. gelede"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 min. gelede"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min. gelede"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 uur gelede"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> uur gelede"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"gister"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dae gelede"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"oor 1 sek."</item>
- <item quantity="other" msgid="5495880108825805108">"oor <xliff:g id="COUNT">%d</xliff:g> sek."</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"oor 1 min."</item>
- <item quantity="other" msgid="4216113292706568726">"oor <xliff:g id="COUNT">%d</xliff:g> minute"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"oor 1 uur"</item>
- <item quantity="other" msgid="3705373766798013406">"oor <xliff:g id="COUNT">%d</xliff:g> uur"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"môre"</item>
- <item quantity="other" msgid="2973062968038355991">"oor <xliff:g id="COUNT">%d</xliff:g> dae"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"op <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"by <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"in <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index a946741..c7b5b53 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከስልኩ ጋር ለመግባባት ምን በጣትዎ ስር ወይም ምልክቶችን ማከናወን እንዳለብዎ ማብራሪያ ሊመለከቱ ወይም ሊሰሙ ይችላሉ።"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"ከ1 ወር በፊት"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ከ1 ወር በፊት"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"ከ1 ሴኮንድ በፊት"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ሰኮንዶች በፊት"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"ከ 1 ደቂቃ በፊት"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች በፊት"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"ከ1 ሰዓት በፊት"</item>
- <item quantity="other" msgid="2467273239587587569">"ከ <xliff:g id="COUNT">%d</xliff:g> ሰዓት በፊት"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">" ያለፈው ወር"</string>
<string name="older" msgid="5211975022815554840">"የድሮ"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ትላንትና"</item>
- <item quantity="other" msgid="2479586466153314633">"ከ <xliff:g id="COUNT">%d</xliff:g>ቀን በፊት"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"በ1 ሴኮንድ"</item>
- <item quantity="other" msgid="1241926116443974687">"በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"በ1 ደቂቃ ውስጥ"</item>
- <item quantity="other" msgid="3330713936399448749">"በ<xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች ውስጥ"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"በ 1 ሰዓት"</item>
- <item quantity="other" msgid="547290677353727389">"በ <xliff:g id="COUNT">%d</xliff:g> ሰዓቶች"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"ነገ"</item>
- <item quantity="other" msgid="5109449375100953247">"በ<xliff:g id="COUNT">%d</xliff:g> ቀኖች"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 ሴኮንድ በፊት"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች በፊት"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"ከ 1 ደቂቃ በፊት"</item>
- <item quantity="other" msgid="851164968597150710">"ከ <xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች በፊት"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"ከ1 ሰዓት በፊት"</item>
- <item quantity="other" msgid="6889970745748538901">"ከ <xliff:g id="COUNT">%d</xliff:g> ሰዓት በፊት"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ትላንትና"</item>
- <item quantity="other" msgid="3453342639616481191">"ከ <xliff:g id="COUNT">%d</xliff:g>ቀን በፊት"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"በ1 ሴኮንድ"</item>
- <item quantity="other" msgid="5495880108825805108">"በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"በ1 ደቂቃ ውስጥ"</item>
- <item quantity="other" msgid="4216113292706568726">"በ<xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች ውስጥ"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"በ 1 ሰዓት"</item>
- <item quantity="other" msgid="3705373766798013406">"በ <xliff:g id="COUNT">%d</xliff:g> ሰዓቶች"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"ነገ"</item>
- <item quantity="other" msgid="2973062968038355991">"በ<xliff:g id="COUNT">%d</xliff:g> ቀኖች"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"በ <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"በ <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"ውስጥ <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 860b8a0..2beadc6 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"يريد <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> تمكين ميزة Explore by Touch. عند تشغيل ميزة Explore by Touch، سيكون بإمكانك سماع أو مشاهدة أوصاف لما تحت إصبعك أو إجراء إيماءات للتفاعل مع الهاتف."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"قبل شهر واحد"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"قبل شهر واحد"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"قبل ثانية واحدة"</item>
- <item quantity="other" msgid="3903706804349556379">"قبل <xliff:g id="COUNT">%d</xliff:g> ثانية"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"قبل دقيقة واحدة"</item>
- <item quantity="other" msgid="2176942008915455116">"قبل <xliff:g id="COUNT">%d</xliff:g> دقيقة"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"قبل ساعة واحدة"</item>
- <item quantity="other" msgid="2467273239587587569">"قبل <xliff:g id="COUNT">%d</xliff:g> ساعات"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"الشهر الماضي"</string>
<string name="older" msgid="5211975022815554840">"أقدم"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"أمس"</item>
- <item quantity="other" msgid="2479586466153314633">"قبل <xliff:g id="COUNT">%d</xliff:g> يوم"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"في ثانية واحدة"</item>
- <item quantity="other" msgid="1241926116443974687">"في <xliff:g id="COUNT">%d</xliff:g> ثانية"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"في دقيقة واحدة"</item>
- <item quantity="other" msgid="3330713936399448749">"في <xliff:g id="COUNT">%d</xliff:g> دقيقة"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"في ساعة واحدة"</item>
- <item quantity="other" msgid="547290677353727389">"في <xliff:g id="COUNT">%d</xliff:g> ساعة"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"غدًا"</item>
- <item quantity="other" msgid="5109449375100953247">"في <xliff:g id="COUNT">%d</xliff:g> يوم"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"قبل ثانية واحدة"</item>
- <item quantity="other" msgid="3699169366650930415">"قبل <xliff:g id="COUNT">%d</xliff:g> ثانية"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"قبل دقيقة واحدة"</item>
- <item quantity="other" msgid="851164968597150710">"قبل <xliff:g id="COUNT">%d</xliff:g> دقيقة"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"قبل ساعة واحدة"</item>
- <item quantity="other" msgid="6889970745748538901">"قبل <xliff:g id="COUNT">%d</xliff:g> ساعة"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"أمس"</item>
- <item quantity="other" msgid="3453342639616481191">"قبل <xliff:g id="COUNT">%d</xliff:g> يوم"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"في ثانية واحدة"</item>
- <item quantity="other" msgid="5495880108825805108">"في <xliff:g id="COUNT">%d</xliff:g> ثانية"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"في دقيقة واحدة"</item>
- <item quantity="other" msgid="4216113292706568726">"في <xliff:g id="COUNT">%d</xliff:g> دقيقة"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"في ساعة واحدة"</item>
- <item quantity="other" msgid="3705373766798013406">"في <xliff:g id="COUNT">%d</xliff:g> ساعة"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"غدًا"</item>
- <item quantity="other" msgid="2973062968038355991">"في <xliff:g id="COUNT">%d</xliff:g> يوم"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"في <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"في الساعة <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"في <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 479cfcf..b22eb7a 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -967,75 +967,11 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> Toxunaraq Kəşf Et rejimini aktivləşdirmək istəyir. Toxunaraq Kəşf Et açıldığı zaman, barmağınızın altında nə olduğu haqda olan təsvirləri eşidə və ya görə bilərsiniz və ya telefonda insanlarla əlaqəyə keçmək üçün jestlər həyata keçirə bilərsiniz"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ay öncə"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 ay əvvəl"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 saniyə əvvəl"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> saniyə əvvəl"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 dəqiqə əvvəl"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> dəqiqə əvvəl"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 saat əvvəl"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> saat əvvəl"</item>
- </plurals>
<plurals name="last_num_days">
<item quantity="other" msgid="3069992808164318268">"Son <xliff:g id="COUNT">%d</xliff:g> gün"</item>
</plurals>
<string name="last_month" msgid="3959346739979055432">"Keçən ay"</string>
<string name="older" msgid="5211975022815554840">"Köhnə"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"dünən"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> gün əvvəl"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 saniyə ərzində"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> saniyə içində"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 dəqiqə içində"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> dəqiqə ərzində"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 saata"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> saata"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"sabah"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> gün ərzində"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 saniyə əvvəl"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> san əvvəl"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 dəqiqə əvvəl"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> dəqiqə əvvəl"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 saat əvvəl"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> saat əvvəl"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"dünən"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> gün əvvəl"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 san ərzində"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> san ərzində"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 dəq ərzində"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> dəqiqəyə"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 saat ərzində"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> saata"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"sabah"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> günə"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> tarixində"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"saat <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> ilində"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 9f572cf..1c43360 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> иска да активира изследването чрез докосване. Когато услугата е включена, можете да чувате или да виждате описания на това, което е под пръста ви, или да изпълнявате жестове, за да взаимодействате с телефона."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Преди 1 месец"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Преди повече от месец"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Преди 1 секунда"</item>
- <item quantity="other" msgid="3903706804349556379">"Преди <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Преди 1 минута"</item>
- <item quantity="other" msgid="2176942008915455116">"Преди <xliff:g id="COUNT">%d</xliff:g> минути"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Преди 1 час"</item>
- <item quantity="other" msgid="2467273239587587569">"Преди <xliff:g id="COUNT">%d</xliff:g> часа"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Последният месец"</string>
<string name="older" msgid="5211975022815554840">"По-стари"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"вчера"</item>
- <item quantity="other" msgid="2479586466153314633">"Преди <xliff:g id="COUNT">%d</xliff:g> дни"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"след 1 секунда"</item>
- <item quantity="other" msgid="1241926116443974687">"след <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"след 1 минута"</item>
- <item quantity="other" msgid="3330713936399448749">"след <xliff:g id="COUNT">%d</xliff:g> минути"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"след 1 час"</item>
- <item quantity="other" msgid="547290677353727389">"след <xliff:g id="COUNT">%d</xliff:g> часа"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"утре"</item>
- <item quantity="other" msgid="5109449375100953247">"след <xliff:g id="COUNT">%d</xliff:g> дни"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"Преди 1 сек"</item>
- <item quantity="other" msgid="3699169366650930415">"Преди <xliff:g id="COUNT">%d</xliff:g> сек"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"Преди 1 мин"</item>
- <item quantity="other" msgid="851164968597150710">"Преди <xliff:g id="COUNT">%d</xliff:g> мин"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Преди 1 час"</item>
- <item quantity="other" msgid="6889970745748538901">"Преди <xliff:g id="COUNT">%d</xliff:g> часа"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"вчера"</item>
- <item quantity="other" msgid="3453342639616481191">"Преди <xliff:g id="COUNT">%d</xliff:g> дни"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"след 1 сек"</item>
- <item quantity="other" msgid="5495880108825805108">"след <xliff:g id="COUNT">%d</xliff:g> сек"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"след 1 мин"</item>
- <item quantity="other" msgid="4216113292706568726">"след <xliff:g id="COUNT">%d</xliff:g> мин"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"след 1 час"</item>
- <item quantity="other" msgid="3705373766798013406">"след <xliff:g id="COUNT">%d</xliff:g> часа"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"утре"</item>
- <item quantity="other" msgid="2973062968038355991">"след <xliff:g id="COUNT">%d</xliff:g> дни"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"на <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"в <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"през <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 9f79384..1d389f3 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> \'স্পর্শের মাধ্যমে অন্বেষণ করুন\' সক্ষম করতে চাইছে৷ যখন \'স্পর্শের মাধ্যমে অন্বেষণ করুন\' চালু করা হবে তখন আপনার আঙ্গুলের নিয়ন্ত্রণে থাকা জিনিসের বর্ণনাগুলি শুনতে অথবা দেখতে পাবেন অথবা ফোনের সাথে ইন্টারঅ্যাক্ট করার জন্য অঙ্গভঙ্গির সাহায্য নিতে পারবেন৷"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"১ মাস আগে"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"১ মাস আগে"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"১ সেকেন্ড আগে"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> সেকেন্ড আগে"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"১ মিনিট আগে"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> মিনিট আগে"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"১ ঘন্টা আগে"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ঘন্টা আগে"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"গত মাস"</string>
<string name="older" msgid="5211975022815554840">"পুরোনো"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"গতকাল"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> দিন আগে"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"১ সেকেন্ডের মধ্যে"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> সেকেন্ডের মধ্যে"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"১ মিনিটের মধ্যে"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> মিনিটের মধ্যে"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"১ ঘন্টার মধ্যে"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> ঘন্টার মধ্যে"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"আগামীকাল"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> দিনের মধ্যে"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"১ সেকেন্ড আগে"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> সেকেন্ড আগে"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"১ মিনিট আগে"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> মিনিট আগে"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"১ ঘন্টা আগে"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ঘন্টা আগে"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"গতকাল"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> দিন আগে"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"১ সেকেন্ডের মধ্যে"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> সেকেন্ডের মধ্যে"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"১ মিনিটের মধ্যে"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> মিনিটের মধ্যে"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"১ ঘন্টার মধ্যে"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> ঘন্টার মধ্যে"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"আগামীকাল"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> দিনের মধ্যে"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> এ"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> এ"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> এ"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 3f68244..b60187a 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vol activar l\'exploració tàctil. Quan l\'exploració per tàctil està activada, pots escoltar o veure les descripcions del contingut seleccionat o utilitzar gestos per interactuar amb el telèfon."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Fa 1 mes"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Fa més d\'1 mes"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Fa 1 segon"</item>
- <item quantity="other" msgid="3903706804349556379">"Fa <xliff:g id="COUNT">%d</xliff:g> segons"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Fa 1 minut"</item>
- <item quantity="other" msgid="2176942008915455116">"Fa <xliff:g id="COUNT">%d</xliff:g> minuts"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Fa 1 hora"</item>
- <item quantity="other" msgid="2467273239587587569">"Fa <xliff:g id="COUNT">%d</xliff:g> hores"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"El mes passat"</string>
<string name="older" msgid="5211975022815554840">"Més antigues"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"Ahir"</item>
- <item quantity="other" msgid="2479586466153314633">"Fa <xliff:g id="COUNT">%d</xliff:g> dies"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"d\'aquí a 1 segon"</item>
- <item quantity="other" msgid="1241926116443974687">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> segons"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"d\'aquí a 1 minut"</item>
- <item quantity="other" msgid="3330713936399448749">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> minuts"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"d\'aquí a 1 hora"</item>
- <item quantity="other" msgid="547290677353727389">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> hores"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"demà"</item>
- <item quantity="other" msgid="5109449375100953247">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> dies"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"Fa 1 s"</item>
- <item quantity="other" msgid="3699169366650930415">"Fa <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"fa 1 min"</item>
- <item quantity="other" msgid="851164968597150710">"Fa <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Fa 1 hora"</item>
- <item quantity="other" msgid="6889970745748538901">"Fa <xliff:g id="COUNT">%d</xliff:g> hores"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ahir"</item>
- <item quantity="other" msgid="3453342639616481191">"Fa <xliff:g id="COUNT">%d</xliff:g> dies"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"d\'aquí a 1 s"</item>
- <item quantity="other" msgid="5495880108825805108">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"d\'aquí a 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> minuts"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"d\'aquí a 1 hora"</item>
- <item quantity="other" msgid="3705373766798013406">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> hores"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"demà"</item>
- <item quantity="other" msgid="2973062968038355991">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> dies"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"el <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"a les <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"el <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 00913d26..7e02459 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim Letadlo je ZAPNUTÝ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim Letadlo je VYPNUTÝ"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Nastavení"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Hlas. asistence"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Zamknout"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
@@ -1132,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Služba <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> požaduje povolení funkce Prozkoumání dotykem. Pokud je funkce Prozkoumání dotykem zapnuta, můžete slyšet nebo vidět popisy objektů pod vaším prstem nebo ovládat telefon gesty."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"před 1 měsícem"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Déle než před 1 měsícem"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"před 1 sekundou"</item>
- <item quantity="other" msgid="3903706804349556379">"před <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"před 1 min"</item>
- <item quantity="other" msgid="2176942008915455116">"před <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"před 1 h"</item>
- <item quantity="other" msgid="2467273239587587569">"před <xliff:g id="COUNT">%d</xliff:g> h"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Poslední měsíc"</string>
<string name="older" msgid="5211975022815554840">"Starší"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"včera"</item>
- <item quantity="other" msgid="2479586466153314633">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"za 1 sekundu"</item>
- <item quantity="other" msgid="1241926116443974687">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"za 1 minutu"</item>
- <item quantity="other" msgid="3330713936399448749">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"za 1 hodinu"</item>
- <item quantity="other" msgid="547290677353727389">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"zítra"</item>
- <item quantity="other" msgid="5109449375100953247">"za <xliff:g id="COUNT">%d</xliff:g> dny"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"před 1 s"</item>
- <item quantity="other" msgid="3699169366650930415">"před <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"před 1 min"</item>
- <item quantity="other" msgid="851164968597150710">"před <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"před 1 h"</item>
- <item quantity="other" msgid="6889970745748538901">"před <xliff:g id="COUNT">%d</xliff:g> h"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"včera"</item>
- <item quantity="other" msgid="3453342639616481191">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"za 1 s"</item>
- <item quantity="other" msgid="5495880108825805108">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"za 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"za 1 hodinu"</item>
- <item quantity="other" msgid="3705373766798013406">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"zítra"</item>
- <item quantity="other" msgid="2973062968038355991">"za <xliff:g id="COUNT">%d</xliff:g> dny"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"dne <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"v <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"roku <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 157d282..1b71828 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ønsker at aktivere Udforsk ved berøring. Når Udforsk ved berøring er aktiveret, kan du høre eller se beskrivelser af, hvad der er under din finger, eller udføre bevægelser for at interagere med telefonen."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"for 1 måned siden"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Før for 1 måned siden"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"for 1 sekund siden"</item>
- <item quantity="other" msgid="3903706804349556379">"for <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"for 1 minut siden"</item>
- <item quantity="other" msgid="2176942008915455116">"for <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"for 1 time siden"</item>
- <item quantity="other" msgid="2467273239587587569">"for <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Seneste måned"</string>
<string name="older" msgid="5211975022815554840">"Ældre"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"i går"</item>
- <item quantity="other" msgid="2479586466153314633">"for <xliff:g id="COUNT">%d</xliff:g> dage siden"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"om 1 sekund"</item>
- <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"om 1 minut"</item>
- <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"om 1 time"</item>
- <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"i morgen"</item>
- <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dage"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"for 1 sek. siden"</item>
- <item quantity="other" msgid="3699169366650930415">"for <xliff:g id="COUNT">%d</xliff:g> sek. siden"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"for 1 min. siden"</item>
- <item quantity="other" msgid="851164968597150710">"for <xliff:g id="COUNT">%d</xliff:g> min. siden"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"for 1 time siden"</item>
- <item quantity="other" msgid="6889970745748538901">"for <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"i går"</item>
- <item quantity="other" msgid="3453342639616481191">"for <xliff:g id="COUNT">%d</xliff:g> dage siden"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"om 1 sek."</item>
- <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"om 1 min."</item>
- <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> min."</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"om 1 time"</item>
- <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"i morgen"</item>
- <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> dage"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"den <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"kl. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"i <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 5605ccc..3670b67 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen & Entdecken\". Wenn \"Tippen & Entdecken\" aktiviert ist, können Sie Beschreibungen dessen hören oder sehen, was sich unter ihren Fingern befindet, oder Gesten ausführen, um mit dem Telefon zu kommunizieren."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Vor 1 Monat"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vor mehr als 1 Monat"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"vor 1 Sekunde"</item>
- <item quantity="other" msgid="3903706804349556379">"vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"vor 1 Minute"</item>
- <item quantity="other" msgid="2176942008915455116">"vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"vor 1 Stunde"</item>
- <item quantity="other" msgid="2467273239587587569">"vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Letzter Monat"</string>
<string name="older" msgid="5211975022815554840">"Älter"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"gestern"</item>
- <item quantity="other" msgid="2479586466153314633">"vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"in 1 Sekunde"</item>
- <item quantity="other" msgid="1241926116443974687">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"in 1 Minute"</item>
- <item quantity="other" msgid="3330713936399448749">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"in 1 Stunde"</item>
- <item quantity="other" msgid="547290677353727389">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"morgen"</item>
- <item quantity="other" msgid="5109449375100953247">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"vor 1 Sekunde"</item>
- <item quantity="other" msgid="3699169366650930415">"vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"vor 1 Minute"</item>
- <item quantity="other" msgid="851164968597150710">"vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"vor 1 Stunde"</item>
- <item quantity="other" msgid="6889970745748538901">"vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"gestern"</item>
- <item quantity="other" msgid="3453342639616481191">"vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"in 1 Sekunde"</item>
- <item quantity="other" msgid="5495880108825805108">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"in 1 Minute"</item>
- <item quantity="other" msgid="4216113292706568726">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"in 1 Stunde"</item>
- <item quantity="other" msgid="3705373766798013406">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"morgen"</item>
- <item quantity="other" msgid="2973062968038355991">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"am <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"um <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"im Jahr <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 9229bc6..da33214 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Η υπηρεσία <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> απαιτεί ενεργοποίηση της Εξερεύνησης μέσω αφής. Όταν είναι ενεργοποιημένη η Εξερεύνηση μέσω αφής, μπορείτε να δείτε ή να ακούσετε περιγραφές για τις επιλογές που βρίσκονται κάτω από το δάχτυλό σας ή να κάνετε κινήσεις αλληλεπίδρασης με το τηλέφωνό σας."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"πριν από 1 μήνα"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Παλαιότερα από 1 μήνα"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"πριν από 1 δευτερόλεπτο"</item>
- <item quantity="other" msgid="3903706804349556379">"πριν από <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"πριν από 1 λεπτό"</item>
- <item quantity="other" msgid="2176942008915455116">"πριν από <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"πριν από 1 ώρα"</item>
- <item quantity="other" msgid="2467273239587587569">"πριν από <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Τελευταίος μήνας"</string>
<string name="older" msgid="5211975022815554840">"Παλαιότερα"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"χθες"</item>
- <item quantity="other" msgid="2479586466153314633">"πριν από <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"σε 1 δευτερόλεπτο"</item>
- <item quantity="other" msgid="1241926116443974687">"σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"σε 1 λεπτό"</item>
- <item quantity="other" msgid="3330713936399448749">"σε <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"σε 1 ώρα"</item>
- <item quantity="other" msgid="547290677353727389">"σε <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"αύριο"</item>
- <item quantity="other" msgid="5109449375100953247">"σε <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"πριν από 1 δευτερόλεπτο"</item>
- <item quantity="other" msgid="3699169366650930415">"πριν από <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"πριν από 1 λεπτό"</item>
- <item quantity="other" msgid="851164968597150710">"πριν από <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"πριν από 1 ώρα"</item>
- <item quantity="other" msgid="6889970745748538901">"πριν από <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"χθες"</item>
- <item quantity="other" msgid="3453342639616481191">"πριν από <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"σε 1 δευτερόλεπτο"</item>
- <item quantity="other" msgid="5495880108825805108">"σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"σε 1 λεπτό"</item>
- <item quantity="other" msgid="4216113292706568726">"σε <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"σε 1 ώρα"</item>
- <item quantity="other" msgid="3705373766798013406">"σε <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"αύριο"</item>
- <item quantity="other" msgid="2973062968038355991">"σε <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"στις <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"στις <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"το <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index f7f62e9..d4d038c 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wants to enable Explore by Touch. When Explore by Touch is turned on, you can hear or see descriptions of what\'s under your finger or perform gestures to interact with the phone."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 month ago"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Before 1 month ago"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 second ago"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> seconds ago"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minute ago"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minutes ago"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 hour ago"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> hours ago"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Last month"</string>
<string name="older" msgid="5211975022815554840">"Older"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"yesterday"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> days ago"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"in 1 second"</item>
- <item quantity="other" msgid="1241926116443974687">"in <xliff:g id="COUNT">%d</xliff:g> seconds"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"in 1 minute"</item>
- <item quantity="other" msgid="3330713936399448749">"in <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"in 1 hour"</item>
- <item quantity="other" msgid="547290677353727389">"in <xliff:g id="COUNT">%d</xliff:g> hours"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"tomorrow"</item>
- <item quantity="other" msgid="5109449375100953247">"in <xliff:g id="COUNT">%d</xliff:g> days"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 sec ago"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> secs ago"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 min ago"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> mins ago"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 hour ago"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> hours ago"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"yesterday"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> days ago"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"in 1 sec"</item>
- <item quantity="other" msgid="5495880108825805108">"in <xliff:g id="COUNT">%d</xliff:g> secs"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"in 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"in <xliff:g id="COUNT">%d</xliff:g> mins"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"in 1 hour"</item>
- <item quantity="other" msgid="3705373766798013406">"in <xliff:g id="COUNT">%d</xliff:g> hours"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"tomorrow"</item>
- <item quantity="other" msgid="2973062968038355991">"in <xliff:g id="COUNT">%d</xliff:g> days"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"on <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"at <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"in<xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index f7f62e9..d4d038c 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wants to enable Explore by Touch. When Explore by Touch is turned on, you can hear or see descriptions of what\'s under your finger or perform gestures to interact with the phone."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 month ago"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Before 1 month ago"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 second ago"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> seconds ago"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minute ago"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minutes ago"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 hour ago"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> hours ago"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Last month"</string>
<string name="older" msgid="5211975022815554840">"Older"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"yesterday"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> days ago"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"in 1 second"</item>
- <item quantity="other" msgid="1241926116443974687">"in <xliff:g id="COUNT">%d</xliff:g> seconds"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"in 1 minute"</item>
- <item quantity="other" msgid="3330713936399448749">"in <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"in 1 hour"</item>
- <item quantity="other" msgid="547290677353727389">"in <xliff:g id="COUNT">%d</xliff:g> hours"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"tomorrow"</item>
- <item quantity="other" msgid="5109449375100953247">"in <xliff:g id="COUNT">%d</xliff:g> days"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 sec ago"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> secs ago"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 min ago"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> mins ago"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 hour ago"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> hours ago"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"yesterday"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> days ago"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"in 1 sec"</item>
- <item quantity="other" msgid="5495880108825805108">"in <xliff:g id="COUNT">%d</xliff:g> secs"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"in 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"in <xliff:g id="COUNT">%d</xliff:g> mins"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"in 1 hour"</item>
- <item quantity="other" msgid="3705373766798013406">"in <xliff:g id="COUNT">%d</xliff:g> hours"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"tomorrow"</item>
- <item quantity="other" msgid="2973062968038355991">"in <xliff:g id="COUNT">%d</xliff:g> days"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"on <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"at <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"in<xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rSG/strings.xml b/core/res/res/values-en-rSG/strings.xml
index 09a8490..5ba1082b 100644
--- a/core/res/res/values-en-rSG/strings.xml
+++ b/core/res/res/values-en-rSG/strings.xml
@@ -776,22 +776,6 @@
<skip />
<!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
<skip />
- <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
- <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
- <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
- <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
- <!-- no translation found for num_hours_ago:one (853404611989669641) -->
- <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
- <!-- no translation found for num_days_ago:one (4222479980812128212) -->
- <!-- no translation found for num_days_ago:other (5445701370433601703) -->
- <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
- <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
- <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
- <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
- <!-- no translation found for in_num_hours:one (6501470863235186391) -->
- <!-- no translation found for in_num_hours:other (4415358752953289251) -->
- <!-- no translation found for in_num_days:one (5608475533104443893) -->
- <!-- no translation found for in_num_days:other (3827193006163842267) -->
<!-- no translation found for preposition_for_date (2689847983632851560) -->
<skip />
<!-- no translation found for preposition_for_time (2613388053493148013) -->
diff --git a/core/res/res/values-en-rUS/strings.xml b/core/res/res/values-en-rUS/strings.xml
index fdc0d69..adae7f4 100644
--- a/core/res/res/values-en-rUS/strings.xml
+++ b/core/res/res/values-en-rUS/strings.xml
@@ -777,22 +777,6 @@
<skip />
<!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
<skip />
- <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
- <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
- <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
- <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
- <!-- no translation found for num_hours_ago:one (853404611989669641) -->
- <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
- <!-- no translation found for num_days_ago:one (4222479980812128212) -->
- <!-- no translation found for num_days_ago:other (5445701370433601703) -->
- <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
- <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
- <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
- <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
- <!-- no translation found for in_num_hours:one (6501470863235186391) -->
- <!-- no translation found for in_num_hours:other (4415358752953289251) -->
- <!-- no translation found for in_num_days:one (5608475533104443893) -->
- <!-- no translation found for in_num_days:other (3827193006163842267) -->
<!-- no translation found for preposition_for_date (2689847983632851560) -->
<skip />
<!-- no translation found for preposition_for_time (2613388053493148013) -->
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 5c8e65c..65e50dc 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"El modo avión está Activado"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"El modo avión está Desactivado"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Configuración"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear ahora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
@@ -1132,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> desea activar la exploración táctil. Cuando esta función esté activada, podrás escuchar o ver descripciones del contenido seleccionado o usar gestos para interactuar con el dispositivo."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Hace 1 mes."</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Anterior a 1 mes atrás"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"hace 1 segundo"</item>
- <item quantity="other" msgid="3903706804349556379">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Hace 1 minuto."</item>
- <item quantity="other" msgid="2176942008915455116">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Hace 1 hora"</item>
- <item quantity="other" msgid="2467273239587587569">"Hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Último mes"</string>
<string name="older" msgid="5211975022815554840">"Antiguos"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ayer"</item>
- <item quantity="other" msgid="2479586466153314633">"Hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"en 1 segundo"</item>
- <item quantity="other" msgid="1241926116443974687">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"en 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"en 1 hora"</item>
- <item quantity="other" msgid="547290677353727389">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"mañana"</item>
- <item quantity="other" msgid="5109449375100953247">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"hace 1 segundo"</item>
- <item quantity="other" msgid="3699169366650930415">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"hace 1 min"</item>
- <item quantity="other" msgid="851164968597150710">"Hace <xliff:g id="COUNT">%d</xliff:g> minutos."</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Hace 1 hora"</item>
- <item quantity="other" msgid="6889970745748538901">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ayer"</item>
- <item quantity="other" msgid="3453342639616481191">"Hace <xliff:g id="COUNT">%d</xliff:g> días."</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"en 1 segundo"</item>
- <item quantity="other" msgid="5495880108825805108">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"en 1 minuto"</item>
- <item quantity="other" msgid="4216113292706568726">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"en 1 hora"</item>
- <item quantity="other" msgid="3705373766798013406">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"mañana"</item>
- <item quantity="other" msgid="2973062968038355991">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"activado <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"a las <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index f06832d..82cd9c8 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quiere habilitar la exploración táctil. Cuando esta función esté activada, podrás escuchar o ver descripciones del contenido seleccionado o usar gestos para interactuar con el teléfono."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Hace un mes"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Hace más de un mes"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Hace 1 segundo"</item>
- <item quantity="other" msgid="3903706804349556379">"Hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Hace 1 minuto"</item>
- <item quantity="other" msgid="2176942008915455116">"Hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Hace 1 hora"</item>
- <item quantity="other" msgid="2467273239587587569">"Hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"El mes pasado"</string>
<string name="older" msgid="5211975022815554840">"Anterior"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"Ayer"</item>
- <item quantity="other" msgid="2479586466153314633">"Hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"dentro de 1 segundo"</item>
- <item quantity="other" msgid="1241926116443974687">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"dentro de 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"dentro de 1 hora"</item>
- <item quantity="other" msgid="547290677353727389">"dentro de <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"mañana"</item>
- <item quantity="other" msgid="5109449375100953247">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"hace 1 segundo"</item>
- <item quantity="other" msgid="3699169366650930415">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"hace 1 minuto"</item>
- <item quantity="other" msgid="851164968597150710">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"hace 1 hora"</item>
- <item quantity="other" msgid="6889970745748538901">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"Ayer"</item>
- <item quantity="other" msgid="3453342639616481191">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"dentro de 1 segundo"</item>
- <item quantity="other" msgid="5495880108825805108">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"dentro de 1 minuto"</item>
- <item quantity="other" msgid="4216113292706568726">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"dentro de 1 hora"</item>
- <item quantity="other" msgid="3705373766798013406">"dentro de <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"mañana"</item>
- <item quantity="other" msgid="2973062968038355991">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"el <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"a las <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 5a8e0a0..bef7626 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> soovib lubada puudutusega uurimise. Kui puudutusega uurimine on sisse lülitatud, kuulete või näete kirjeldusi asjade kohta, mis on teie sõrme all, või saate suhelda telefoniga liigutuste abil."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 kuu tagasi"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Varem kui 1 kuu tagasi"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 sekund tagasi"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sekundit tagasi"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minut tagasi"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minutit tagasi"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 tund tagasi"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> tundi tagasi"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Eelmisel kuul"</string>
<string name="older" msgid="5211975022815554840">"Vanem"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"eile"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> päeva tagasi"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 sekundi pärast"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> sekundi pärast"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 minuti pärast"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> minuti pärast"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 tunni pärast"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> tunni pärast"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"homme"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> päeva pärast"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 s tagasi"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sekundit tagasi"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 minut tagasi"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minutit tagasi"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 tund tagasi"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> tundi tagasi"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"eile"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> päeva tagasi"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 sekundi pärast"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> sekundi pärast"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 minuti pärast"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> minuti pärast"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 tunni pärast"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> tunni pärast"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"homme"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> päeva pärast"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"kuupäeval <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"kell <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"aastal <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index e2369ea..a37111b 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> zerbitzuak \"Arakatu ukituta\" eginbidea gaitu nahi du. Eginbide hori aktibatuta dagoenean, hatzaren azpian duzunaren azalpena ikus edo entzun dezakezu, edo telefonoarekin elkarrekintzan aritzeko keinuak egin ditzakezu."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Duela hilabete"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Duela hilabete baino gutxiago"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"duela segundo bat"</item>
- <item quantity="other" msgid="3903706804349556379">"duela <xliff:g id="COUNT">%d</xliff:g> segundo"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"duela minutu bat"</item>
- <item quantity="other" msgid="2176942008915455116">"duela <xliff:g id="COUNT">%d</xliff:g> minutu"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Duela ordubete"</item>
- <item quantity="other" msgid="2467273239587587569">"duela <xliff:g id="COUNT">%d</xliff:g> ordu"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Azken hilabetea"</string>
<string name="older" msgid="5211975022815554840">"Zaharragoa"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"atzo"</item>
- <item quantity="other" msgid="2479586466153314633">"Duela <xliff:g id="COUNT">%d</xliff:g> egun"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"segundo bat barru"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> segundo barru"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"Minutu bat barru"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> minutu barru"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"Ordubete barru"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> ordu barru"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"bihar"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> egun barru"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"duela segundo bat"</item>
- <item quantity="other" msgid="3699169366650930415">"duela <xliff:g id="COUNT">%d</xliff:g> segundo"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"duela minutu bat"</item>
- <item quantity="other" msgid="851164968597150710">"duela <xliff:g id="COUNT">%d</xliff:g> minutu"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"duela ordubete"</item>
- <item quantity="other" msgid="6889970745748538901">"duela <xliff:g id="COUNT">%d</xliff:g> ordu"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"atzo"</item>
- <item quantity="other" msgid="3453342639616481191">"Duela <xliff:g id="COUNT">%d</xliff:g> egun"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"segundo bat barru"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> segundo barru"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"minutu bat barru"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> minutu barru"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"ordubete barru"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> ordu barru"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"bihar"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> egun barru"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"data: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"urtea: <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 547f432..42ae410 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> میخواهد «کاوش با لمس» را فعال کند. وقتی «کاوش با لمس» فعال است، میتوانید توضیحاتی را برای آنچه که زیر انگشت شما است مشاهده کرده یا بشنوید یا برای استفاده از تلفن خود از حرکات استفاده کنید."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"۱ ماه قبل"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"قبل از ۱ ماه گذشته"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"۱ ثانیه قبل"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ثانیه قبل"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"۱ دقیقه قبل"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> دقیقه قبل"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"۱ ساعت قبل"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ساعت قبل"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"ماه گذشته"</string>
<string name="older" msgid="5211975022815554840">"قدیمی تر"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ديروز"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> روز قبل"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"در ۱ ثانیه"</item>
- <item quantity="other" msgid="1241926116443974687">"در <xliff:g id="COUNT">%d</xliff:g> ثانیه"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"در ۱ دقیقه"</item>
- <item quantity="other" msgid="3330713936399448749">"در <xliff:g id="COUNT">%d</xliff:g> دقیقه"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"در ۱ ساعت"</item>
- <item quantity="other" msgid="547290677353727389">"در <xliff:g id="COUNT">%d</xliff:g> ساعت"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"فردا"</item>
- <item quantity="other" msgid="5109449375100953247">"در <xliff:g id="COUNT">%d</xliff:g> روز"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"۱ ثانیه قبل"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ثانیه قبل"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"۱ دقیقه قبل"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> دقیقه قبل"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"۱ ساعت قبل"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ساعت قبل"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ديروز"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> روز قبل"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"در ۱ ثانیه"</item>
- <item quantity="other" msgid="5495880108825805108">"در <xliff:g id="COUNT">%d</xliff:g> ثانیه"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"در ۱ دقیقه"</item>
- <item quantity="other" msgid="4216113292706568726">"در <xliff:g id="COUNT">%d</xliff:g> دقیقه"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"در ۱ ساعت"</item>
- <item quantity="other" msgid="3705373766798013406">"در <xliff:g id="COUNT">%d</xliff:g> ساعت"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"فردا"</item>
- <item quantity="other" msgid="2973062968038355991">"در <xliff:g id="COUNT">%d</xliff:g> روز"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"در <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"در <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"در <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index f5ef513c..0798424 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lentokonetila on KÄYTÖSSÄ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lentokonetila on POIS KÄYTÖSTÄ"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Asetukset"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Ääniapuri"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lukitse nyt"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
@@ -1132,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> haluaa ottaa Tutustu koskettamalla -ominaisuuden käyttöön. Kun Tutustu koskettamalla on käytössä, näet tai kuulet kuvauksen sormen alla olevista kohteista ja voit käyttää puhelinta sormieleiden avulla."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"kuukausi sitten"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Yli kuukausi sitten"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 sekunti sitten"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sekuntia sitten"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minuutti sitten"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minuuttia sitten"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 tunti sitten"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> tuntia sitten"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Viime kuussa"</string>
<string name="older" msgid="5211975022815554840">"Vanhemmat"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"eilen"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> päivää sitten"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 sekunnin kuluttua"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> sekunnin kuluttua"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 minuutin kuluttua"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> minuutin kuluttua"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 tunnin kuluttua"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> tunnin kuluttua"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"huomenna"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> päivän kuluttua"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 s sitten"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> s sitten"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 min sitten"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min sitten"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 tunti sitten"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> tuntia sitten"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"eilen"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> päivää sitten"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 s kuluttua"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> sekunnin kuluttua"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 min kuluttua"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> min kuluttua"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 tunnin kuluttua"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> tunnin kuluttua"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"huomenna"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> päivän kuluttua"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"päivä: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"klo <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"vuonna <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 9a9ab32..52f3e48 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> souhaite activer la fonctionnalité \"Explorer au toucher\". Lorsque celle-ci est activée, vous pouvez entendre ou voir les descriptions des éléments que vous sélectionnez, ou bien interagir avec le téléphone en effectuant certains gestes."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Il y a 1 mois"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Il y a plus d\'un mois"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"il y a 1 seconde"</item>
- <item quantity="other" msgid="3903706804349556379">"Il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Il y a 1 minute"</item>
- <item quantity="other" msgid="2176942008915455116">"Il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Il y a 1 heure"</item>
- <item quantity="other" msgid="2467273239587587569">"il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Le mois dernier"</string>
<string name="older" msgid="5211975022815554840">"Précédent"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"hier"</item>
- <item quantity="other" msgid="2479586466153314633">"il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"dans 1 seconde"</item>
- <item quantity="other" msgid="1241926116443974687">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"dans 1 minute"</item>
- <item quantity="other" msgid="3330713936399448749">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"dans 1 heure"</item>
- <item quantity="other" msgid="547290677353727389">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"demain"</item>
- <item quantity="other" msgid="5109449375100953247">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"il y a 1 seconde"</item>
- <item quantity="other" msgid="3699169366650930415">"il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"il y a 1 min"</item>
- <item quantity="other" msgid="851164968597150710">"il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Il y a 1 h"</item>
- <item quantity="other" msgid="6889970745748538901">"il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"hier"</item>
- <item quantity="other" msgid="3453342639616481191">"il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"dans 1 seconde"</item>
- <item quantity="other" msgid="5495880108825805108">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"dans 1 minute"</item>
- <item quantity="other" msgid="4216113292706568726">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"dans 1 heure"</item>
- <item quantity="other" msgid="3705373766798013406">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"demain"</item>
- <item quantity="other" msgid="2973062968038355991">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"le <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"à <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 4ba1aae..667c7cb 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> souhaite activer la fonctionnalité \"Explorer au toucher\". Lorsque celle-ci est activée, vous pouvez entendre ou voir les descriptions des éléments que vous sélectionnez, ou bien interagir avec le téléphone en effectuant certains gestes."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Il y a 1 mois"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Il y a plus d\'un mois"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Il y a 1 seconde"</item>
- <item quantity="other" msgid="3903706804349556379">"Il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Il y a 1 minute"</item>
- <item quantity="other" msgid="2176942008915455116">"Il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"il y a 1 heure"</item>
- <item quantity="other" msgid="2467273239587587569">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Le mois dernier"</string>
<string name="older" msgid="5211975022815554840">"Préc."</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"hier"</item>
- <item quantity="other" msgid="2479586466153314633">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"dans 1 seconde"</item>
- <item quantity="other" msgid="1241926116443974687">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"dans 1 minute"</item>
- <item quantity="other" msgid="3330713936399448749">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"dans 1 heure"</item>
- <item quantity="other" msgid="547290677353727389">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"demain"</item>
- <item quantity="other" msgid="5109449375100953247">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"il y a 1 seconde"</item>
- <item quantity="other" msgid="3699169366650930415">"il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"il y a 1 minute"</item>
- <item quantity="other" msgid="851164968597150710">"il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"il y a 1 heure"</item>
- <item quantity="other" msgid="6889970745748538901">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"hier"</item>
- <item quantity="other" msgid="3453342639616481191">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"dans 1 seconde"</item>
- <item quantity="other" msgid="5495880108825805108">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"dans 1 minute"</item>
- <item quantity="other" msgid="4216113292706568726">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"dans 1 heure"</item>
- <item quantity="other" msgid="3705373766798013406">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"demain"</item>
- <item quantity="other" msgid="2973062968038355991">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"le <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"à <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 26629c1..220fec7 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quere activar a exploración táctil. Cando a exploración táctil estea activada, poderás escoitar ou ver descricións do contido seleccionado ou realizar xestos para interactuar co teléfono."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Hai 1 mes"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Hai máis de 1 mes"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"hai 1 segundo"</item>
- <item quantity="other" msgid="3903706804349556379">"hai <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"hai 1 minuto"</item>
- <item quantity="other" msgid="2176942008915455116">"hai <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Hai 1 hora"</item>
- <item quantity="other" msgid="2467273239587587569">"hai <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"O mes pasado"</string>
<string name="older" msgid="5211975022815554840">"Antes"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"onte"</item>
- <item quantity="other" msgid="2479586466153314633">"Hai <xliff:g id="COUNT">%d</xliff:g> días"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"en 1 segundo"</item>
- <item quantity="other" msgid="1241926116443974687">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"En 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"En 1 hora"</item>
- <item quantity="other" msgid="547290677353727389">"En <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"mañá"</item>
- <item quantity="other" msgid="5109449375100953247">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"hai 1 s"</item>
- <item quantity="other" msgid="3699169366650930415">"hai <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"hai 1 min"</item>
- <item quantity="other" msgid="851164968597150710">"hai <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"hai 1 hora"</item>
- <item quantity="other" msgid="6889970745748538901">"hai <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"onte"</item>
- <item quantity="other" msgid="3453342639616481191">"Hai <xliff:g id="COUNT">%d</xliff:g> días"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"en 1 s"</item>
- <item quantity="other" msgid="5495880108825805108">"en <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"en 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"en <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"en 1 hora"</item>
- <item quantity="other" msgid="3705373766798013406">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"mañá"</item>
- <item quantity="other" msgid="2973062968038355991">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"o <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"ás <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"no <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-h320dp/bools.xml b/core/res/res/values-h320dp/bools.xml
new file mode 100644
index 0000000..8dbc2e1
--- /dev/null
+++ b/core/res/res/values-h320dp/bools.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <bool name="allow_stacked_button_bar">true</bool>
+</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 2ebee8f..14c1710 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> स्पर्श के द्वारा अन्वेषण करें सक्षम करना चाहती है. स्पर्श के द्वारा अन्वेष करें चालू होने पर, आप अपनी अंगुली के नीचे क्या है उसका विवरण सुन सकते हैं या देख सकते हैं या फ़ोन से डॉयलॉग करने के लिए जेस्चर निष्पादित कर सकते हैं."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 माह पहले"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 माह से पहले"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 सेकंड पहले"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> सेकंड पहले"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 मिनट पहले"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> मिनट पहले"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 घंटे पहले"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> घंटे पहले"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"पिछला माह"</string>
<string name="older" msgid="5211975022815554840">"इससे पुराना"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"बीता कल"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> दिन पहले"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 सेकंड में"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> सेकंड में"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 मिनट में"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> मिनट में"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 घंटे में"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> घंटे में"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"आने वाला कल"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> दिन में"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 सेकंड पहले"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> सेकंड पहले"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 मिनट पहले"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> मिनट पहले"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 घंटे पहले"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> घंटे पहले"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"बीता कल"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> दिन पहले"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 सेकंड में"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> सेकंड में"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 मिनट में"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> मिनट में"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 घंटे में"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> घंटे में"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"आने वाला कल"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> दिन में"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> को"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> पर"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> में"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index af4a687..919466d 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Usluga <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> želi omogućiti značajku Istraživanje dodirom. Kad je značajka Istraživanje dodirom uključena, možete čuti ili vidjeti opise onoga što je pod vašim prstom ili izvršiti pokrete za interakciju s telefonom."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Prije 1 mjesec"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Prije 1 mjesec"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Prije 1 sekundu"</item>
- <item quantity="other" msgid="3903706804349556379">"prije <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"prije 1 minutu"</item>
- <item quantity="other" msgid="2176942008915455116">"Prije <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Prije 1 sata"</item>
- <item quantity="other" msgid="2467273239587587569">"Prije <xliff:g id="COUNT">%d</xliff:g> h"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Prošli mjesec"</string>
<string name="older" msgid="5211975022815554840">"Starije"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"jučer"</item>
- <item quantity="other" msgid="2479586466153314633">"Prije <xliff:g id="COUNT">%d</xliff:g> dana"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"za 1 sekundu"</item>
- <item quantity="other" msgid="1241926116443974687">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"za 1 minutu"</item>
- <item quantity="other" msgid="3330713936399448749">"za sljedeći broj minuta: <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"za 1 sat"</item>
- <item quantity="other" msgid="547290677353727389">"za <xliff:g id="COUNT">%d</xliff:g> h"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"sutra"</item>
- <item quantity="other" msgid="5109449375100953247">"za sljedeći broj dana: <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"Prije 1 s"</item>
- <item quantity="other" msgid="3699169366650930415">"Prije <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"Prije 1 min"</item>
- <item quantity="other" msgid="851164968597150710">"Prije <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Prije 1 sat"</item>
- <item quantity="other" msgid="6889970745748538901">"Prije <xliff:g id="COUNT">%d</xliff:g> h"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"jučer"</item>
- <item quantity="other" msgid="3453342639616481191">"Prije <xliff:g id="COUNT">%d</xliff:g> dana"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"za 1 s"</item>
- <item quantity="other" msgid="5495880108825805108">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"za 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"za 1 sat"</item>
- <item quantity="other" msgid="3705373766798013406">"za sljedeći broj sati: <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"sutra"</item>
- <item quantity="other" msgid="2973062968038355991">"za sljedeći broj dana: <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"dana <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"u <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 2a993cd..3bcdb52 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> aktiválni szeretné a Felfedezés érintéssel funkciót. Amikor be van kapcsolva a Felfedezés érintéssel, akkor hallhatja vagy láthatja annak leírását, ami az ujja alatt van, illetve végrehajthat kézmozdulatokat a telefon kezeléséhez."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 hónapja"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Több mint 1 hónapja"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 másodperce"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> másodperce"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 perce"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> perce"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 órája"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> órája"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Múlt hónapban"</string>
<string name="older" msgid="5211975022815554840">"Régebbi"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"tegnap"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> napja"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 másodperc múlva"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> másodperc múlva"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 perc múlva"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> perc múlva"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 óra múlva"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> óra múlva"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"holnap"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> nap múlva"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 másodperce"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> másodperce"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 perce"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> perce"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 órája"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> órája"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"tegnap"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> napja"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 másodperc múlva"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> másodperc múlva"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 perc múlva"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> perc múlva"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 óra múlva"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> óra múlva"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"holnap"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> nap múlva"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"e napon: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"év: <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index c48571e..69621ad 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>-ը ցանկանում է միացնել «Հետազոտում հպման միջոցով» ռեժիմը: Երբ միացված է «Հետազոտում հպման միջոցով» ռեժիմը, դուք կարող եք լսել կամ տեսնել նկարագրությունը, թե ինչ է ձեր մատի տակ, կամ կատարել ժեստեր` հեռախոսի հետ փոխգործակցելու համար:"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ամիս առաջ"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ավելի շուտ քան 1 ամիս"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 վայրկյան առաջ"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> վայրկյան առաջ"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 րոպե առաջ"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> րոպե առաջ"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 ժամ առաջ"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ժամ առաջ"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Անցյալ ամիս"</string>
<string name="older" msgid="5211975022815554840">"Ավելի հին"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"երեկ"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> օր առաջ"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 վայրկյանից"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> վայրկյանից"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 րոպեից"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> րոպեից"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 ժամից"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> ժամից"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"վաղը"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> օրից"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 վրկ առաջ"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> վրկ. առաջ"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 րոպե առաջ"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> րոպե առաջ"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 ժամ առաջ"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ժամ առաջ"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"երեկ"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> օր առաջ"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 վրկ-ից"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> վրկ-ից"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 րոպեից"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> րոպեից"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 ժամից"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> ժամից"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"վաղը"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> օրից"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>-ին"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"ժամը <xliff:g id="TIME">%s</xliff:g>-ին"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> թվականին"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 3eba049..c07a78d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ingin mengaktifkan Menjelajah dengan Sentuhan. Saat Menjelajah dengan Sentuhan diaktifkan, Anda dapat mendengar atau melihat deskripsi dari apa yang ada di bawah jari Anda atau melakukan gerakan untuk berinteraksi dengan ponsel."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 bulan yang lalu"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Sebelum 1 bulan yang lalu"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 detik lalu"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> detik yang lalu"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 menit yang lalu"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> menit yang lalu"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 jam yang lalu"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> jam yang lalu"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Bulan lalu"</string>
<string name="older" msgid="5211975022815554840">"Lawas"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"kemarin"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> hari yang lalu"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"dalam 1 detik"</item>
- <item quantity="other" msgid="1241926116443974687">"dalam <xliff:g id="COUNT">%d</xliff:g> detik"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"dalam 1 menit"</item>
- <item quantity="other" msgid="3330713936399448749">"dalam <xliff:g id="COUNT">%d</xliff:g> menit"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"dalam 1 jam"</item>
- <item quantity="other" msgid="547290677353727389">"dalam <xliff:g id="COUNT">%d</xliff:g> jam"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"besok"</item>
- <item quantity="other" msgid="5109449375100953247">"dalam <xliff:g id="COUNT">%d</xliff:g> hari"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 detik yang lalu"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> detik yang lalu"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 menit yang lalu"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> menit yang lalu"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 jam yang lalu"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> jam yang lalu"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"kemarin"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> hari yang lalu"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"dalam 1 detik"</item>
- <item quantity="other" msgid="5495880108825805108">"dalam <xliff:g id="COUNT">%d</xliff:g> detik"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"dalam 1 menit"</item>
- <item quantity="other" msgid="4216113292706568726">"dalam <xliff:g id="COUNT">%d</xliff:g> menit"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"dalam 1 jam"</item>
- <item quantity="other" msgid="3705373766798013406">"dalam <xliff:g id="COUNT">%d</xliff:g> jam"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"besok"</item>
- <item quantity="other" msgid="2973062968038355991">"dalam <xliff:g id="COUNT">%d</xliff:g> hari"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"pada <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"pada <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"dalam <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 690d6e54..c5bf5d2 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vill kveikja á snertikönnun. Þegar kveikt er á snertikönnun geturðu heyrt eða séð lýsingu á því sem er á skjánum undir fingrinum hverju sinni eða notað bendingar til að stjórna símanum."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Fyrir mánuði"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Fyrir meira en mánuði"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"fyrir sekúndu"</item>
- <item quantity="other" msgid="3903706804349556379">"fyrir <xliff:g id="COUNT">%d</xliff:g> sekúndum"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"fyrir mínútu"</item>
- <item quantity="other" msgid="2176942008915455116">"fyrir <xliff:g id="COUNT">%d</xliff:g> mínútum"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"fyrir klukkustund"</item>
- <item quantity="other" msgid="2467273239587587569">"fyrir <xliff:g id="COUNT">%d</xliff:g> klukkustundum"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Í síðasta mánuði"</string>
<string name="older" msgid="5211975022815554840">"Eldra"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"í gær"</item>
- <item quantity="other" msgid="2479586466153314633">"fyrir <xliff:g id="COUNT">%d</xliff:g> dögum"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"eftir sekúndu"</item>
- <item quantity="other" msgid="1241926116443974687">"eftir <xliff:g id="COUNT">%d</xliff:g> sekúndur"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"eftir mínútu"</item>
- <item quantity="other" msgid="3330713936399448749">"eftir <xliff:g id="COUNT">%d</xliff:g> mínútur"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"eftir klukkustund"</item>
- <item quantity="other" msgid="547290677353727389">"eftir <xliff:g id="COUNT">%d</xliff:g> klukkustundir"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"á morgun"</item>
- <item quantity="other" msgid="5109449375100953247">"eftir <xliff:g id="COUNT">%d</xliff:g> daga"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"fyrir sekúndu"</item>
- <item quantity="other" msgid="3699169366650930415">"fyrir <xliff:g id="COUNT">%d</xliff:g> sekúndum"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"fyrir mínútu"</item>
- <item quantity="other" msgid="851164968597150710">"fyrir <xliff:g id="COUNT">%d</xliff:g> mínútum"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"fyrir klukkustund"</item>
- <item quantity="other" msgid="6889970745748538901">"fyrir <xliff:g id="COUNT">%d</xliff:g> klukkustundum"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"í gær"</item>
- <item quantity="other" msgid="3453342639616481191">"fyrir <xliff:g id="COUNT">%d</xliff:g> dögum"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"eftir sekúndu"</item>
- <item quantity="other" msgid="5495880108825805108">"eftir <xliff:g id="COUNT">%d</xliff:g> sekúndur"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"eftir mínútu"</item>
- <item quantity="other" msgid="4216113292706568726">"eftir <xliff:g id="COUNT">%d</xliff:g> mínútur"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"eftir klukkustund"</item>
- <item quantity="other" msgid="3705373766798013406">"eftir <xliff:g id="COUNT">%d</xliff:g> klukkustundir"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"á morgun"</item>
- <item quantity="other" msgid="2973062968038355991">"eftir <xliff:g id="COUNT">%d</xliff:g> daga"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"kl. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index bea0c13..1bdc1ff 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vuole attivare la funzione Esplora al tocco. Quando la funzione Esplora al tocco è attiva, puoi ascoltare o visualizzare le descrizioni di ciò che stai toccando oppure interagire con il telefono tramite gesti."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 mese fa"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Oltre 1 mese fa"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 secondo fa"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> secondi fa"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minuto fa"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minuti fa"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 ora fa"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Ultimo mese"</string>
<string name="older" msgid="5211975022815554840">"Precedente"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ieri"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"tra 1 secondo"</item>
- <item quantity="other" msgid="1241926116443974687">"tra <xliff:g id="COUNT">%d</xliff:g> secondi"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"tra 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"tra <xliff:g id="COUNT">%d</xliff:g> minuti"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"tra 1 ora"</item>
- <item quantity="other" msgid="547290677353727389">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"domani"</item>
- <item quantity="other" msgid="5109449375100953247">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 sec fa"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sec fa"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 min fa"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min fa"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 ora fa"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ieri"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"tra 1 sec"</item>
- <item quantity="other" msgid="5495880108825805108">"tra <xliff:g id="COUNT">%d</xliff:g> sec"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"tra 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"tra <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"tra 1 ora"</item>
- <item quantity="other" msgid="3705373766798013406">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"domani"</item>
- <item quantity="other" msgid="2973062968038355991">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"in data <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"alle ore <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"nel <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index edf5dd8..7b6d979 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> רוצה להפעיל את התכונה \'חקור על ידי מגע\'. כאשר התכונה \'חקור על ידי מגע\' מופעלת, אתה יכול לשמוע או לראות תיאורים של הפריטים שעליהם אצבעך מונחת או לקיים אינטראקציה עם הטלפון באמצעות תנועות אצבע."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"לפני חודש אחד"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"לפני חודש אחד"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"לפני שנייה אחת"</item>
- <item quantity="other" msgid="3903706804349556379">"לפני <xliff:g id="COUNT">%d</xliff:g> שניות"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"לפני דקה אחת"</item>
- <item quantity="other" msgid="2176942008915455116">"לפני <xliff:g id="COUNT">%d</xliff:g> דקות"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"לפני שעה"</item>
- <item quantity="other" msgid="2467273239587587569">"לפני <xliff:g id="COUNT">%d</xliff:g> שעות"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"בחודש שעבר"</string>
<string name="older" msgid="5211975022815554840">"ישן יותר"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"אתמול"</item>
- <item quantity="other" msgid="2479586466153314633">"לפני <xliff:g id="COUNT">%d</xliff:g> ימים"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"בעוד שנייה אחת"</item>
- <item quantity="other" msgid="1241926116443974687">"תוך <xliff:g id="COUNT">%d</xliff:g> שניות"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"בעוד דקה אחת"</item>
- <item quantity="other" msgid="3330713936399448749">"תוך <xliff:g id="COUNT">%d</xliff:g> דקות"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"תוך שעה אחת"</item>
- <item quantity="other" msgid="547290677353727389">"תוך <xliff:g id="COUNT">%d</xliff:g> שעות"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"מחר"</item>
- <item quantity="other" msgid="5109449375100953247">"בעוד <xliff:g id="COUNT">%d</xliff:g> ימים"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"לפני שנייה אחת"</item>
- <item quantity="other" msgid="3699169366650930415">"לפני <xliff:g id="COUNT">%d</xliff:g> שניות"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"לפני דקה"</item>
- <item quantity="other" msgid="851164968597150710">"לפני <xliff:g id="COUNT">%d</xliff:g> דקות"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"לפני שעה"</item>
- <item quantity="other" msgid="6889970745748538901">"לפני <xliff:g id="COUNT">%d</xliff:g> שעות"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"אתמול"</item>
- <item quantity="other" msgid="3453342639616481191">"לפני <xliff:g id="COUNT">%d</xliff:g> ימים"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"תוך שנייה אחת"</item>
- <item quantity="other" msgid="5495880108825805108">"תוך <xliff:g id="COUNT">%d</xliff:g> שניות"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"תוך דקה אחת"</item>
- <item quantity="other" msgid="4216113292706568726">"תוך <xliff:g id="COUNT">%d</xliff:g> דקות"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"תוך שעה אחת"</item>
- <item quantity="other" msgid="3705373766798013406">"תוך <xliff:g id="COUNT">%d</xliff:g> שעות"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"מחר"</item>
- <item quantity="other" msgid="2973062968038355991">"בעוד <xliff:g id="COUNT">%d</xliff:g> ימים"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"בתאריך <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"בשעה <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"בשנת <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 8714dbb..ca4ccda 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"機内モードON"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"機内モードOFF"</string>
<string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"音声アシスト"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"今すぐロック"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
@@ -1132,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>がタッチガイドをONにしようとしています。タッチガイドをONにすると、指の位置にあるアイテムの説明を読み上げたり表示したりできます。また、携帯端末を通常とは違うジェスチャーで操作できます。"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1か月前"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1か月前"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1秒前"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1分前"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g>分前"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1時間前"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g>時間前"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"先月"</string>
<string name="older" msgid="5211975022815554840">"もっと前"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"昨日"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g>日前"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1秒後"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1分後"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1時間後"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"明日"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1秒前"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1分前"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g>分前"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1時間前"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g>時間前"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"昨日"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g>日前"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1秒後"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1分後"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1時間後"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"明日"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>年"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 421c3e2..b3ab0e4 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>-ს სურს „შეხებით შესწავლის“ რეჟიმის ჩრთვა. ეს ტელეფონის ჟესტებით მართვისა და იმ ელემენტების აღწერის მოსმენის შესაძლებლობას მოგცემთ, რომელსაც შეეხებით."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"ერთი თვის წინ"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"უფრო ადრე, ვიდრე ერთი თვის წინ"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 წამის წინ"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> წამის წინ"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 წუთის უკან"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> წუთის წინ"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 საათის წინ"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> საათის წინ"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"გასული თვე"</string>
<string name="older" msgid="5211975022815554840">"უფრო ძველი"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"გუშინ"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> დღის წინ"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 წამში"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> წამში"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 წუთში"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> წუთში"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 საათში"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> საათში"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"ხვალ"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> დღეში"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 წმ. წინ"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> წამის წინ"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 წუთის წინ"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> წუთის წინ"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 საათის წინ"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> საათის წინ"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"გუშინ"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> დღის წინ"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 წამში"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> წამის წინ"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 წუთში"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> წუთში"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 საათში"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> საათში"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"ხვალ"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> დღეში"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"თარიღი: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>-ზე"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> წელს"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 7fad880..be1007dd 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> Сенсор арқылы шолу функциясын іске қосуды қалайды. Сенсор арқылы шолу функциясы қосылғанда саусақ астындағы нысан сипаттарын естуге немесе көруге болады немесе телефонмен қатынасу қимылдарын орындауға болады."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ай бұрын"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Осыған дейін 1 ай бұрын"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 секунд бұрын"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> секунд бұрын"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 минут бұрын"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> минут бұрын"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 сағат бұрын"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> сағат бұрын"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Соңғы ай"</string>
<string name="older" msgid="5211975022815554840">"Ескілеу"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"кеше"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> күн бұрын"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 секундта"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> секундта"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 минутта"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> минутта"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 сағатта"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> сағатта"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"ертең"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> күнде"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 секунд бұрын"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> секунд бұрын"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 минут бұрын"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> минут бұрын"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 сағат бұрын"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> сағат бұрын"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"кеше"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> күн бұрын"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 секундта"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> секундта"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 минутта"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> минутта"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 сағатта"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> сағатта"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"ертең"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> күнде"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> күні"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> уақытында"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> жылда"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 6f38aec..6e06b33 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ចង់បើកការរុករកដោយប៉ះ។ ពេលរុករកដោយប៉ះត្រូវបានបើក អ្នកអាចស្ដាប់ឮ ឬឃើញការពណ៌នាអ្វីដែលនៅក្រោមម្រាមដៃរបស់អ្នក ឬអនុវត្តកាយវិការដើម្បីមានអន្តរកម្មជាមួយទូរស័ព្ទ។"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ខែមុន"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"មុនពេល ១ ខែមុន"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"១ វិនាទីមុន"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> វិនាទីមុន"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"១ នាទីមុន"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> នាទីមុន"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"១ ម៉ោងមុន"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ម៉ោងមុន"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"ខែមុន"</string>
<string name="older" msgid="5211975022815554840">"ចាស់ជាង"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ម្សិលមិញ"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ថ្ងៃមុន"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"ក្នុងរយៈពេល ១ វិនាទី"</item>
- <item quantity="other" msgid="1241926116443974687">"ក្នុងរយៈពេល <xliff:g id="COUNT">%d</xliff:g> វិនាទី"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"ក្នុងរយៈពេល ១ នាទី"</item>
- <item quantity="other" msgid="3330713936399448749">"រយៈពេល <xliff:g id="COUNT">%d</xliff:g> នាទី"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"រយៈពេល ១ ម៉ោង"</item>
- <item quantity="other" msgid="547290677353727389">"រយៈពេល <xliff:g id="COUNT">%d</xliff:g> ម៉ោង"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"ថ្ងៃស្អែក"</item>
- <item quantity="other" msgid="5109449375100953247">"រយៈពេល <xliff:g id="COUNT">%d</xliff:g> ថ្ងៃ"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"១ វិនាទីមុន"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> វិនាទីមុន"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"១ នាទីមុន"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> នាទីមុន"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"១ ម៉ោងមុន"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ម៉ោងមុន"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ម្សិលមិញ"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ថ្ងៃមុន"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"ក្នុងពេល 1 វិនាទី"</item>
- <item quantity="other" msgid="5495880108825805108">"ក្នុងពេល <xliff:g id="COUNT">%d</xliff:g> វិនាទី"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"ក្នុងពេល 1 នាទី"</item>
- <item quantity="other" msgid="4216113292706568726">"នៅរយៈពេល <xliff:g id="COUNT">%d</xliff:g> នាទី"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"ក្នុងរយៈពេល ១ ម៉ោង"</item>
- <item quantity="other" msgid="3705373766798013406">"ក្នុងរយៈពេល <xliff:g id="COUNT">%d</xliff:g> ម៉ោង"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"ថ្ងៃស្អែក"</item>
- <item quantity="other" msgid="2973062968038355991">"ក្នុងរយៈពេល <xliff:g id="COUNT">%d</xliff:g> ថ្ងៃ"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"នៅ <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"នៅម៉ោង <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"ក្នុងឆ្នាំ <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index 421c103..8bb3083 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"ಸ್ಪರ್ಶದ ಮೂಲಕ ಎಕ್ಸ್ಪ್ಲೋರ್ ಸಕ್ರಿಯಗೊಳಿಸಲು <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ಬಯಸುತ್ತದೆ. ಸ್ಪರ್ಶದ ಮೂಲಕ ಎಕ್ಸ್ಪ್ಲೋರ್ ಆನ್ ಮಾಡಿದಾಗ, ಫೋನ್ ಜೊತೆ ಸಂವಹನ ನಡೆಸಲು ನಿಮ್ಮ ಬೆರಳಿನ ಅಡಿಯಲ್ಲಿರುವ ವಿವರಣೆಗಳನ್ನು ನೀವು ಆಲಿಸಬಹುದು ಅಥವಾ ವೀಕ್ಷಿಸಬಹುದು ಇಲ್ಲವೇ ಗೆಶ್ಚರ್ ಮಾಡಬಹುದು."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ತಿಂಗಳ ಹಿಂದೆ"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 ತಿಂಗಳ ಹಿಂದಕ್ಕೂ ಮೊದಲು"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 ಸೆಕೆಂಡಿನ ಹಿಂದೆ"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳ ಹಿಂದೆ"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 ನಿಮಿಷದ ಹಿಂದೆ"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳ ಹಿಂದೆ"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 ಗಂಟೆ ಹಿಂದೆ"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳ ಹಿಂದೆ"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"ಕಳೆದ ತಿಂಗಳು"</string>
<string name="older" msgid="5211975022815554840">"ಹಳೆಯದು"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ನಿನ್ನೆ"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ದಿನಗಳ ಹಿಂದೆ"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 ಸೆಕೆಂಡಿನಲ್ಲಿ"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 ನಿಮಿಷದಲ್ಲಿ"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳಲ್ಲಿ"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 ಗಂಟೆಯಲ್ಲಿ"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳಲ್ಲಿ"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"ನಾಳೆ"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> ದಿನಗಳಲ್ಲಿ"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 ಸೆಕೆಂಡಿನ ಹಿಂದೆ"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳ ಹಿಂದೆ"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 ನಿಮಿಷದ ಹಿಂದೆ"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳ ಹಿಂದೆ"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 ಗಂಟೆ ಹಿಂದೆ"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳ ಹಿಂದೆ"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ನಿನ್ನೆ"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ದಿನಗಳ ಹಿಂದೆ"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 ಸೆಕೆಂಡಿನಲ್ಲಿ"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 ನಿಮಿಷದಲ್ಲಿ"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳಲ್ಲಿ"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 ಗಂಟೆಯಲ್ಲಿ"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳಲ್ಲಿ"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"ನಾಳೆ"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> ದಿನಗಳಲ್ಲಿ"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> ರಂದು"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> ರಲ್ಲಿ"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> ರಲ್ಲಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 94c60d9..afa99f3 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>을(를) 사용하려면 \'터치하여 탐색\' 기능을 사용하도록 설정해야 합니다. \'터치하여 탐색\'을 사용하도록 설정하면, 화면을 터치하여 손가락 아래에 표시된 항목에 대한 설명을 듣고 보거나 휴대전화로 상호작용하기 위한 동작을 수행할 수 있습니다."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"한 달 전"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"한 달 전"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1초 전"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g>초 전"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1분 전"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1시간 전"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"지난 달"</string>
<string name="older" msgid="5211975022815554840">"이전"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"어제"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g>일 전"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1초 내"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1분 후"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1시간 후"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"내일"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g>일 후"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1초 전"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g>초 전"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1분 전"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1시간 전"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"어제"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g>일 전"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1초 후"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1분 후"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1시간 후"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"내일"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g>일 후"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>년"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 898b226..f4586e1 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -1474,44 +1474,11 @@
<skip />
<!-- no translation found for beforeOneMonthDurationPast (909134546836499826) -->
<skip />
- <!-- no translation found for num_seconds_ago:one (4869870056547896011) -->
- <!-- no translation found for num_seconds_ago:other (3903706804349556379) -->
- <!-- no translation found for num_minutes_ago:one (3306787433088810191) -->
- <!-- no translation found for num_minutes_ago:other (2176942008915455116) -->
- <!-- no translation found for num_hours_ago:one (9150797944610821849) -->
- <!-- no translation found for num_hours_ago:other (2467273239587587569) -->
- <!-- no translation found for last_num_days:one (7555846096746489821) -->
<!-- no translation found for last_num_days:other (3069992808164318268) -->
<!-- no translation found for last_month (3959346739979055432) -->
<skip />
<!-- no translation found for older (5211975022815554840) -->
<skip />
- <!-- no translation found for num_days_ago:one (861358534398115820) -->
- <!-- no translation found for num_days_ago:other (2479586466153314633) -->
- <!-- no translation found for in_num_seconds:one (2729745560954905102) -->
- <!-- no translation found for in_num_seconds:other (1241926116443974687) -->
- <!-- no translation found for in_num_minutes:one (8793095251325200395) -->
- <!-- no translation found for in_num_minutes:other (3330713936399448749) -->
- <!-- no translation found for in_num_hours:one (7164353342477769999) -->
- <!-- no translation found for in_num_hours:other (547290677353727389) -->
- <!-- no translation found for in_num_days:one (5413088743009839518) -->
- <!-- no translation found for in_num_days:other (5109449375100953247) -->
- <!-- no translation found for abbrev_num_seconds_ago:one (1849036840200069118) -->
- <!-- no translation found for abbrev_num_seconds_ago:other (3699169366650930415) -->
- <!-- no translation found for abbrev_num_minutes_ago:one (6361490147113871545) -->
- <!-- no translation found for abbrev_num_minutes_ago:other (851164968597150710) -->
- <!-- no translation found for abbrev_num_hours_ago:one (4796212039724722116) -->
- <!-- no translation found for abbrev_num_hours_ago:other (6889970745748538901) -->
- <!-- no translation found for abbrev_num_days_ago:one (8463161711492680309) -->
- <!-- no translation found for abbrev_num_days_ago:other (3453342639616481191) -->
- <!-- no translation found for abbrev_in_num_seconds:one (5842225370795066299) -->
- <!-- no translation found for abbrev_in_num_seconds:other (5495880108825805108) -->
- <!-- no translation found for abbrev_in_num_minutes:one (562786149928284878) -->
- <!-- no translation found for abbrev_in_num_minutes:other (4216113292706568726) -->
- <!-- no translation found for abbrev_in_num_hours:one (3274708118124045246) -->
- <!-- no translation found for abbrev_in_num_hours:other (3705373766798013406) -->
- <!-- no translation found for abbrev_in_num_days:one (2178576254385739855) -->
- <!-- no translation found for abbrev_in_num_days:other (2973062968038355991) -->
<!-- no translation found for preposition_for_date (9093949757757445117) -->
<skip />
<!-- no translation found for preposition_for_time (5506831244263083793) -->
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 086a9e5..ec70266 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ຕ້ອງການເປີດນຳໃຊ້ \"ການສຳຫຼວດໂດຍສຳພັດ\". ເມື່ອເປີດ \"ການສຳຫຼວດໂດຍສຳພັດ\" ແລ້ວ ທ່ານຈະສາມາດໄດ້ຍິນ ຫຼືເຫັນຄຳບັນຍາຍວ່າມີຫຍັງຢູ່ກ້ອງນິ້ວມືຂອງທ່ານ ຫຼືໃຊ້ຮູບແບບການເຄື່ອນໄຫວເພື່ອໂຕ້ຕອບກັບໂທລະສັບ."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ເດືອນກ່ອນຫນ້ານີ້"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ຫຼາຍກວ່າ 1 ເດືອນກ່ອນ"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 ວິນາທີກ່ອນ"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ວິນາທີກ່ອນໜ້ານີ້"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 ນາທີກ່ອນໜ້ານີ້"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> ນາທີທີ່ຜ່ານມາ"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 ຊົ່ວໂມງກ່ອນໜ້ານີ້"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ຊົ່ວໂມງທີ່ຜ່ານມາ"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"ເດືອນແລ້ວ"</string>
<string name="older" msgid="5211975022815554840">"ເກົ່າກວ່າ"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ມື້ວານນີ້"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ມື້ກ່ອນ"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"ໃນອີກ 1 ວິນາທີ"</item>
- <item quantity="other" msgid="1241926116443974687">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ວິນາທີ"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"ໃນ 1 ນາທີ"</item>
- <item quantity="other" msgid="3330713936399448749">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ນາທີ"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"ໃນ 1 ຊົ່ວໂມງ"</item>
- <item quantity="other" msgid="547290677353727389">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ຊົ່ວໂມງ"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"ມື້ອື່ນ"</item>
- <item quantity="other" msgid="5109449375100953247">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ມື້"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 ວິນາທີກ່ອນ"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ວິ ກ່ອນໜ້ານີ້"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 ນທ ກ່ອນ"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> ນທ ກ່ອນໜ້ານີ້"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 ຊົ່ວໂມງກ່ອນ"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ຊົ່ວໂມງກ່ອນໜ້ານີ້"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ມື້ວານນີ້"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ມື້ກ່ອນໜ້ານີ້"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"ໃນ 1 ວິ"</item>
- <item quantity="other" msgid="5495880108825805108">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ວິ"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"ໃນ 1 ນາທີ"</item>
- <item quantity="other" msgid="4216113292706568726">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ນທ"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"ໃນ 1 ຊົ່ວໂມງ"</item>
- <item quantity="other" msgid="3705373766798013406">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ຊົ່ວໂມງ"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"ມື້ອື່ນ"</item>
- <item quantity="other" msgid="2973062968038355991">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ມື້"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"ວັນທີ <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"ເວລາ <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"ໃນ <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index d7a93ac..8e8d436 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"„<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>“ nori įgalinti naršymą liečiant. Kai naršymas liečiant bus įjungtas, galėsite išgirsti ar peržiūrėti pirštu liečiamų elementų aprašus arba atlikdami gestus naudoti telefoną."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Prieš 1 mėn."</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Prieš maždaug 1 mėnesį"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Prieš 1 sek."</item>
- <item quantity="other" msgid="3903706804349556379">"Prieš <xliff:g id="COUNT">%d</xliff:g> sek."</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Prieš 1 minutę"</item>
- <item quantity="other" msgid="2176942008915455116">"Prieš <xliff:g id="COUNT">%d</xliff:g> min."</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Prieš 1 valandą"</item>
- <item quantity="other" msgid="2467273239587587569">"Prieš <xliff:g id="COUNT">%d</xliff:g> val."</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Paskutinį mėnesį"</string>
<string name="older" msgid="5211975022815554840">"Senesni"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"vakar"</item>
- <item quantity="other" msgid="2479586466153314633">"Prieš <xliff:g id="COUNT">%d</xliff:g> d."</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"po 1 sek."</item>
- <item quantity="other" msgid="1241926116443974687">"po <xliff:g id="COUNT">%d</xliff:g> sek."</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"po 1 min."</item>
- <item quantity="other" msgid="3330713936399448749">"po <xliff:g id="COUNT">%d</xliff:g> min."</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"po 1 val."</item>
- <item quantity="other" msgid="547290677353727389">"po <xliff:g id="COUNT">%d</xliff:g> val."</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"rytoj"</item>
- <item quantity="other" msgid="5109449375100953247">"po <xliff:g id="COUNT">%d</xliff:g> d."</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"Prieš 1 sek."</item>
- <item quantity="other" msgid="3699169366650930415">"Prieš <xliff:g id="COUNT">%d</xliff:g> sek."</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"Prieš 1 min."</item>
- <item quantity="other" msgid="851164968597150710">"Prieš <xliff:g id="COUNT">%d</xliff:g> min."</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Prieš 1 valandą"</item>
- <item quantity="other" msgid="6889970745748538901">"Prieš <xliff:g id="COUNT">%d</xliff:g> val."</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"vakar"</item>
- <item quantity="other" msgid="3453342639616481191">"Prieš <xliff:g id="COUNT">%d</xliff:g> d."</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"po 1 sek."</item>
- <item quantity="other" msgid="5495880108825805108">"po <xliff:g id="COUNT">%d</xliff:g> sek."</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"po 1 min."</item>
- <item quantity="other" msgid="4216113292706568726">"po <xliff:g id="COUNT">%d</xliff:g> min."</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"po 1 val."</item>
- <item quantity="other" msgid="3705373766798013406">"po <xliff:g id="COUNT">%d</xliff:g> val."</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"rytoj"</item>
- <item quantity="other" msgid="2973062968038355991">"po <xliff:g id="COUNT">%d</xliff:g> d."</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> m."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 1989b55..2c74c82 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vēlas iespējot funkciju “Atklāt pieskaroties”. Kad ir ieslēgta funkcija “Atklāt pieskaroties”, var dzirdēt vai redzēt tā vienuma aprakstu, virs kura atrodas pirksts, vai veikt žestus, lai mijiedarbotos ar tālruni."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Pirms 1 mēneša"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vairāk nekā pirms 1 mēneša"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Pirms 1 sekundes"</item>
- <item quantity="other" msgid="3903706804349556379">"Pirms <xliff:g id="COUNT">%d</xliff:g> sekundes(-ēm)"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Pirms 1 minūtes"</item>
- <item quantity="other" msgid="2176942008915455116">"Pirms <xliff:g id="COUNT">%d</xliff:g> minūtes(-ēm)"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Pirms 1 stundas"</item>
- <item quantity="other" msgid="2467273239587587569">"Pirms <xliff:g id="COUNT">%d</xliff:g> stundas(-ām)"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Iepriekšējā mēnesī"</string>
<string name="older" msgid="5211975022815554840">"Vecāks"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"vakar"</item>
- <item quantity="other" msgid="2479586466153314633">"Pirms <xliff:g id="COUNT">%d</xliff:g> dienas(-ām)"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"pēc 1 sekundes"</item>
- <item quantity="other" msgid="1241926116443974687">"pēc <xliff:g id="COUNT">%d</xliff:g> sekundes(-ēm)"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"pēc 1 minūtes"</item>
- <item quantity="other" msgid="3330713936399448749">"pēc <xliff:g id="COUNT">%d</xliff:g> minūtes(-ēm)"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"pēc 1 stundas"</item>
- <item quantity="other" msgid="547290677353727389">"pēc <xliff:g id="COUNT">%d</xliff:g> stundas(-ām)"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"rītdien"</item>
- <item quantity="other" msgid="5109449375100953247">"pēc <xliff:g id="COUNT">%d</xliff:g> dienas(-ām)"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"Pirms 1 sekundes"</item>
- <item quantity="other" msgid="3699169366650930415">"Pirms <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"Pirms 1 min"</item>
- <item quantity="other" msgid="851164968597150710">"Pirms <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Pirms 1 stundas"</item>
- <item quantity="other" msgid="6889970745748538901">"Pirms <xliff:g id="COUNT">%d</xliff:g> stundas(-ām)"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"vakar"</item>
- <item quantity="other" msgid="3453342639616481191">"Pirms <xliff:g id="COUNT">%d</xliff:g> dienas(-ām)"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"pēc 1 s"</item>
- <item quantity="other" msgid="5495880108825805108">"pēc <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"pēc 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"pēc <xliff:g id="COUNT">%d</xliff:g> minūtes(-ēm)"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"pēc 1 stundas"</item>
- <item quantity="other" msgid="3705373766798013406">"pēc <xliff:g id="COUNT">%d</xliff:g> stundas(-ām)"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"rītdien"</item>
- <item quantity="other" msgid="2973062968038355991">"pēc <xliff:g id="COUNT">%d</xliff:g> dienas(-ām)"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"šādā datumā: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"šādā gadā: <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index a3d0386..a6ec56c 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> сака да овозможи „Истражувај со допир“. Кога е вклучено „Истражувај со допир“, може да се слушнат или да се видат описи на она што е под вашиот прст или да се прават движења за комуницирање со телефонот."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Пред 1 месец"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Пред повеќе од 1 месец"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"пред 1 секунда"</item>
- <item quantity="other" msgid="3903706804349556379">"пред <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"пред 1 минута"</item>
- <item quantity="other" msgid="2176942008915455116">"пред <xliff:g id="COUNT">%d</xliff:g> минути"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Пред 1 час"</item>
- <item quantity="other" msgid="2467273239587587569">"пред <xliff:g id="COUNT">%d</xliff:g> часа"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Минатиот месец"</string>
<string name="older" msgid="5211975022815554840">"Постари"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"вчера"</item>
- <item quantity="other" msgid="2479586466153314633">"Пред <xliff:g id="COUNT">%d</xliff:g> дена"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"за 1 секунда"</item>
- <item quantity="other" msgid="1241926116443974687">"за <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"за 1 минута"</item>
- <item quantity="other" msgid="3330713936399448749">"за <xliff:g id="COUNT">%d</xliff:g> минути"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"за 1 час"</item>
- <item quantity="other" msgid="547290677353727389">"за <xliff:g id="COUNT">%d</xliff:g> часа"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"утре"</item>
- <item quantity="other" msgid="5109449375100953247">"за <xliff:g id="COUNT">%d</xliff:g> дена"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"пред 1 сек"</item>
- <item quantity="other" msgid="3699169366650930415">"пред <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"пред 1 мин"</item>
- <item quantity="other" msgid="851164968597150710">"пред <xliff:g id="COUNT">%d</xliff:g> минути"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"пред 1 час"</item>
- <item quantity="other" msgid="6889970745748538901">"пред <xliff:g id="COUNT">%d</xliff:g> часа"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"вчера"</item>
- <item quantity="other" msgid="3453342639616481191">"Пред <xliff:g id="COUNT">%d</xliff:g> дена"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"за 1 сек"</item>
- <item quantity="other" msgid="5495880108825805108">"за <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"за 1 мин"</item>
- <item quantity="other" msgid="4216113292706568726">"за <xliff:g id="COUNT">%d</xliff:g> минути"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"за 1 час"</item>
- <item quantity="other" msgid="3705373766798013406">"за <xliff:g id="COUNT">%d</xliff:g> часа"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"утре"</item>
- <item quantity="other" msgid="2973062968038355991">"за <xliff:g id="COUNT">%d</xliff:g> дена"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"на <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"во <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"во <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 49f86e8..a2e36ac 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"ടച്ച് വഴി പര്യവേക്ഷണം ചെയ്യൽ പ്രവർത്തനക്ഷമമാക്കാൻ <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> താൽപ്പര്യപ്പെടുന്നു. ടച്ച് വഴി പര്യവേക്ഷണം ചെയ്യൽ ഓൺ ചെയ്യുമ്പോൾ, നിങ്ങളുടെ വിരലിനടിയിലുള്ളവയുടെ വിവരണം കേൾക്കാനോ കാണാനോ അല്ലെങ്കിൽ ഫോണുമായി സംവദിക്കുന്ന ജെസ്റ്ററുകൾ നിർവഹിക്കാനോ കഴിയും."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 മാസം മുമ്പുള്ളത്"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ഒരു മാസം മുമ്പ്"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 നിമിഷം മുമ്പ്"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> നിമിഷം മുമ്പ്"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 മിനിറ്റ് മുമ്പ്"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> മിനിറ്റ് മുമ്പ്"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 മണിക്കൂര് മുമ്പ്"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> മണിക്കൂർ മുമ്പ്"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"കഴിഞ്ഞ മാസം"</string>
<string name="older" msgid="5211975022815554840">"പഴയത്"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ഇന്നലെ"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ദിവസം മുമ്പ്"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"ഒരു നിമിഷത്തിനുള്ളിൽ"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> നിമിഷത്തിനുള്ളിൽ"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"ഒരു മിനിറ്റിൽ"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> മിനിറ്റിനുള്ളിൽ"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"ഒരു മണിക്കൂറിനുള്ളിൽ"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> മണിക്കൂറിനുള്ളിൽ"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"നാളെ"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> ദിവസത്തിനുള്ളിൽ"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"ഒരു നിമിഷം മുമ്പ്"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> നിമിഷം മുമ്പ്"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"ഒരു മിനിറ്റ് മുമ്പ്"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> മിനിറ്റ് മുമ്പ്"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 മണിക്കൂര് മുമ്പ്"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> മണിക്കൂർ മുമ്പ്"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ഇന്നലെ"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ദിവസം മുമ്പ്"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"ഒരു നിമിഷത്തിനുള്ളിൽ"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> നിമിഷത്തിനുള്ളിൽ"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"ഒരു മിനിറ്റിനുള്ളിൽ"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> മിനിറ്റിനുള്ളിൽ"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"ഒരു മണിക്കൂറിനുള്ളിൽ"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> മണിക്കൂറിനുള്ളിൽ"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"നാളെ"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> ദിവസത്തിനുള്ളിൽ"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>-ന്"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>-ന്"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>-ൽ"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index e714570..d91363a 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> нь Хүрч танихыг идэвхжүүлэхийг шаардаж байна. Хүрч таних идэвхжсэн тохиолдолд та хуруун доороо юу байгааг сонсох, тайлбарыг харах боломжтой ба утастайгаа дохиогоор харилцах боломжтой."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 сарын өмнө"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 сарын өмнө"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 секундын өмнө"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> секундын өмнө"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 минутын өмнө"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> минутын өмнө"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 цагийн өмнө"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> цагийн өмнө"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Сүүлийн сар"</string>
<string name="older" msgid="5211975022815554840">"Хуучин"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"өчигдөр"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> өдрийн өмнө"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 секундын дараа"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> секундын дараа"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 минутын дараа"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> минутын дараа"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 цагийн дараа"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> цагийн дараа"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"маргааш"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> өдрийн дараа"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 секундын өмнө"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> сек дараа"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 мин өмнө"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> минутын өмнө"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 цагийн өмнө"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> цагийн өмнө"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"өчигдөр"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> өдрийн өмнө"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 сек дараа"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> сек дараа"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 мин дараа"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> минутын дараа"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 цагийн дараа"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> цагийн дараа"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"маргааш"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> өдрийн дараа"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 763c18e..646a29d 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> स्पर्श करून एक्सप्लोर करा सक्षम करू इच्छिते. स्पर्श करून एक्सप्लोर करा चालू असते, तेव्हा आपण आपल्या बोटाखाली काय आहे त्याचे वर्णन ऐकू किंवा पाहू शकता किंवा फोनसह संवाद साधण्यासाठी जेश्चर करू शकता."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 महिन्यापूर्वी"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 महिन्यापूर्वी"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 सेकंदापूर्वी"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> सेकंदांपूर्वी"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 मिनिटापूर्वी"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> मिनिटांपूर्वी"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 तासापूर्वी"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> तासांपूर्वी"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"अंतिम महिना"</string>
<string name="older" msgid="5211975022815554840">"अधिक जुने"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"काल"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> दिवसांपूर्वी"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 सेकंदात"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> सेकंदांमध्ये"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 मिनिटात"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> मिनिटांमध्ये"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 तासात"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> तासांमध्ये"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"उद्या"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> दिवसांमध्ये"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 सेकंदापूर्वी"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> सेकंदांपूर्वी"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 मिनिटापूर्वी"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> मिनिटांपूर्वी"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 तासापूर्वी"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> तासांपूर्वी"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"काल"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> दिवसांपूर्वी"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 सेकंदामध्ये"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> सेकंदांमध्ये"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 मिनिटामध्ये"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> मिनिटांमध्ये"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 तासात"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> तासांमध्ये"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"उद्या"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> दिवसांमध्ये"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> रोजी"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> वाजता"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> मध्ये"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 21be5b19..069a6c0 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ingin mendayakan Jelajah melalui Sentuhan. Apabila Jelajah melalui Sentuhan didayakan, anda boleh mendengar atau melihat penerangan tentang apa di bawah jari anda atau melakukan gerak isyarat untuk berinteraksi dengan telefon."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 bulan yang lalu"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Sebelum 1 bulan yang lalu"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 saat yang lalu"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> saat yang lalu"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minit yang lalu"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minit yang lalu"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 jam yang lalu"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> jam yang lalu"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Bulan lepas"</string>
<string name="older" msgid="5211975022815554840">"Lebih lama"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"semalam"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> hari yang lalu"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"dalam 1 saat"</item>
- <item quantity="other" msgid="1241926116443974687">"dalam <xliff:g id="COUNT">%d</xliff:g> saat"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"dalam 1 minit"</item>
- <item quantity="other" msgid="3330713936399448749">"dalam <xliff:g id="COUNT">%d</xliff:g> minit"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"dalam 1 jam"</item>
- <item quantity="other" msgid="547290677353727389">"dalam <xliff:g id="COUNT">%d</xliff:g> jam"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"esok"</item>
- <item quantity="other" msgid="5109449375100953247">"dalam <xliff:g id="COUNT">%d</xliff:g> hari"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 saat yang lalu"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> saat yang lalu"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 minit yang lalu"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minit yang lalu"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 jam yang lalu"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> jam yang lalu"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"semalam"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> hari yang lalu"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"dalam 1 saat"</item>
- <item quantity="other" msgid="5495880108825805108">"dalam <xliff:g id="COUNT">%d</xliff:g> saat"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"dalam 1 minit"</item>
- <item quantity="other" msgid="4216113292706568726">"dalam <xliff:g id="COUNT">%d</xliff:g> minit"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"dalam 1 jam"</item>
- <item quantity="other" msgid="3705373766798013406">"dalam <xliff:g id="COUNT">%d</xliff:g> jam"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"esok"</item>
- <item quantity="other" msgid="2973062968038355991">"dalam <xliff:g id="COUNT">%d</xliff:g> hari"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"pada <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"pada <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"dalam <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index a8e95b5..c0bea1f 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> က ထိတွေ့ပြီး ရှာဖွေခြင်းကို လုပ်ချင်ပါသည်။ ထိတွေ့ရှာဖွေခြင်း ဖွင့်ထားလျှင် သင့်လက်ဖျားအောက်မှ အရာကို ကြားနိုင် သို့ ရှင်းလင်းချက်ကို မြင်နိုင်တဲ့ အပြင် လက် အနေအထားဖြင့် ဖုန်းကို ဆက်သွယ်ပြုလုပ်စေခိုင်းနိုင်ပါသည်"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"လွန်ခဲ့သော၁လက"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"လွန်ခဲ့သော၁လမတိုင်မီက"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"လွန်ခဲ့သော ၁စက္ကန့်က"</item>
- <item quantity="other" msgid="3903706804349556379">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> စက္ကန့်က"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"လွန်ခဲ့သော ၁မိနစ်က"</item>
- <item quantity="other" msgid="2176942008915455116">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> မိနစ်က"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"လွနခဲ့သော ၁နာရီက"</item>
- <item quantity="other" msgid="2467273239587587569">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> နာရီက"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"ပြီးခဲ့သောလ"</string>
<string name="older" msgid="5211975022815554840">"ယခင်က"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"မနေ့က"</item>
- <item quantity="other" msgid="2479586466153314633">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> ရက်တွင်"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"နောက် ၁စက္ကန့်တွင်"</item>
- <item quantity="other" msgid="1241926116443974687">"နောက် <xliff:g id="COUNT">%d</xliff:g> စက္ကန့်တွင်"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"နောက်၁မီနစ်တွင်"</item>
- <item quantity="other" msgid="3330713936399448749">"နောက် <xliff:g id="COUNT">%d</xliff:g> မိနစ်တွင်"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"နောက်၁နာရီတွင်"</item>
- <item quantity="other" msgid="547290677353727389">"နောက် <xliff:g id="COUNT">%d</xliff:g> နာရီတွင်"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"မနက်ဖြန်"</item>
- <item quantity="other" msgid="5109449375100953247">"နောက် <xliff:g id="COUNT">%d</xliff:g> ရက်တွင်"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"လွန်ခဲ့သော ၁စက္ကန့်က"</item>
- <item quantity="other" msgid="3699169366650930415">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> စက္ကန့်က"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"လွန်ခဲ့သော ၁မိနစ်က"</item>
- <item quantity="other" msgid="851164968597150710">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> မိနစ်က"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"လွန်ခဲ့သော ၁နာရီက"</item>
- <item quantity="other" msgid="6889970745748538901">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> နာရီက"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"မနေ့က"</item>
- <item quantity="other" msgid="3453342639616481191">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> ရက်တွင်"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"နောက် ၁စက္ကန့်တွင်"</item>
- <item quantity="other" msgid="5495880108825805108">"နောက် <xliff:g id="COUNT">%d</xliff:g> စက္ကန့်တွင်"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"နောက်၁မိနစ်တွင်"</item>
- <item quantity="other" msgid="4216113292706568726">"နောက် <xliff:g id="COUNT">%d</xliff:g> မိနစ်တွင်"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"နောက်၁နာရီတွင်"</item>
- <item quantity="other" msgid="3705373766798013406">"နောက် <xliff:g id="COUNT">%d</xliff:g> နာရီတွင်"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"မနက်ဖြန်"</item>
- <item quantity="other" msgid="2973062968038355991">"နောက် <xliff:g id="COUNT">%d</xliff:g> ရက်တွင်"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> တွင်"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>မှာ"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>တွင်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 35147e4..1b14de1 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ber om aktivering av Utforsk ved å trykke. Når Utforsk ved å trykke er slått på, kan du høre eller se beskrivelser av det som er under fingrene dine. Du kan også utføre handlinger på nettbrettet ved hjelp av bevegelser."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"For én måned siden"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"For over en måned siden"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"for et sekund siden"</item>
- <item quantity="other" msgid="3903706804349556379">"for <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"for et minutt siden"</item>
- <item quantity="other" msgid="2176942008915455116">"for <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"for en time siden"</item>
- <item quantity="other" msgid="2467273239587587569">"for <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Forrige måned"</string>
<string name="older" msgid="5211975022815554840">"Eldre"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"i går"</item>
- <item quantity="other" msgid="2479586466153314633">"for <xliff:g id="COUNT">%d</xliff:g> dager siden"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"om et sekund"</item>
- <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"om et minutt"</item>
- <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"om et minutt"</item>
- <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"i morgen"</item>
- <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dager"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 sek siden"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sek siden"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 min siden"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min siden"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 t siden"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> t siden"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"i går"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> d siden"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"om 1 sek"</item>
- <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"om 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"om 1 t"</item>
- <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> t"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"i morgen"</item>
- <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> d"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"kl. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"i <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 093f3c9..da70149 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>ले स्पर्षद्वारा अन्वेषण सक्षम गर्न चाहन्छ। स्पर्षद्वारा अन्वेषण सक्षम भएको बेला तपाईँ आफ्नो औँलाको मुनि भएका विषयवस्तुहरू बारे सुन्न वा विवरण हेर्न सक्नुहुन्छ वा फोनसँग अन्तर्क्रिया गर्न इशारा गर्नुहोस्।"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"१ महिना अघि"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"१ महिना अघि"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"१ सेकेन्ड अघि"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्ड अघि"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"१ मिनेट अघि"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> मिनेट अघि"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"१ घन्टा अघि"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> घन्टा अघि"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"अन्तिम महिना"</string>
<string name="older" msgid="5211975022815554840">"पुरानो"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"हिजो"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> दिन अघि"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"१ सेकेन्डमा"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्डमा"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"१ मिनेटमा"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>मिनेटमा"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"१ घन्टामा"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> घन्टामा"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"भोलि"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> दिनमा"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"१ सेकेन्ड अघि"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्ड अगाडि"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"१ मिनेट अघि"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> मिनेट अघि"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"१ घन्टा अघि"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> घन्टा अघि"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"हिजो"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> दिन अघि"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"१ सेकन्ड"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्डमा"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"१ मिनेटमा"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> मिनेटमा"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"१ घन्टामा"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> घन्टामा"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"भोलि"</item>
- <item quantity="other" msgid="2973062968038355991">"दिन<xliff:g id="COUNT">%d</xliff:g> मा"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> मा"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> मा"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> मा"</string>
diff --git a/core/res/res/values-night/themes_material_daynight.xml b/core/res/res/values-night/themes_material_daynight.xml
new file mode 100644
index 0000000..da870b7
--- /dev/null
+++ b/core/res/res/values-night/themes_material_daynight.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see themes_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+<resources>
+
+ <!-- Material theme (day/night version) for activities. -->
+ <style name="Theme.Material.DayNight" parent="Theme.Material" />
+
+ <!-- Variant of Material.DayNight that has a solid (opaque) action bar
+ with an inverse color profile. The dark action bar sharply stands out against
+ the light content (when applicable). -->
+ <style name="Theme.Material.DayNight.DarkActionBar" parent="Theme.Material" />
+
+ <!-- Variant of Material.DayNight with no action bar. -->
+ <style name="Theme.Material.DayNight.NoActionBar" parent="Theme.Material.NoActionBar" />
+
+ <!-- Variant of Material.DayNight that has no title bar and fills
+ the entire screen. This theme
+ sets {@link android.R.attr#windowFullscreen} to true. -->
+ <style name="Theme.Material.DayNight.NoActionBar.Fullscreen" parent="Theme.Material.NoActionBar.Fullscreen" />
+
+ <!-- Variant of Material.DayNight that has no title bar and fills
+ the entire screen and extends into the display overscan region. This theme
+ sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
+ to true. -->
+ <style name="Theme.Material.DayNight.NoActionBar.Overscan" parent="Theme.Material.NoActionBar.Overscan" />
+
+ <!-- Variant of Material.DayNight that has no title bar and translucent
+ system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
+ {@link android.R.attr#windowTranslucentNavigation} to true. -->
+ <style name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" parent="Theme.Material.NoActionBar.TranslucentDecor" />
+
+ <!-- Default Material.DayNight theme for panel windows. This removes all extraneous
+ window decorations, so you basically have an empty rectangle in which
+ to place your content. It makes the window floating, with a transparent
+ background, and turns off dimming behind the window. -->
+ <style name="Theme.Material.DayNight.Panel" parent="Theme.Material.Panel" />
+
+ <!-- Material theme (day/night version) for dialog windows and activities,
+ which is used by the {@link android.app.Dialog} class. This changes
+ the window to be floating (not fill the entire screen), and puts a
+ frame around its contents. You can set this theme on an activity if
+ you would like to make an activity that looks like a Dialog. -->
+ <style name="Theme.Material.DayNight.Dialog" parent="Theme.Material.DayNight.BaseDialog" />
+ <style name="Theme.Material.DayNight.BaseDialog" parent="Theme.Material.BaseDialog" />
+
+ <!-- Variant of Theme.Material.DayNight.Dialog that has a nice minimum width for
+ a regular dialog. -->
+ <style name="Theme.Material.DayNight.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth" />
+
+ <!-- Variant of Theme.Material.DayNight.Dialog that does not include a title bar. -->
+ <style name="Theme.Material.DayNight.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar" />
+
+ <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a nice minimum width for
+ a regular dialog. -->
+ <style name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth" />
+
+ <!-- Variant of Theme.Material.DayNight.Dialog that has a fixed size. -->
+ <style name="Theme.Material.DayNight.Dialog.FixedSize" parent="Theme.Material.Dialog.FixedSize" />
+
+ <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a fixed size. -->
+ <style name="Theme.Material.DayNight.Dialog.NoActionBar.FixedSize" parent="Theme.Material.Dialog.NoActionBar.FixedSize" />
+
+ <!-- Theme for a window that will be displayed either full-screen on
+ smaller screens (small, normal) or as a dialog on larger screens
+ (large, xlarge). -->
+ <style name="Theme.Material.DayNight.DialogWhenLarge" parent="Theme.Material.DialogWhenLarge" />
+
+ <!-- Theme for a window without an action bar that will be displayed either full-screen
+ on smaller screens (small, normal) or as a dialog on larger screens
+ (large, xlarge). -->
+ <style name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" parent="Theme.Material.DialogWhenLarge.NoActionBar" />
+
+ <!-- Theme for a presentation window on a secondary display. -->
+ <style name="Theme.Material.DayNight.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation" />
+
+ <!-- Material user theme for alert dialog windows, which is used by the
+ {@link android.app.AlertDialog} class. -->
+ <style name="Theme.Material.DayNight.Dialog.Alert" parent="Theme.Material.DayNight.Dialog.BaseAlert" />
+ <style name="Theme.Material.DayNight.Dialog.BaseAlert" parent="Theme.Material.Dialog.BaseAlert" />
+
+ <style name="Theme.Material.DayNight.SearchBar" parent="Theme.Material.SearchBar" />
+ <style name="Theme.Material.DayNight.CompactMenu" parent="Theme.Material.CompactMenu" />
+
+</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 0aff8604..c4bb334 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wil \'Verkennen via aanraking\' inschakelen. Wanneer \'Verkennen via aanraking\' is ingeschakeld, kunt u beschrijvingen beluisteren of bekijken van wat er onder uw vinger staat of aanraakbewerkingen uitvoeren op de telefoon."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 maand geleden"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Meer dan 1 maand geleden"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 seconde geleden"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minuut geleden"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 uur geleden"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Afgelopen maand"</string>
<string name="older" msgid="5211975022815554840">"Ouder"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"gisteren"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"over 1 seconde"</item>
- <item quantity="other" msgid="1241926116443974687">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"over 1 minuut"</item>
- <item quantity="other" msgid="3330713936399448749">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"over 1 uur"</item>
- <item quantity="other" msgid="547290677353727389">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"morgen"</item>
- <item quantity="other" msgid="5109449375100953247">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 seconde geleden"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 minuut geleden"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 uur geleden"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"gisteren"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"over 1 seconde"</item>
- <item quantity="other" msgid="5495880108825805108">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"over 1 minuut"</item>
- <item quantity="other" msgid="4216113292706568726">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"over 1 uur"</item>
- <item quantity="other" msgid="3705373766798013406">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"morgen"</item>
- <item quantity="other" msgid="2973062968038355991">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"op <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"om <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"in <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 2b25918..ac14db8 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> chce włączyć Czytanie dotykiem. Gdy ta funkcja jest włączona, słyszysz i widzisz opisy elementów, które są pod Twoim palcem, oraz możesz obsługiwać telefon gestami."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 miesiąc temu"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ponad 1 miesiąc temu"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"sekundę temu"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sek. temu"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minutę temu"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> min temu"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"godzinę temu"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> godz. temu"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Ostatni miesiąc"</string>
<string name="older" msgid="5211975022815554840">"Starsze"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"wczoraj"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"za sekundę"</item>
- <item quantity="other" msgid="1241926116443974687">"za <xliff:g id="COUNT">%d</xliff:g> sek."</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"za minutę"</item>
- <item quantity="other" msgid="3330713936399448749">"za <xliff:g id="COUNT">%d</xliff:g> min."</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"za godzinę"</item>
- <item quantity="other" msgid="547290677353727389">"za <xliff:g id="COUNT">%d</xliff:g> godzin"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"jutro"</item>
- <item quantity="other" msgid="5109449375100953247">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"sekundę temu"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> s temu"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"minutę temu"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min temu"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"godzinę temu"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> godz. temu"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"wczoraj"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"za sekundę"</item>
- <item quantity="other" msgid="5495880108825805108">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"za minutę"</item>
- <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"za godzinę"</item>
- <item quantity="other" msgid="3705373766798013406">"za <xliff:g id="COUNT">%d</xliff:g> godz."</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"jutro"</item>
- <item quantity="other" msgid="2973062968038355991">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"w dniu <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"o godzinie <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"w <xliff:g id="YEAR">%s</xliff:g> r."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 041847d..87c4dcc 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> pretende ativar a funcionalidade Explorar Através do Toque. Quando a funcionalidade Explorar Através do Toque estiver ativada, pode ouvir ou visualizar descrições sobre o que está por baixo do seu dedo ou executar gestos para interagir com o telemóvel."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Há 1 mês"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Há mais de 1 mês"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Há 1 segundo"</item>
- <item quantity="other" msgid="3903706804349556379">"Há <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Há 1 minuto"</item>
- <item quantity="other" msgid="2176942008915455116">"Há <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Há 1 hora"</item>
- <item quantity="other" msgid="2467273239587587569">"Há <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Último mês"</string>
<string name="older" msgid="5211975022815554840">"Mais antiga"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ontem"</item>
- <item quantity="other" msgid="2479586466153314633">"Há <xliff:g id="COUNT">%d</xliff:g> dias"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"daqui a 1 segundo"</item>
- <item quantity="other" msgid="1241926116443974687">"daqui a <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"daqui a 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"daqui a <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"daqui a 1 hora"</item>
- <item quantity="other" msgid="547290677353727389">"daqui a <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"amanhã"</item>
- <item quantity="other" msgid="5109449375100953247">"daqui a <xliff:g id="COUNT">%d</xliff:g> dias"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"Há 1 seg"</item>
- <item quantity="other" msgid="3699169366650930415">"Há <xliff:g id="COUNT">%d</xliff:g> seg"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"há 1 min"</item>
- <item quantity="other" msgid="851164968597150710">"Há <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Há 1 hora"</item>
- <item quantity="other" msgid="6889970745748538901">"Há <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ontem"</item>
- <item quantity="other" msgid="3453342639616481191">"Há <xliff:g id="COUNT">%d</xliff:g> dias"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"daqui a 1 seg"</item>
- <item quantity="other" msgid="5495880108825805108">"daqui a <xliff:g id="COUNT">%d</xliff:g> seg"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"daqui a 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"daqui a <xliff:g id="COUNT">%d</xliff:g> min"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"daqui a 1 hora"</item>
- <item quantity="other" msgid="3705373766798013406">"em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"amanhã"</item>
- <item quantity="other" msgid="2973062968038355991">"daqui a <xliff:g id="COUNT">%d</xliff:g> dias"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"a <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"às <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"em <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 4ea2f18..f65b088 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quer ativar a exploração pelo toque. Com ela, você pode ouvir ou ver descrições do que está sob seu dedo e interagir com o telefone através de gestos."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 mês atrás"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Antes de 1 mês atrás"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 segundo atrás"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> segundos atrás"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minuto atrás"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 hora atrás"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Mês passado"</string>
<string name="older" msgid="5211975022815554840">"Mais antigos"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ontem"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"em 1 segundo"</item>
- <item quantity="other" msgid="1241926116443974687">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"em 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"em 1 hora"</item>
- <item quantity="other" msgid="547290677353727389">"Em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"amanhã"</item>
- <item quantity="other" msgid="5109449375100953247">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 seg. atrás"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> segundos atrás"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 minuto atrás"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 hora atrás"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ontem"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"em 1 segundo"</item>
- <item quantity="other" msgid="5495880108825805108">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"em 1 minuto"</item>
- <item quantity="other" msgid="4216113292706568726">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"em 1 hora"</item>
- <item quantity="other" msgid="3705373766798013406">"em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"amanhã"</item>
- <item quantity="other" msgid="2973062968038355991">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"em <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"às <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"em <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 031b983..018d3b0 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modul Avion este ACTIVAT"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modul avion este DEZACTIVAT"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Setări"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistent vocal"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Blocați acum"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
@@ -1132,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcţie este activată, puteţi auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteţi efectua gesturi pentru a interacţiona cu telefonul."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"cu 1 lună în urmă"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Cu mai mult de 1 lună în urmă"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"cu 1 secundă în urmă"</item>
- <item quantity="other" msgid="3903706804349556379">"cu <xliff:g id="COUNT">%d</xliff:g> (de) secunde în urmă"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"cu 1 minut în urmă"</item>
- <item quantity="other" msgid="2176942008915455116">"cu <xliff:g id="COUNT">%d</xliff:g> (de) minute în urmă"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"cu 1 oră în urmă"</item>
- <item quantity="other" msgid="2467273239587587569">"cu <xliff:g id="COUNT">%d</xliff:g> (de) ore în urmă"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Luna trecută"</string>
<string name="older" msgid="5211975022815554840">"Mai vechi"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ieri"</item>
- <item quantity="other" msgid="2479586466153314633">"cu <xliff:g id="COUNT">%d</xliff:g> (de) zile în urmă"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"într-o secundă"</item>
- <item quantity="other" msgid="1241926116443974687">"în <xliff:g id="COUNT">%d</xliff:g> (de) secunde"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"în 1 minut"</item>
- <item quantity="other" msgid="3330713936399448749">"în <xliff:g id="COUNT">%d</xliff:g> (de) minute"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"în 1 oră"</item>
- <item quantity="other" msgid="547290677353727389">"în <xliff:g id="COUNT">%d</xliff:g> (de) ore"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"mâine"</item>
- <item quantity="other" msgid="5109449375100953247">"în <xliff:g id="COUNT">%d</xliff:g> (de) zile"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"cu 1 sec. în urmă"</item>
- <item quantity="other" msgid="3699169366650930415">"cu <xliff:g id="COUNT">%d</xliff:g> (de) secunde în urmă"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"cu 1 min. în urmă"</item>
- <item quantity="other" msgid="851164968597150710">"cu <xliff:g id="COUNT">%d</xliff:g> (de) min. în urmă"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"cu 1 oră în urmă"</item>
- <item quantity="other" msgid="6889970745748538901">"cu <xliff:g id="COUNT">%d</xliff:g> (de) ore în urmă"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ieri"</item>
- <item quantity="other" msgid="3453342639616481191">"cu <xliff:g id="COUNT">%d</xliff:g> (de) zile în urmă"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"în 1 sec."</item>
- <item quantity="other" msgid="5495880108825805108">"în <xliff:g id="COUNT">%d</xliff:g> (de) sec."</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"în 1 min."</item>
- <item quantity="other" msgid="4216113292706568726">"în <xliff:g id="COUNT">%d</xliff:g> (de) min."</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"în 1 oră"</item>
- <item quantity="other" msgid="3705373766798013406">"în <xliff:g id="COUNT">%d</xliff:g> (de) ore"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"mâine"</item>
- <item quantity="other" msgid="2973062968038355991">"în <xliff:g id="COUNT">%d</xliff:g> (de) zile"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"pe <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"la <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"în <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 608407d..c613d55 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Выключить"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Включить"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Настройки"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Аудиоподсказки"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Заблокировать"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
@@ -1132,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> хочет включить функцию \"Аудиоподсказки\". Она позволяет прослушивать или просматривать описание элементов, которых вы касаетесь, и управлять телефоном с помощью жестов."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 месяц назад"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Более месяца назад"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 секунду назад"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> с. назад"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 минуту назад"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 час назад"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Прошлый месяц"</string>
<string name="older" msgid="5211975022815554840">"Еще раньше"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"вчера"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"через 1 секунду"</item>
- <item quantity="other" msgid="1241926116443974687">"через <xliff:g id="COUNT">%d</xliff:g> с."</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"через 1 минуту"</item>
- <item quantity="other" msgid="3330713936399448749">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"через 1 час"</item>
- <item quantity="other" msgid="547290677353727389">"через <xliff:g id="COUNT">%d</xliff:g> ч."</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"завтра"</item>
- <item quantity="other" msgid="5109449375100953247">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 сек. назад"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> сек. назад"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 мин. назад"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 час назад"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"вчера"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"через 1 с."</item>
- <item quantity="other" msgid="5495880108825805108">"через <xliff:g id="COUNT">%d</xliff:g> с."</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"через 1 мин."</item>
- <item quantity="other" msgid="4216113292706568726">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"через 1 час"</item>
- <item quantity="other" msgid="3705373766798013406">"через <xliff:g id="COUNT">%d</xliff:g> ч."</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"завтра"</item>
- <item quantity="other" msgid="2973062968038355991">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"в <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"в <xliff:g id="YEAR">%s</xliff:g> г."</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index b7ccd99..af55f75 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -1133,73 +1133,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"ස්පර්ශය වෙතින් ගවේෂණය සක්රිය කිරීමට <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ට අවශ්යයි. ස්පර්ශය වෙතින් ගවේෂණය සක්රිය විට, ඔබගේ ඇඟිලිවලට පහළ විස්තර ඇසිය හෝ බැලිය හැක හෝ දුරකථනය සමග අන්තර් ක්රියාකාරී වීමට ඉංගිති සිදු කළ හැක."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"මාස 1 කට පෙර"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"මාස 1 කට පෙර"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"තත්පර 1 කට පෙර"</item>
- <item quantity="other" msgid="3903706804349556379">"තත්පර <xliff:g id="COUNT">%d</xliff:g> ට පෙර"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"මිනිත්තු 1 ට පෙර"</item>
- <item quantity="other" msgid="2176942008915455116">"මිනිත්තු <xliff:g id="COUNT">%d</xliff:g> කට පෙර"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"පැය 1 කට පෙර"</item>
- <item quantity="other" msgid="2467273239587587569">"පැය <xliff:g id="COUNT">%d</xliff:g> කට පෙර"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"අවසාන මාසය"</string>
<string name="older" msgid="5211975022815554840">"පරණ"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ඊයේ"</item>
- <item quantity="other" msgid="2479586466153314633">"දින <xliff:g id="COUNT">%d</xliff:g> කට පෙර"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"තත්පර 1 කින්"</item>
- <item quantity="other" msgid="1241926116443974687">"තත්පර <xliff:g id="COUNT">%d</xliff:g> කදී"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"මිනිත්තු 1 කදී"</item>
- <item quantity="other" msgid="3330713936399448749">"මිනිත්තු <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"පැය 1 ක් තුළ"</item>
- <item quantity="other" msgid="547290677353727389">"පැය <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"හෙට"</item>
- <item quantity="other" msgid="5109449375100953247">"දින <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"තත්පර 1 කට පෙර"</item>
- <item quantity="other" msgid="3699169366650930415">"තත්පර <xliff:g id="COUNT">%d</xliff:g> කට පෙර"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"මිනිත්තු 1 කට පෙර"</item>
- <item quantity="other" msgid="851164968597150710">"මිනිත්තු <xliff:g id="COUNT">%d</xliff:g> ට පෙර"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"පැය 1 කට පෙර"</item>
- <item quantity="other" msgid="6889970745748538901">"පැය <xliff:g id="COUNT">%d</xliff:g> ට පෙර"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ඊයේ"</item>
- <item quantity="other" msgid="3453342639616481191">"දින <xliff:g id="COUNT">%d</xliff:g> ට පෙර"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"තත්පර 1 ක් තුළ"</item>
- <item quantity="other" msgid="5495880108825805108">"තත්පර <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"මිනිත්තු 1 ක් තුළ"</item>
- <item quantity="other" msgid="4216113292706568726">"මිනිත්තු <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"පැය 1 ක් තුළ"</item>
- <item quantity="other" msgid="3705373766798013406">"පැය <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"හෙට"</item>
- <item quantity="other" msgid="2973062968038355991">"දින <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> වන දා"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> ට"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> තුළ"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 2a73770..312791b 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Služba <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> požaduje povolenie funkcie Preskúmanie dotykom. Ak je funkcia Preskúmanie dotykom zapnutá, môžete počuť alebo vidieť popisy objektov pod vaším prstom alebo ovládať telefón gestami."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"pred 1 mesiacom"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Viac ako pred 1 mesiacom"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"pred 1 sekundou"</item>
- <item quantity="other" msgid="3903706804349556379">"pred <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Pred minútou"</item>
- <item quantity="other" msgid="2176942008915455116">"pred <xliff:g id="COUNT">%d</xliff:g> minútami"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"pred 1 hodinou"</item>
- <item quantity="other" msgid="2467273239587587569">"pred <xliff:g id="COUNT">%d</xliff:g> hodinami"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Minulý mesiac"</string>
<string name="older" msgid="5211975022815554840">"Staršie"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"včera"</item>
- <item quantity="other" msgid="2479586466153314633">"pred <xliff:g id="COUNT">%d</xliff:g> dňami"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"o 1 sekundu"</item>
- <item quantity="other" msgid="1241926116443974687">"o <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"o 1 minútu"</item>
- <item quantity="other" msgid="3330713936399448749">"o <xliff:g id="COUNT">%d</xliff:g> minút"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"o 1 hodinu"</item>
- <item quantity="other" msgid="547290677353727389">"o <xliff:g id="COUNT">%d</xliff:g> hodín"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"zajtra"</item>
- <item quantity="other" msgid="5109449375100953247">"o <xliff:g id="COUNT">%d</xliff:g> dní"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"pred 1 s"</item>
- <item quantity="other" msgid="3699169366650930415">"pred <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"pred 1 min."</item>
- <item quantity="other" msgid="851164968597150710">"pred <xliff:g id="COUNT">%d</xliff:g> min."</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"pred 1 hodinou"</item>
- <item quantity="other" msgid="6889970745748538901">"pred <xliff:g id="COUNT">%d</xliff:g> hodinami"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"včera"</item>
- <item quantity="other" msgid="3453342639616481191">"pred <xliff:g id="COUNT">%d</xliff:g> dňami"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"o 1 s"</item>
- <item quantity="other" msgid="5495880108825805108">"o <xliff:g id="COUNT">%d</xliff:g> s"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"o 1 min."</item>
- <item quantity="other" msgid="4216113292706568726">"o <xliff:g id="COUNT">%d</xliff:g> min."</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"o 1 hodinu"</item>
- <item quantity="other" msgid="3705373766798013406">"o <xliff:g id="COUNT">%d</xliff:g> hodín"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"zajtra"</item>
- <item quantity="other" msgid="2973062968038355991">"o <xliff:g id="COUNT">%d</xliff:g> dní"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"dňa <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"o <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"z <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index bc8a851..df365fd 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Storitev <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> želi omogočiti raziskovanje z dotikom. Ko je raziskovanje z dotikom vklopljeno, lahko slišite ali vidite opise tega, kar je pod vašim prstom, ali izvajate poteze za interakcijo s telefonom."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Pred 1 mesecem"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Pred več kot 1 mesecem"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Pred 1 sekundo"</item>
- <item quantity="other" msgid="3903706804349556379">"pred toliko sekundami: <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"pred 1 minuto"</item>
- <item quantity="other" msgid="2176942008915455116">"Pred <xliff:g id="COUNT">%d</xliff:g> minutami"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"pred 1 uro"</item>
- <item quantity="other" msgid="2467273239587587569">"Pred <xliff:g id="COUNT">%d</xliff:g> urami"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Pretekli mesec"</string>
<string name="older" msgid="5211975022815554840">"Starejše"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"včeraj"</item>
- <item quantity="other" msgid="2479586466153314633">"Pred <xliff:g id="COUNT">%d</xliff:g> dnevi"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"čez 1 sekundo"</item>
- <item quantity="other" msgid="1241926116443974687">"Čez <xliff:g id="COUNT">%d</xliff:g> sekund"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"čez 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"Čez toliko minut: <xliff:g id="COUNT">%d</xliff:g>."</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"čez 1 uro"</item>
- <item quantity="other" msgid="547290677353727389">"čez <xliff:g id="COUNT">%d</xliff:g> ur"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"jutri"</item>
- <item quantity="other" msgid="5109449375100953247">"čez <xliff:g id="COUNT">%d</xliff:g> dni"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"pred 1 sekundo"</item>
- <item quantity="other" msgid="3699169366650930415">"Pred toliko sekundami: <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"pred 1 minuto"</item>
- <item quantity="other" msgid="851164968597150710">"Pred <xliff:g id="COUNT">%d</xliff:g> minutami"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"pred 1 uro"</item>
- <item quantity="other" msgid="6889970745748538901">"Pred <xliff:g id="COUNT">%d</xliff:g> urami"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"včeraj"</item>
- <item quantity="other" msgid="3453342639616481191">"Pred <xliff:g id="COUNT">%d</xliff:g> dnevi"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"čez 1 sekundo"</item>
- <item quantity="other" msgid="5495880108825805108">"čez toliko sekund: <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"čez 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"čez <xliff:g id="COUNT">%d</xliff:g> minut"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"čez 1 uro"</item>
- <item quantity="other" msgid="3705373766798013406">"čez <xliff:g id="COUNT">%d</xliff:g> ur"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"jutri"</item>
- <item quantity="other" msgid="2973062968038355991">"čez <xliff:g id="COUNT">%d</xliff:g> dni"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"vsak <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"ob <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"leta <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 6d1e793..8277f33 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> жели да омогући Истраживање додиром. Када је Истраживање додиром укључено, можете да чујете или видите описе ставке на коју сте ставили прст или да комуницирате са телефоном помоћу покрета."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Пре месец дана"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Пре месец дана"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Пре 1 секунде"</item>
- <item quantity="other" msgid="3903706804349556379">"пре <xliff:g id="COUNT">%d</xliff:g> секунде(и)"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Пре једног минута"</item>
- <item quantity="other" msgid="2176942008915455116">"пре <xliff:g id="COUNT">%d</xliff:g> минута"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Пре сат времена"</item>
- <item quantity="other" msgid="2467273239587587569">"пре <xliff:g id="COUNT">%d</xliff:g> сата(и)"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Прошлог месеца"</string>
<string name="older" msgid="5211975022815554840">"Старије"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"јуче"</item>
- <item quantity="other" msgid="2479586466153314633">"пре <xliff:g id="COUNT">%d</xliff:g> дана"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"за 1 секунду"</item>
- <item quantity="other" msgid="1241926116443974687">"за <xliff:g id="COUNT">%d</xliff:g> секунде(и)"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"за 1 минут"</item>
- <item quantity="other" msgid="3330713936399448749">"за <xliff:g id="COUNT">%d</xliff:g> минута"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"за 1 сат"</item>
- <item quantity="other" msgid="547290677353727389">"за <xliff:g id="COUNT">%d</xliff:g> сата(и)"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"сутра"</item>
- <item quantity="other" msgid="5109449375100953247">"за <xliff:g id="COUNT">%d</xliff:g> дана"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"Пре једне сек"</item>
- <item quantity="other" msgid="3699169366650930415">"пре <xliff:g id="COUNT">%d</xliff:g> сек"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"Пре један мин"</item>
- <item quantity="other" msgid="851164968597150710">"пре <xliff:g id="COUNT">%d</xliff:g> мин"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Пре сат времена"</item>
- <item quantity="other" msgid="6889970745748538901">"пре <xliff:g id="COUNT">%d</xliff:g> сата(и)"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"јуче"</item>
- <item quantity="other" msgid="3453342639616481191">"пре <xliff:g id="COUNT">%d</xliff:g> дана"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"за 1 сек"</item>
- <item quantity="other" msgid="5495880108825805108">"за <xliff:g id="COUNT">%d</xliff:g> сек"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"за 1 мин"</item>
- <item quantity="other" msgid="4216113292706568726">"за <xliff:g id="COUNT">%d</xliff:g> мин"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"за 1 сат"</item>
- <item quantity="other" msgid="3705373766798013406">"за <xliff:g id="COUNT">%d</xliff:g> сата(и)"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"сутра"</item>
- <item quantity="other" msgid="2973062968038355991">"за <xliff:g id="COUNT">%d</xliff:g> дана"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"дана <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"у <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"у <xliff:g id="YEAR">%s</xliff:g>."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 61b0a3d..f31ba4d 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vill aktivera Explore by Touch. När funktionen är aktiv kan du höra eller se beskrivningar av vad du har under fingret eller utföra gester för att göra saker med telefonen."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"för 1 månad sedan"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"För mer än en månad sedan"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"för 1 sekund sedan"</item>
- <item quantity="other" msgid="3903706804349556379">"för <xliff:g id="COUNT">%d</xliff:g> sekunder sedan"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"för 1 minut sedan"</item>
- <item quantity="other" msgid="2176942008915455116">"för <xliff:g id="COUNT">%d</xliff:g> minuter sedan"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"för 1 timme sedan"</item>
- <item quantity="other" msgid="2467273239587587569">"för <xliff:g id="COUNT">%d</xliff:g> timmar sedan"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Föregående månad"</string>
<string name="older" msgid="5211975022815554840">"Äldre"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"igår"</item>
- <item quantity="other" msgid="2479586466153314633">"för <xliff:g id="COUNT">%d</xliff:g> dagar sedan"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"om 1 sekund"</item>
- <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"om 1 minut"</item>
- <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minuter"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"om 1 timme"</item>
- <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timmar"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"imorgon"</item>
- <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dagar"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"för 1 sek sedan"</item>
- <item quantity="other" msgid="3699169366650930415">"för <xliff:g id="COUNT">%d</xliff:g> sekunder sedan"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"för 1 minut sedan"</item>
- <item quantity="other" msgid="851164968597150710">"för <xliff:g id="COUNT">%d</xliff:g> minuter sedan"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"för 1 timme sedan"</item>
- <item quantity="other" msgid="6889970745748538901">"för <xliff:g id="COUNT">%d</xliff:g> timmar sedan"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"igår"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dagar sedan"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"om 1 sekund"</item>
- <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"om 1 minut"</item>
- <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> minuter"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"om 1 timme"</item>
- <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> timmar"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"imorgon"</item>
- <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> dagar"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"den <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"kl. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 9a97e24..5e57cc1 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> inataka kuwezesha Kuchunguza kwa Kugusa. Wakati Kuchunguza kwa Kugusa kumewezeshwa, unaweza kusikia au kuona maelezo ya kilicho chini ya kidole chako au kutumia ishara ili kuingiliana na simu."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Mwezi 1 uliopita"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Kabla ya mwezi 1 uliopita"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Sekunde 1 iliopita"</item>
- <item quantity="other" msgid="3903706804349556379">"sekunde <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Dakika 1 iliyopita"</item>
- <item quantity="other" msgid="2176942008915455116">"Dakika <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Saa 1 iliyopita"</item>
- <item quantity="other" msgid="2467273239587587569">"Saa <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Mwezi uliopita"</string>
<string name="older" msgid="5211975022815554840">"Kuukuu zaidi"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"jana"</item>
- <item quantity="other" msgid="2479586466153314633">"siku <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"kati ya sekunde 1"</item>
- <item quantity="other" msgid="1241926116443974687">"kati ya sekunde <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"kati ya dakika 1"</item>
- <item quantity="other" msgid="3330713936399448749">"baada ya dakika <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"kati ya saa 1"</item>
- <item quantity="other" msgid="547290677353727389">"kati ya saa <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"kesho"</item>
- <item quantity="other" msgid="5109449375100953247">"katika siku <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"Sekunde 1 iliyopita"</item>
- <item quantity="other" msgid="3699169366650930415">"Sekunde <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"Dakika 1 iliyopita"</item>
- <item quantity="other" msgid="851164968597150710">"Dakika <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Saa 1 iliyopita"</item>
- <item quantity="other" msgid="6889970745748538901">"Saa <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"jana"</item>
- <item quantity="other" msgid="3453342639616481191">"siku <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"kati ya sekunde 1"</item>
- <item quantity="other" msgid="5495880108825805108">"kati ya sekunde <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"baada ya dakika 1"</item>
- <item quantity="other" msgid="4216113292706568726">"kati ya dakika<xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"kati ya saa 1"</item>
- <item quantity="other" msgid="3705373766798013406">"katika saa <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"kesho"</item>
- <item quantity="other" msgid="2973062968038355991">"kati ya siku <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"tarehe <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"Saa <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"ndani ya <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 03ffc98..14a0e67 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"தொடுவதன் மூலம் அறிக என்பதை இயக்க <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> விரும்புகிறது. தொடுவதன் மூலம் அறிக என்பது இயக்கப்பட்டிருக்கும்போது, உங்கள் விரலுக்கு அடியில் இருப்பவையின் விளக்கங்களை நீங்கள் கேட்கவோ, பார்க்கவோ செய்யலாம் அல்லது மொபைலுடன் ஊடாட சைகைகளை மேற்கொள்ளலாம்."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 மாதத்திற்கு முன்பு"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 மாதத்திற்கு முன்பு"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 வினாடிக்கு முன்பு"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகளுக்கு முன்பு"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 நிமிடம் முன்பு"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> நிமிடத்திற்கு முன்"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 மணிநேரம் முன்பு"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> மணிநேரத்திற்கு முன்பு"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"சென்ற மாதம்"</string>
<string name="older" msgid="5211975022815554840">"பழையது"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"நேற்று"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> நாட்களுக்கு முன்பு"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 வினாடியில்"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகளில்"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 நிமிடத்தில்"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> நிமிடங்களில்"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 மணிநேரத்தில்"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> மணிநேரத்தில்"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"நாளை"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> நாட்களில்"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 வினாடி முன்பு"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகளுக்கு முன்பு"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 நிமிடம் முன்பு"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> நிமிடத்திற்கு முன்"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 மணிநேரம் முன்பு"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> மணிநேரத்திற்கு முன்பு"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"நேற்று"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> நாட்களுக்கு முன்பு"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 வினாடியில்"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகளில்"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 நிமிடத்தில்"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> நிமிடங்களில்"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 மணிநேரத்தில்"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> மணிநேரத்தில்"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"நாளை"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> நாட்களில்"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> அன்று"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> இல்"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> இல்"</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 2c80adb..72df68b 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> తాకడం ద్వారా విశ్లేషణను ప్రారంభించాలనుకుంటోంది. తాకడం ద్వారా విశ్లేషణ ఆన్ చేయబడినప్పుడు, మీరు మీ వేలి క్రింద ఉన్నవాటి యొక్క వివరణలను వినవచ్చు లేదా చూడవచ్చు లేదా ఫోన్తో పరస్పర చర్య చేయడానికి సంజ్ఞలు చేయవచ్చు."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 నెల క్రితం"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 నెలకు ముందు"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 సెకను క్రితం"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> సెకన్ల క్రితం"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 నిమిషం క్రితం"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> నిమిషాల క్రితం"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 గంట క్రితం"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> గంటల క్రితం"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"గత నెల"</string>
<string name="older" msgid="5211975022815554840">"పాతది"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"నిన్న"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> రోజుల క్రితం"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 సెకనులో"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> సెకన్లలో"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 నిమిషంలో"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> నిమిషాల్లో"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 గంటలో"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> గంటల్లో"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"రేపు"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> రోజుల్లో"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 సెక క్రితం"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> సెక క్రితం"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 నిమి క్రితం"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> నిమి క్రితం"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 గంట క్రితం"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> గంటల క్రితం"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"నిన్న"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> రోజుల క్రితం"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 సెకనులో"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> సెకన్లలో"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 నిమిషంలో"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> నిమిషాల్లో"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 గంటలో"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> గంటల్లో"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"రేపు"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> రోజుల్లో"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>న"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>కి"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>లో"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index bb972e4..eaf0827 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ต้องการเปิดใช้งาน \"สำรวจโดยการแตะ\" เมื่อเปิดใช้งานแล้ว คุณสามารถฟังหรือดูคำอธิบายของสิ่งที่อยู่ใต้นิ้วของคุณ หรือใช้ท่าทางสัมผัสต่างๆ เพื่อโต้ตอบกับโทรศัพท์ได้"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 เดือนที่ผ่านมา"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ก่อน 1 เดือนที่แล้ว"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 วินาทีที่แล้ว"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> วินาทีที่แล้ว"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 นาทีที่ผ่านมา"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> นาทีที่ผ่านมา"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 ชั่วโมงที่ผ่านมา"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ชั่วโมงที่ผ่านมา"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"เดือนที่แล้ว"</string>
<string name="older" msgid="5211975022815554840">"เก่ากว่า"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"เมื่อวาน"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> วันที่ผ่านมา"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"ใน 1 วินาที"</item>
- <item quantity="other" msgid="1241926116443974687">"ใน <xliff:g id="COUNT">%d</xliff:g> วินาที"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"ใน 1 นาที"</item>
- <item quantity="other" msgid="3330713936399448749">"ใน <xliff:g id="COUNT">%d</xliff:g> นาที"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"ใน 1 ชั่วโมง"</item>
- <item quantity="other" msgid="547290677353727389">"ใน <xliff:g id="COUNT">%d</xliff:g> ชั่วโมง"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"พรุ่งนี้"</item>
- <item quantity="other" msgid="5109449375100953247">"ใน <xliff:g id="COUNT">%d</xliff:g> วัน"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 วินาทีที่แล้ว"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> วินาทีที่ผ่านมา"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 นาทีที่ผ่านมา"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> นาทีที่ผ่านมา"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 ชั่วโมงที่ผ่านมา"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ชั่วโมงที่ผ่านมา"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"เมื่อวาน"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> วันที่ผ่านมา"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"ใน 1 วินาที"</item>
- <item quantity="other" msgid="5495880108825805108">"ใน <xliff:g id="COUNT">%d</xliff:g> วินาที"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"ใน 1 นาที"</item>
- <item quantity="other" msgid="4216113292706568726">"ใน <xliff:g id="COUNT">%d</xliff:g> นาที"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"ใน 1 ชั่วโมง"</item>
- <item quantity="other" msgid="3705373766798013406">"ใน <xliff:g id="COUNT">%d</xliff:g> ชั่วโมง"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"พรุ่งนี้"</item>
- <item quantity="other" msgid="2973062968038355991">"ใน <xliff:g id="COUNT">%d</xliff:g> วัน"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"ในวันที่ <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"ที่ <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"ใน <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 97dda674..707402d 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Nais paganahin ng <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ang Galugarin sa pamamagitan ng pagpindot. Kapag naka-on ang Galugarin sa pamamagitan ng pagpindot, maaari mong marinig o makita ang mga paglalarawan ng nasa ilalim ng iyong daliri o maaari kang magsagawa ng mga galaw upang makipag-ugnayan sa telepono."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 buwan ang nakalipas"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Bago ang nakalipas na 1 buwan"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 segundo ang nakakalipas"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> (na) segundo ang nakalipas"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minuto ang nakalipas"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> (na) minuto ang nakalipas"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 oras ang nakalipas"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> (na) oras ang nakalipas"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Nakaraang buwan"</string>
<string name="older" msgid="5211975022815554840">"Mas luma"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"kahapon"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> (na) araw ang nakalipas"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"sa 1 segundo"</item>
- <item quantity="other" msgid="1241926116443974687">"sa <xliff:g id="COUNT">%d</xliff:g> (na) segundo"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"sa 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"sa <xliff:g id="COUNT">%d</xliff:g> (na) minuto"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"sa 1 oras"</item>
- <item quantity="other" msgid="547290677353727389">"sa <xliff:g id="COUNT">%d</xliff:g> (na) oras"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"bukas"</item>
- <item quantity="other" msgid="5109449375100953247">"sa <xliff:g id="COUNT">%d</xliff:g> (na) araw"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 segundo ang nakalipas"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> (na) segundo ang nakalipas"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 minuto ang nakalipas"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> (na) minuto ang nakalipas"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 oras ang nakalipas"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> (na) oras ang nakalipas"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"kahapon"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> (na) araw ang nakalipas"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"sa 1 seg"</item>
- <item quantity="other" msgid="5495880108825805108">"sa <xliff:g id="COUNT">%d</xliff:g> (na) segundo"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"sa 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"sa <xliff:g id="COUNT">%d</xliff:g> (na) minuto"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"sa 1 oras"</item>
- <item quantity="other" msgid="3705373766798013406">"sa <xliff:g id="COUNT">%d</xliff:g> (na) oras"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"bukas"</item>
- <item quantity="other" msgid="2973062968038355991">"sa <xliff:g id="COUNT">%d</xliff:g> (na) araw"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"sa <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"nang <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"sa <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ebc10da..36f6f8f 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uçak modu AÇIK"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Uçak modu KAPALI"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Ayarlar"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Ses Yardımı"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Şimdi kilitle"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
@@ -1132,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>, Dokunarak Keşfet özelliğini etkinleştirmek istiyor. Dokunarak Keşfet açık olduğunda parmağınızın altındaki öğelere ait açıklamaları duyabilir veya görebilir ya da telefonla etkileşimde bulunmak için birtakım hareketler yapabilirsiniz."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ay önce"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 ay önce"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 saniye önce"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> saniye önce"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 dakika önce"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> dakika önce"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 saat önce"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> saat önce"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Son ay"</string>
<string name="older" msgid="5211975022815554840">"Daha eski"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"dün"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> gün önce"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 saniye içinde"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 dakika içinde"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> dakika içinde"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 saat içinde"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> saat içinde"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"yarın"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> gün içinde"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 saniye önce"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> saniye önce"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 dak. önce"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> dakika önce"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 saat önce"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> saat önce"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"dün"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> gün önce"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 san. içinde"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 dak. içinde"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> dakika içinde"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 saat içinde"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> saat içinde"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"yarın"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> gün içinde"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> tarihinde"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> yılında"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 664976a6..1768942 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> хоче ввімкнути функцію дослідження дотиком. Увімкнувши функцію дослідження дотиком, можна чути або бачити опис елемента, розташованого під вашим пальцем, або виконувати жести для взаємодії з телефоном."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 міс. тому"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Раніше 1 місяця тому"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 сек. тому"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> сек. тому"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 хвилину тому"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> хв. тому"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 год. тому"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> год. тому"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Останній міс."</string>
<string name="older" msgid="5211975022815554840">"Давніше"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"учора"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> дн. тому"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"через 1 сек."</item>
- <item quantity="other" msgid="1241926116443974687">"через <xliff:g id="COUNT">%d</xliff:g> сек."</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"через 1 хв."</item>
- <item quantity="other" msgid="3330713936399448749">"через <xliff:g id="COUNT">%d</xliff:g> хв."</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"через 1 год."</item>
- <item quantity="other" msgid="547290677353727389">"через <xliff:g id="COUNT">%d</xliff:g> год."</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"завтра"</item>
- <item quantity="other" msgid="5109449375100953247">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 сек. тому"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> сек. тому"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 хв. тому"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> хв. тому"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 годину тому"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> год. тому"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"учора"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> дн. тому"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"через 1 с."</item>
- <item quantity="other" msgid="5495880108825805108">"через <xliff:g id="COUNT">%d</xliff:g> сек."</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"через 1 хв."</item>
- <item quantity="other" msgid="4216113292706568726">"через <xliff:g id="COUNT">%d</xliff:g> хв."</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"через 1 год."</item>
- <item quantity="other" msgid="3705373766798013406">"через <xliff:g id="COUNT">%d</xliff:g> год."</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"завтра"</item>
- <item quantity="other" msgid="2973062968038355991">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"о <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"у <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index edab739f..feecb77 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -200,7 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ہوائی جہاز وضع آن ہے"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ہوائی جہاز وضع آف ہے"</string>
<string name="global_action_settings" msgid="1756531602592545966">"ترتیبات"</string>
- <string name="global_action_voice_assist" msgid="7751191495200504480">"صوتی مدد"</string>
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ابھی مقفل کریں"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"حفاظتی وضع"</string>
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ٹچ کرکے دریافت کریں کو فعال کرنا چاہتی ہے۔ ٹچ کرکے دریافت کریں کے آن ہو جانے پر، آپ کو اپنی انگلی کے نیچے موجود چیزوں کی تفصیلات دکھائی یا سنائی دے سکتی ہیں یا آپ فون کے ساتھ تعامل کرنے کیلئے اشارے انجام دے سکتے ہیں۔"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 مہینہ پہلے"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 مہینہ سے زیادہ پہلے"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 سیکنڈ پہلے"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> سیکنڈ پہلے"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 منٹ پہلے"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> منٹ پہلے"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 گھنٹہ پہلے"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> گھنٹے پہلے"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"پچھلے مہینے"</string>
<string name="older" msgid="5211975022815554840">"پرانا"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"گزشتہ کل"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> دن پہلے"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 سیکنڈ میں"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> سیکنڈ میں"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 منٹ میں"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> منٹ میں"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 گھنٹہ میں"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> گھنٹے میں"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"آنے والا کل"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> دن میں"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 سیکنڈ پہلے"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> سیکنڈ پہلے"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 منٹ پہلے"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> منٹ پہلے"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 گھنٹہ پہلے"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> گھنٹے پہلے"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"گزشتہ کل"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> دن پہلے"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 سیکنڈ میں"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> سیکنڈ میں"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 منٹ میں"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> منٹ میں"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 گھنٹہ میں"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> گھنٹے میں"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"آنے والا کل"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> دن میں"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> کو"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"بوقت <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> میں"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 30164e1..721e9bc 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> teginib o‘rganish xususiyatini yoqishni xohlamoqda. Bu xususiyat yoqilganda, barmog‘ingiz ostidagi elementlar ta‘rifini ko‘rishingiz yoki eshitishingiz mumkin yoki telefon bilan o‘zaro bog‘lanish uchun barmog‘ingiz bilan imo-ishorali harakatlarni bajaring."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 oy oldin"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 oydan oldinroq"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 soniya oldin"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> soniya oldin"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 daqiqa oldin"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> daqiqa oldin"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 soat oldin"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> soat oldin"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"O‘tgan oy"</string>
<string name="older" msgid="5211975022815554840">"Eskiroq"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"kecha"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> kun oldin"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 soniyada"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> soniyada"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 daqiqada"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> daqiqada"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 soatda"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> soatda"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"ertaga"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> kunda"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 soniya oldin"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> soniya oldin"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 daq. oldin"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> daq. oldin"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 soat oldin"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> soat oldin"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"kecha"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> kun oldin"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 soniya da"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> soniya da"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 daq. da"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> daq. da"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 soatda"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> soatda"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"ertaga"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> kunda"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>da"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>da"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>da"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 2bf3819..9f7118e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> muốn bật Khám phá bằng cách chạm. Khi Khám phá bằng cách chạm được bật, bạn có thể nghe hoặc xem mô tả dưới ngón tay bạn hoặc thực hiện cử chỉ để tương tác với điện thoại."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 tháng trước"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Trước 1 tháng trước"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 giây trước"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> giây trước"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 phút trước"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> phút trước"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 giờ trước"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> giờ trước"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Tháng trước"</string>
<string name="older" msgid="5211975022815554840">"Cũ hơn"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"hôm qua"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ngày trước"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"trong 1 giây"</item>
- <item quantity="other" msgid="1241926116443974687">"trong <xliff:g id="COUNT">%d</xliff:g> giây"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"trong 1 phút"</item>
- <item quantity="other" msgid="3330713936399448749">"trong <xliff:g id="COUNT">%d</xliff:g> phút"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"trong 1 giờ"</item>
- <item quantity="other" msgid="547290677353727389">"trong <xliff:g id="COUNT">%d</xliff:g> giờ"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"ngày mai"</item>
- <item quantity="other" msgid="5109449375100953247">"trong <xliff:g id="COUNT">%d</xliff:g> ngày"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 giây trước"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> giây trước"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 phút trước"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> phút trước"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 giờ trước"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> giờ trước"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"hôm qua"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ngày trước"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"trong 1 giây"</item>
- <item quantity="other" msgid="5495880108825805108">"trong <xliff:g id="COUNT">%d</xliff:g> giây"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"trong 1 phút"</item>
- <item quantity="other" msgid="4216113292706568726">"trong <xliff:g id="COUNT">%d</xliff:g> phút"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"trong 1 giờ"</item>
- <item quantity="other" msgid="3705373766798013406">"trong <xliff:g id="COUNT">%d</xliff:g> giờ"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"ngày mai"</item>
- <item quantity="other" msgid="2973062968038355991">"trong <xliff:g id="COUNT">%d</xliff:g> ngày"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"vào <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"vào lúc <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"trong <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index f1a4fb31..4d8db93 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"已开启飞行模式"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"未开启飞行模式"</string>
<string name="global_action_settings" msgid="1756531602592545966">"设置"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"语音助理"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"立即锁定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
@@ -1132,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>想要启用“触摸浏览”。“触摸浏览”启用后,您可以听到或看到所触摸内容的说明,还可以通过手势操作与手机互动。"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 个月前"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 个月前"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1秒前"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1分钟前"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g>分钟前"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1小时前"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g>小时前"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"上个月"</string>
<string name="older" msgid="5211975022815554840">"往前"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"昨天"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g>天前"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1秒后"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g>秒后"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1分钟后"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>分钟后"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1小时后"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g>小时后"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"明天"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> 天后"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1秒前"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1分钟前"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g>分钟前"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1小时前"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g>小时前"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"昨天"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g>天前"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1秒后"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g>秒后"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1分钟后"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g>分钟后"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1小时后"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g>小时后"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"明天"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> 天后"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"日期:<xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"年份:<xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 83ae8f3..d08a416 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> 需要啟用「輕觸探索」。開啟這項功能時,系統會在您的手指輕觸螢幕上的物件時顯示或朗讀說明,您也可以執行手勢來與手機互動。"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 個月前"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 個月前"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 秒前"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 分鐘前"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> 分鐘前"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 小時前"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"上個月"</string>
<string name="older" msgid="5211975022815554840">"較舊"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"昨天"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 秒後"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> 秒後"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 分鐘後"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> 分鐘後"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 小時後"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> 小時後"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"明天"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> 天後"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 秒前"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 分鐘前"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> 分鐘前"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 小時前"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"昨天"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 秒後"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> 秒後"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 分鐘後"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> 分鐘後"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 小時後"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> 小時後"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"明天"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> 天後"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"於 <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"在 <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"於 <xliff:g id="YEAR">%s</xliff:g> 年"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index c9e5364..24ccc9a 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> 需要啟用「輕觸探索」。開啟這項功能時,系統會在您的手指輕觸螢幕上的物件時顯示或朗讀說明,您也可以執行手勢來與手機互動。"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 個月以前"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 個月前"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 秒以前"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 分鐘以前"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> 分鐘前"</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 小時以前"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"上個月"</string>
<string name="older" msgid="5211975022815554840">"較舊"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"昨天"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 秒內"</item>
- <item quantity="other" msgid="1241926116443974687">"在 <xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 分鐘內"</item>
- <item quantity="other" msgid="3330713936399448749">"在 <xliff:g id="COUNT">%d</xliff:g> 分鐘內"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 小時內"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> 小時內"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"明天"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 秒以前"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> 秒以前"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 分鐘以前"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> 分鐘以前"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 小時以前"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"昨天"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 秒內"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 分鐘內"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> 分鐘內"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 小時內"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> 小時內"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"明天"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"於 <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"於<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"於 <xliff:g id="YEAR">%s</xliff:g> 年"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 77cfdde..881b544 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1131,73 +1131,9 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"I-<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ifuna ukunika amandla i-Explore by Touch. Uma i-Explore by Touch ikhanya, ungezwa noma ubone izincazelo ezingaphansi komunwe wakho noma wenze izenzo zomzimba ukuze uxhumane nefoni."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"inyanga engu-1 edlule"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ngaphambi kwenyanga engu-1 edlule"</string>
- <plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 isekhondi eledlule"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> amasekhondi adlule"</item>
- </plurals>
- <plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 iminithi elidlule"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> amaminithi adlule.."</item>
- </plurals>
- <plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 ihora eledlule"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> amahora adlule"</item>
- </plurals>
<!-- no translation found for last_num_days:one (7555846096746489821) -->
<string name="last_month" msgid="3959346739979055432">"Inyanga edlule"</string>
<string name="older" msgid="5211975022815554840">"Okudala kakhulu"</string>
- <plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"Izolo"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> izinsuku ezedlule"</item>
- </plurals>
- <plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"esekhondini elingu-1"</item>
- <item quantity="other" msgid="1241926116443974687">"emasekhondini angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"eminithini engu-1"</item>
- <item quantity="other" msgid="3330713936399448749">"emaminithini angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"ehoreni elingu-1"</item>
- <item quantity="other" msgid="547290677353727389">"emahoreni angu- <xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"Kusasa"</item>
- <item quantity="other" msgid="5109449375100953247">"ezinsukwini ezingu-<xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 isekhondi edlule"</item>
- <item quantity="other" msgid="3699169366650930415">"amasekhondi angu-<xliff:g id="COUNT">%d</xliff:g> edlule"</item>
- </plurals>
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 iminithi eledlule"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> amaminithi adlule"</item>
- </plurals>
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 ihora eledlule"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> amahora adlule"</item>
- </plurals>
- <plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"Izolo"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> izinsuku ezedlule"</item>
- </plurals>
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"esekhondini elingu-1"</item>
- <item quantity="other" msgid="5495880108825805108">"emasekhondini angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"eminithini engu-1"</item>
- <item quantity="other" msgid="4216113292706568726">"emaminithini angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"ehoreni elingu-1"</item>
- <item quantity="other" msgid="3705373766798013406">"emahoreni angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
- <plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"Kusasa"</item>
- <item quantity="other" msgid="2973062968038355991">"ezinsukwini ezing-<xliff:g id="COUNT">%d</xliff:g>"</item>
- </plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"ngo-<xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"e-<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"phakathi- <xliff:g id="YEAR">%s</xliff:g>"</string>
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 457131a..7c63950 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -25,4 +25,8 @@
<bool name="show_ongoing_ime_switcher">true</bool>
<bool name="action_bar_expanded_action_views_exclusive">true</bool>
<bool name="target_honeycomb_needs_options_menu">true</bool>
+
+ <!-- Whether to allow vertically stacked button bars. This is disabled for
+ configurations with a small (e.g. less than 320dp) screen height. -->
+ <bool name="allow_stacked_button_bar">false</bool>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f2d9de8..4c25e7d 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -632,6 +632,14 @@
Any other values will have surprising consequences. -->
<integer name="config_defaultUiModeType">1</integer>
+ <!-- Control the default night mode to use when there is no other mode override set.
+ One of the following values (see UiModeManager.java):
+ 0 - MODE_NIGHT_AUTO
+ 1 - MODE_NIGHT_NO
+ 2 - MODE_NIGHT_YES
+ -->
+ <integer name="config_defaultNightMode">1</integer>
+
<!-- Indicate whether to allow the device to suspend when the screen is off
due to the proximity sensor. This resource should only be set to true
if the sensor HAL correctly handles the proximity sensor as a wake-up source.
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 68a3493..bec224e 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -304,6 +304,9 @@
<!-- Touch slop for the global toggle accessibility gesture -->
<dimen name="accessibility_touch_slop">80dip</dimen>
+ <!-- Width of the outline stroke used by the accessibility screen magnification indicator -->
+ <dimen name="accessibility_magnification_indicator_width">4dip</dimen>
+
<!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
<dimen name="keyguard_security_width">320dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e2a0ec9..3ac7374 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2617,4 +2617,20 @@
<public type="style" name="Widget.Material.Button.Colored" />
+ <public type="style" name="Theme.Material.DayNight" />
+ <public type="style" name="Theme.Material.DayNight.DarkActionBar" />
+ <public type="style" name="Theme.Material.DayNight.Dialog" />
+ <public type="style" name="Theme.Material.DayNight.Dialog.Alert" />
+ <public type="style" name="Theme.Material.DayNight.Dialog.MinWidth" />
+ <public type="style" name="Theme.Material.DayNight.Dialog.NoActionBar" />
+ <public type="style" name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" />
+ <public type="style" name="Theme.Material.DayNight.Dialog.Presentation" />
+ <public type="style" name="Theme.Material.DayNight.DialogWhenLarge" />
+ <public type="style" name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" />
+ <public type="style" name="Theme.Material.DayNight.NoActionBar" />
+ <public type="style" name="Theme.Material.DayNight.NoActionBar.Fullscreen" />
+ <public type="style" name="Theme.Material.DayNight.NoActionBar.Overscan" />
+ <public type="style" name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" />
+ <public type="style" name="Theme.Material.DayNight.Panel" />
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9946ce8..ff03ca9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3380,24 +3380,6 @@
<!-- String used to display the date. This is the string to say something happened more than 1 month ago. -->
<string name="beforeOneMonthDurationPast">Before 1 month ago</string>
- <!-- This is used to express that something occurred some number of seconds in the past (e.g., 5 seconds ago). -->
- <plurals name="num_seconds_ago">
- <item quantity="one">1 second ago</item>
- <item quantity="other"><xliff:g id="count">%d</xliff:g> seconds ago</item>
- </plurals>
-
- <!-- This is used to express that something occurred some number of minutes in the past (e.g., 5 minutes ago). -->
- <plurals name="num_minutes_ago">
- <item quantity="one">1 minute ago</item>
- <item quantity="other"><xliff:g id="count">%d</xliff:g> minutes ago</item>
- </plurals>
-
- <!-- This is used to express that something occurred some number of hours in the past (e.g., 5 hours ago). -->
- <plurals name="num_hours_ago">
- <item quantity="one">1 hour ago</item>
- <item quantity="other"><xliff:g id="count">%d</xliff:g> hours ago</item>
- </plurals>
-
<!-- This is used to express that something occurred within the last X days (e.g., Last 7 days). -->
<plurals name="last_num_days">
<item quantity="one">Last <xliff:g id="count">%d</xliff:g> day</item>
@@ -3410,84 +3392,6 @@
<!-- This is used to express that something happened longer ago than the previous options -->
<string name="older">Older</string>
- <!-- This is used to express that something occurred some number of days in the past (e.g., 5 days ago). -->
- <plurals name="num_days_ago">
- <item quantity="one">yesterday</item>
- <item quantity="other"><xliff:g id="count">%d</xliff:g> days ago</item>
- </plurals>
-
- <!-- This is used to express that something will occur some number of seconds in the future (e.g., in 5 seconds). -->
- <plurals name="in_num_seconds">
- <item quantity="one">in 1 second</item>
- <item quantity="other">in <xliff:g id="count">%d</xliff:g> seconds</item>
- </plurals>
-
- <!-- This is used to express that something will occur some number of minutes in the future (e.g., in 5 minutes). -->
- <plurals name="in_num_minutes">
- <item quantity="one">in 1 minute</item>
- <item quantity="other">in <xliff:g id="count">%d</xliff:g> minutes</item>
- </plurals>
-
- <!-- This is used to express that something will occur some number of hours in the future (e.g., in 5 hours). -->
- <plurals name="in_num_hours">
- <item quantity="one">in 1 hour</item>
- <item quantity="other">in <xliff:g id="count">%d</xliff:g> hours</item>
- </plurals>
-
- <!-- This is used to express that something will occur some number of days in the future (e.g., in 5 days). -->
- <plurals name="in_num_days">
- <item quantity="one">tomorrow</item>
- <item quantity="other">in <xliff:g id="count">%d</xliff:g> days</item>
- </plurals>
-
- <!-- This is used to express that something occurred some number of abbreviated seconds in the past (e.g., 5 secs ago). -->
- <plurals name="abbrev_num_seconds_ago">
- <item quantity="one">1 sec ago</item>
- <item quantity="other"><xliff:g id="count">%d</xliff:g> secs ago</item>
- </plurals>
-
- <!-- This is used to express that something occurred some number of abbreviated minutes in the past (e.g., 5 mins ago). -->
- <plurals name="abbrev_num_minutes_ago">
- <item quantity="one">1 min ago</item>
- <item quantity="other"><xliff:g id="count">%d</xliff:g> mins ago</item>
- </plurals>
-
- <!-- This is used to express that something occurred some number of abbreviated hours in the past (e.g., 5 hrs ago). -->
- <plurals name="abbrev_num_hours_ago">
- <item quantity="one">1 hour ago</item>
- <item quantity="other"><xliff:g id="count">%d</xliff:g> hours ago</item>
- </plurals>
-
- <!-- This is used to express that something occurred some number of abbreviated days in the past (e.g., 5 days ago). -->
- <plurals name="abbrev_num_days_ago">
- <item quantity="one">yesterday</item>
- <item quantity="other"><xliff:g id="count">%d</xliff:g> days ago</item>
- </plurals>
-
- <!-- This is used to express that something will occur some number of abbreviated seconds in the future (e.g., in 5 secs). -->
- <plurals name="abbrev_in_num_seconds">
- <item quantity="one">in 1 sec</item>
- <item quantity="other">in <xliff:g id="count">%d</xliff:g> secs</item>
- </plurals>
-
- <!-- This is used to express that something will occur some number of abbreviated minutes in the future (e.g., in 5 mins). -->
- <plurals name="abbrev_in_num_minutes">
- <item quantity="one">in 1 min</item>
- <item quantity="other">in <xliff:g id="count">%d</xliff:g> mins</item>
- </plurals>
-
- <!-- This is used to express that something will occur some number of abbreviated hours in the future (e.g., in 5 hrs). -->
- <plurals name="abbrev_in_num_hours">
- <item quantity="one">in 1 hour</item>
- <item quantity="other">in <xliff:g id="count">%d</xliff:g> hours</item>
- </plurals>
-
- <!-- This is used to express that something will occur some number of abbreviated days in the future (e.g., in 5 days). -->
- <plurals name="abbrev_in_num_days">
- <item quantity="one">tomorrow</item>
- <item quantity="other">in <xliff:g id="count">%d</xliff:g> days</item>
- </plurals>
-
<!-- String used to display the date. Preposition for date display ("on May 29") -->
<string name="preposition_for_date">on <xliff:g id="date" example="May 29">%s</xliff:g></string>
<!-- String used to display the date. Preposition for time display ("at 2:33am") -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 813de7c..84c839c 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -412,6 +412,7 @@
<java-symbol type="dimen" name="notification_badge_size" />
<java-symbol type="dimen" name="immersive_mode_cling_width" />
<java-symbol type="dimen" name="circular_display_mask_offset" />
+ <java-symbol type="dimen" name="accessibility_magnification_indicator_width" />
<java-symbol type="string" name="add_account_button_label" />
<java-symbol type="string" name="addToDictionary" />
@@ -1057,27 +1058,11 @@
<java-symbol type="string" name="config_ethernet_tcp_buffers" />
<java-symbol type="string" name="config_wifi_tcp_buffers" />
- <java-symbol type="plurals" name="abbrev_in_num_days" />
- <java-symbol type="plurals" name="abbrev_in_num_hours" />
- <java-symbol type="plurals" name="abbrev_in_num_minutes" />
- <java-symbol type="plurals" name="abbrev_in_num_seconds" />
- <java-symbol type="plurals" name="abbrev_num_days_ago" />
- <java-symbol type="plurals" name="abbrev_num_hours_ago" />
- <java-symbol type="plurals" name="abbrev_num_minutes_ago" />
- <java-symbol type="plurals" name="abbrev_num_seconds_ago" />
<java-symbol type="plurals" name="duration_hours" />
<java-symbol type="plurals" name="duration_minutes" />
<java-symbol type="plurals" name="duration_seconds" />
- <java-symbol type="plurals" name="in_num_days" />
- <java-symbol type="plurals" name="in_num_hours" />
- <java-symbol type="plurals" name="in_num_minutes" />
- <java-symbol type="plurals" name="in_num_seconds" />
<java-symbol type="plurals" name="last_num_days" />
<java-symbol type="plurals" name="matches_found" />
- <java-symbol type="plurals" name="num_days_ago" />
- <java-symbol type="plurals" name="num_hours_ago" />
- <java-symbol type="plurals" name="num_minutes_ago" />
- <java-symbol type="plurals" name="num_seconds_ago" />
<java-symbol type="plurals" name="restr_pin_countdown" />
<java-symbol type="plurals" name="pinpuk_attempts" />
@@ -2161,4 +2146,11 @@
<java-symbol type="string" name="usb_midi_peripheral_manufacturer_name" />
<java-symbol type="string" name="usb_midi_peripheral_model_name" />
+
+ <java-symbol type="bool" name="allow_stacked_button_bar" />
+ <java-symbol type="id" name="spacer" />
+
+ <java-symbol type="xml" name="bookmarks" />
+
+ <java-symbol type="integer" name="config_defaultNightMode" />
</resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 2b8ed5f..57041fdd 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -1238,8 +1238,7 @@
</style>
<!-- Default theme for Settings and activities launched from Settings. -->
- <style name="Theme.Material.Settings" parent="Theme.Material.Light.DarkActionBar">
- <item name="colorBackground">@color/white</item>
+ <style name="Theme.Material.Settings" parent="Theme.Material.DayNight.DarkActionBar">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
<item name="colorAccent">@color/material_deep_teal_500</item>
@@ -1251,8 +1250,7 @@
<item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
</style>
- <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.Light.BaseDialog">
- <item name="colorBackground">@color/white</item>
+ <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.DayNight.BaseDialog">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
<item name="colorAccent">@color/material_deep_teal_500</item>
@@ -1260,8 +1258,7 @@
<style name="Theme.Material.Settings.Dialog" parent="Theme.Material.Settings.BaseDialog" />
- <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert">
- <item name="colorBackground">@color/white</item>
+ <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.DayNight.Dialog.BaseAlert">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
<item name="colorAccent">@color/material_deep_teal_500</item>
@@ -1269,22 +1266,19 @@
<style name="Theme.Material.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.BaseAlert" />
- <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation">
- <item name="colorBackground">@color/white</item>
+ <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.DayNight.Dialog.Presentation">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
<item name="colorAccent">@color/material_deep_teal_500</item>
</style>
- <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.Light.SearchBar">
- <item name="colorBackground">@color/white</item>
+ <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.DayNight.SearchBar">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
<item name="colorAccent">@color/material_deep_teal_500</item>
</style>
- <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.Light.CompactMenu">
- <item name="colorBackground">@color/white</item>
+ <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.DayNight.CompactMenu">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
<item name="colorAccent">@color/material_deep_teal_500</item>
diff --git a/core/res/res/values/themes_material_daynight.xml b/core/res/res/values/themes_material_daynight.xml
new file mode 100644
index 0000000..5d9b860
--- /dev/null
+++ b/core/res/res/values/themes_material_daynight.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see themes_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+<resources>
+
+ <!-- Material theme (day/night vesion) for activities. -->
+ <style name="Theme.Material.DayNight" parent="Theme.Material.Light" />
+
+ <!-- Variant of Material.DayNight that has a solid (opaque) action bar
+ with an inverse color profile. The dark action bar sharply stands out against
+ the light content (when applicable). -->
+ <style name="Theme.Material.DayNight.DarkActionBar" parent="Theme.Material.Light.DarkActionBar" />
+
+ <!-- Variant of Material.DayNight with no action bar. -->
+ <style name="Theme.Material.DayNight.NoActionBar" parent="Theme.Material.Light.NoActionBar" />
+
+ <!-- Variant of Material.DayNight that has no title bar and fills
+ the entire screen. This theme
+ sets {@link android.R.attr#windowFullscreen} to true. -->
+ <style name="Theme.Material.DayNight.NoActionBar.Fullscreen" parent="Theme.Material.Light.NoActionBar.Fullscreen" />
+
+ <!-- Variant of Material.DayNight that has no title bar and fills
+ the entire screen and extends into the display overscan region. This theme
+ sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
+ to true. -->
+ <style name="Theme.Material.DayNight.NoActionBar.Overscan" parent="Theme.Material.Light.NoActionBar.Overscan" />
+
+ <!-- Variant of Material.DayNight that has no title bar and translucent
+ system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
+ {@link android.R.attr#windowTranslucentNavigation} to true. -->
+ <style name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" parent="Theme.Material.Light.NoActionBar.TranslucentDecor" />
+
+ <!-- Default Material.DayNight theme for panel windows. This removes all extraneous
+ window decorations, so you basically have an empty rectangle in which
+ to place your content. It makes the window floating, with a transparent
+ background, and turns off dimming behind the window. -->
+ <style name="Theme.Material.DayNight.Panel" parent="Theme.Material.Light.Panel" />
+
+ <!-- Material theme (day/night vesion) for dialog windows and activities,
+ which is used by the {@link android.app.Dialog} class. This changes
+ the window to be floating (not fill the entire screen), and puts a
+ frame around its contents. You can set this theme on an activity if
+ you would like to make an activity that looks like a Dialog. -->
+ <style name="Theme.Material.DayNight.Dialog" parent="Theme.Material.DayNight.BaseDialog" />
+ <style name="Theme.Material.DayNight.BaseDialog" parent="Theme.Material.Light.BaseDialog" />
+
+ <!-- Variant of Theme.Material.DayNight.Dialog that has a nice minimum width for
+ a regular dialog. -->
+ <style name="Theme.Material.DayNight.Dialog.MinWidth" parent="Theme.Material.Light.Dialog.MinWidth" />
+
+ <!-- Variant of Theme.Material.DayNight.Dialog that does not include a title bar. -->
+ <style name="Theme.Material.DayNight.Dialog.NoActionBar" parent="Theme.Material.Light.Dialog.NoActionBar" />
+
+ <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a nice minimum width for
+ a regular dialog. -->
+ <style name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Light.Dialog.NoActionBar.MinWidth" />
+
+ <!-- Variant of Theme.Material.DayNight.Dialog that has a fixed size. -->
+ <style name="Theme.Material.DayNight.Dialog.FixedSize" parent="Theme.Material.Light.Dialog.FixedSize" />
+
+ <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a fixed size. -->
+ <style name="Theme.Material.DayNight.Dialog.NoActionBar.FixedSize" parent="Theme.Material.Light.Dialog.NoActionBar.FixedSize" />
+
+ <!-- Theme for a window that will be displayed either full-screen on
+ smaller screens (small, normal) or as a dialog on larger screens
+ (large, xlarge). -->
+ <style name="Theme.Material.DayNight.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge" />
+
+ <!-- Theme for a window without an action bar that will be displayed either full-screen
+ on smaller screens (small, normal) or as a dialog on larger screens
+ (large, xlarge). -->
+ <style name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar" />
+
+ <!-- Theme for a presentation window on a secondary display. -->
+ <style name="Theme.Material.DayNight.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation" />
+
+ <!-- Material user theme for alert dialog windows, which is used by the
+ {@link android.app.AlertDialog} class. -->
+ <style name="Theme.Material.DayNight.Dialog.Alert" parent="Theme.Material.DayNight.Dialog.BaseAlert" />
+ <style name="Theme.Material.DayNight.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert" />
+
+ <style name="Theme.Material.DayNight.SearchBar" parent="Theme.Material.Light.SearchBar" />
+ <style name="Theme.Material.DayNight.CompactMenu" parent="Theme.Material.Light.CompactMenu" />
+
+</resources>
diff --git a/core/res/res/xml/bookmarks.xml b/core/res/res/xml/bookmarks.xml
new file mode 100644
index 0000000..454f456
--- /dev/null
+++ b/core/res/res/xml/bookmarks.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+ Default system bookmarks for AOSP.
+ Bookmarks for vendor apps should be added to a bookmarks resource overlay; not here.
+
+ Typical shortcuts (not necessarily defined here):
+ 'a': Calculator
+ 'b': Browser
+ 'c': Contacts
+ 'e': Email
+ 'g': GMail
+ 'l': Calendar
+ 'm': Maps
+ 'p': Music
+ 's': SMS
+ 't': Talk
+ 'y': YouTube
+-->
+<bookmarks>
+ <bookmark
+ category="android.intent.category.APP_CALCULATOR"
+ shortcut="a" />
+ <bookmark
+ category="android.intent.category.APP_BROWSER"
+ shortcut="b" />
+ <bookmark
+ category="android.intent.category.APP_CONTACTS"
+ shortcut="c" />
+ <bookmark
+ category="android.intent.category.APP_EMAIL"
+ shortcut="e" />
+ <bookmark
+ category="android.intent.category.APP_CALENDAR"
+ shortcut="l" />
+ <bookmark
+ category="android.intent.category.APP_MAPS"
+ shortcut="m" />
+ <bookmark
+ category="android.intent.category.APP_MUSIC"
+ shortcut="p" />
+ <bookmark
+ category="android.intent.category.APP_MESSAGING"
+ shortcut="s" />
+</bookmarks>
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index dc43a2f..a59581b 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -425,7 +425,7 @@
if (rLoc == INSTALL_LOC_INT) {
if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
assertTrue("The application should be installed forward locked",
- (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+ (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
assertStartsWith("The APK path should point to the ASEC",
SECURE_CONTAINERS_PREFIX, srcPath);
assertStartsWith("The public APK path should point to the ASEC",
@@ -441,7 +441,8 @@
fail("compat check: Can't read " + info.dataDir + "/lib");
}
} else {
- assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+ assertFalse(
+ (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
assertEquals(appInstallPath, srcPath);
assertEquals(appInstallPath, publicSrcPath);
assertStartsWith("Native library should point to shared lib directory",
@@ -467,16 +468,16 @@
} else if (rLoc == INSTALL_LOC_SD) {
if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
assertTrue("The application should be installed forward locked",
- (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+ (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
} else {
assertFalse("The application should not be installed forward locked",
- (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+ (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
}
assertTrue("Application flags (" + info.flags
+ ") should contain FLAG_EXTERNAL_STORAGE",
(info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
// Might need to check:
- // ((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0)
+ // ((info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0)
assertStartsWith("The APK path should point to the ASEC",
SECURE_CONTAINERS_PREFIX, srcPath);
assertStartsWith("The public APK path should point to the ASEC",
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index f94fe66..42b5d5d 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -335,11 +335,6 @@
</family>
<family>
<fileset>
- <file>NotoSansTaiLe-Regular.ttf</file>
- </fileset>
- </family>
- <family>
- <fileset>
<file>NotoSansTaiTham-Regular.ttf</file>
</fileset>
</family>
@@ -408,10 +403,13 @@
<file lang="ja">MTLmr3m.ttf</file>
</fileset>
</family>
- <!-- Note: complex scripts (i.e. those requiring shaping in Harfbuzz) have
- a cumulative limit of 64k glyphs. Thus, if they are placed after the
- large fonts such as DroidSansFallback, they are likely to render
- incorrectly. Please use caution when putting fonts toward the end of
- the list.
+ <!--
+ Noto Sans Tai Le is intentionally kept last, to make sure it doesn't override
+ the East Asian punctuation for Chinese.
-->
+ <family>
+ <fileset>
+ <file>NotoSansTaiLe-Regular.ttf</file>
+ </fileset>
+ </family>
</familyset>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 02bf877..37527e9 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -288,9 +288,6 @@
<font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
</family>
<family>
- <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
- </family>
- <family>
<font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
</family>
<family>
@@ -332,4 +329,11 @@
<family lang="ja">
<font weight="400" style="normal">MTLmr3m.ttf</font>
</family>
+ <!--
+ Noto Sans Tai Le is intentionally kept last, to make sure it doesn't override
+ the East Asian punctuation for Chinese.
+ -->
+ <family>
+ <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
+ </family>
</familyset>
diff --git a/docs/html/distribute/tools/promote/device-art-resources/wear/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/wear/thumb.png
new file mode 100644
index 0000000..adfe16f
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/wear/thumb.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/wear_round/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/wear_round/port_back.png
new file mode 100644
index 0000000..0b3d04a
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/wear_round/port_back.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/wear_square/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/wear_square/port_back.png
new file mode 100644
index 0000000..aa44795
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/wear_square/port_back.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art.jd b/docs/html/distribute/tools/promote/device-art.jd
index 3902b30..f583eb9 100644
--- a/docs/html/distribute/tools/promote/device-art.jd
+++ b/docs/html/distribute/tools/promote/device-art.jd
@@ -1,13 +1,13 @@
page.title=Device Art Generator
page.image=/images/device-art-ex-crop.jpg
-page.metaDescription=Drag and drop screenshots of your app into real device artwork, for better looking promotional images and improved visual context.
+page.metaDescription=Drag and drop screenshots of your app into device artwork, for better looking promotional images and improved visual context.
meta.tags="disttools, promoting, deviceart, marketing"
page.tags="device, deviceart, nexus, assets"
Xnonavpage=true
@jd:body
-<p>The device art generator enables you to quickly wrap app screenshots in real device artwork. This provides better visual context for your app screenshots on your website or in other promotional materials</p>
+<p>The device art generator enables you to quickly wrap app screenshots in device artwork. This provides better visual context for your app screenshots on your website or in other promotional materials</p>
<p class="note"><strong>Note</strong>: Do <em>not</em> use graphics created here in your 1024x500
feature image or screenshots for your Google Play app listing.</p>
@@ -41,6 +41,12 @@
<label for="output-glare">Screen Glare</label><br><br>
<a class="button" id="rotate-button">Rotate</a>
</p>
+ <p id="wear-customizations">
+ <input type="radio" id="output-square" name="output-wear" checked="checked" class="form-field-checkbutton">
+ <label for="output-square">Square</label><br>
+ <input type="radio" id="output-round" name="output-wear" class="form-field-checkbutton">
+ <label for="output-round">Round</label><br><br>
+ </p>
</div>
<div class="layout-content-col span-10">
<!-- position:relative fixes an issue where dragging an image out of a inline-block container
@@ -52,7 +58,7 @@
</div>
<div class="unsupported-browser" style="display: none">
- <p class="warning"><strong>Error:</strong> This page requires
+ <p class="warning"><strong>Error:</strong> This page requires
<span id="unsupported-browser-reason">certain features</span>, which your web browser
doesn't support. To continue, navigate to this page on a supported web browser, such as
<strong>Google Chrome</strong>.</p>
@@ -165,6 +171,10 @@
// Global constants
var MSG_INVALID_INPUT_IMAGE = 'Invalid screenshot provided. Screenshots must be PNG files '
+ 'matching the target device\'s screen aspect ratio in either portrait or landscape.';
+ var MSG_INVALID_WEAR_IMAGE = 'Invalid screenshot provided. Screenshots must be PNG files '
+ + 'matching the target device\'s screen aspect ratio.'
+ + ' Capture screenshots from a Wear emulator or device with '
+ + '<a href="http://developer.android.com/tools/debugging/debugging-studio.html#screenCap">Android Studio</a>.';
var MSG_NO_INPUT_IMAGE = 'Drag a screenshot (in PNG format) from your desktop onto a '
+ 'target device above.'
var MSG_GENERATING_IMAGE = 'Generating device art…';
@@ -270,6 +280,47 @@
portSize: [768,1280],
archived: true
},
+ {
+ id: 'wear',
+ title: 'Android Wear',
+ url: 'http://www.android.com/wear/',
+ physicalSize: 1.8,
+ physicalHeight: 1.8,
+ density: 'HDPI',
+ landRes: ['back'],
+ landOffset: [225,206],
+ portRes: ['back'],
+ portOffset: [200,214],
+ portSize: [320,320],
+ },
+ {
+ id: 'wear_square',
+ title: 'Android Wear Square',
+ url: 'http://www.android.com/wear/',
+ physicalSize: 1.8,
+ physicalHeight: 1.8,
+ density: 'HDPI',
+ landRes: ['back'],
+ landOffset: [225,206],
+ portRes: ['back'],
+ portOffset: [200,214],
+ portSize: [320,320],
+ hidden: true
+ },
+ {
+ id: 'wear_round',
+ title: 'Android Wear Round',
+ url: 'http://www.android.com/wear/',
+ physicalSize: 1.8,
+ physicalHeight: 1.8,
+ density: 'HDPI',
+ landRes: ['back'],
+ landOffset: [161,167],
+ portRes: ['back'],
+ portOffset: [128,134],
+ portSize: [320,320],
+ hidden: true
+ },
];
DEVICES = DEVICES.sort(function(x, y) { return x.physicalSize - y.physicalSize; });
@@ -343,15 +394,21 @@
$('#output').html(MSG_NO_INPUT_IMAGE);
$('#frame-customizations').hide();
+ $('#wear-customizations').hide();
$('#output-shadow, #output-glare').click(function() {
createFrame();
});
+ $('input[name="output-wear"]').change(function() {
+ createFrame();
+ });
+
// Build device list.
$.each(DEVICES, function() {
var resolution = this.actualResolution || this.portSize;
var scaleFactorText = '';
+ var deviceList = '.device-list.primary';
if (resolution[0] != this.portSize[0]) {
scaleFactorText = '<br>' + (100 * (this.portSize[0] / resolution[0])).toFixed(0) +
'% size output';
@@ -359,6 +416,12 @@
scaleFactorText = '<br> ';
}
+ if (this.archived) {
+ deviceList = '.device-list.archived';
+ } else if (this.hidden) {
+ deviceList = '.device-list.hidden';
+ }
+
$('<li>')
.append($('<div>')
.addClass('thumb-container')
@@ -374,7 +437,7 @@
'<br>' + this.physicalSize + '" @ ' + this.density +
'<br>' + (resolution[0] + 'x' + resolution[1]) + scaleFactorText))
.data('deviceId', this.id)
- .appendTo(this.archived ? '.device-list.archive' : '.device-list.primary');
+ .appendTo(deviceList)
});
// Set up "older devices" expando.
@@ -406,7 +469,11 @@
evt.preventDefault();
loadImageFromFileList(evt.dataTransfer.files, function(data) {
if (data == null) {
- $('#output').html(MSG_INVALID_INPUT_IMAGE);
+ if (g_currentDevice.id == 'wear') {
+ $('#output').html(MSG_INVALID_WEAR_IMAGE);
+ }else {
+ $('#output').html(MSG_INVALID_INPUT_IMAGE);
+ }
return;
}
loadImageFromUri(data.uri, function(img) {
@@ -450,6 +517,14 @@
function createFrame() {
var port;
+ if (g_currentDevice.id == 'wear' || g_currentDevice.id == 'wear_square' || g_currentDevice.id == 'wear_round') {
+ if ($('#output-square').is(':checked')) {
+ g_currentDevice = getDeviceById('wear_square');
+ } else {
+ g_currentDevice = getDeviceById('wear_round');
+ }
+ }
+
var aspect1 = g_currentImage.naturalWidth / g_currentImage.naturalHeight;
var aspect2 = g_currentDevice.portSize[0] / g_currentDevice.portSize[1];
@@ -458,11 +533,18 @@
} else if (aspect1 == 1 / aspect2) {
port = false;
} else {
- alert('The screenshot must have an aspect ratio of ' +
+ if (g_currentDevice.id == 'wear_square' || g_currentDevice.id == 'wear_round') {
+ alert('The screenshot must have an aspect ratio of ' +
+ aspect2.toFixed(3) +
+ ' (ideally ' + g_currentDevice.portSize[0] + 'x' + g_currentDevice.portSize[1] + ').');
+ $('#output').html(MSG_INVALID_WEAR_IMAGE);
+ }else {
+ alert('The screenshot must have an aspect ratio of ' +
aspect2.toFixed(3) + ' or ' + (1 / aspect2).toFixed(3) +
' (ideally ' + g_currentDevice.portSize[0] + 'x' + g_currentDevice.portSize[1] +
' or ' + g_currentDevice.portSize[1] + 'x' + g_currentDevice.portSize[0] + ').');
- $('#output').html(MSG_INVALID_INPUT_IMAGE);
+ $('#output').html(MSG_INVALID_INPUT_IMAGE);
+ }
return;
}
@@ -497,9 +579,37 @@
ctx.drawImage(resourceImages['shadow'], 0, 0);
}
ctx.drawImage(resourceImages['back'], 0, 0);
- ctx.fillStyle = '#000';
- ctx.fillRect(offset[0], offset[1], size[0], size[1]);
- ctx.drawImage(g_currentImage, offset[0], offset[1], size[0], size[1]);
+
+ if (g_currentDevice.id == 'wear_round') {
+ var scratchCanvas = document.createElement('canvas');
+ scratchCanvas.width = width;
+ scratchCanvas.height = height;
+ var scratchCtx = scratchCanvas.getContext('2d');
+
+
+ //drawing code
+ scratchCtx.clearRect(offset[0], offset[1], scratchCanvas.width, scratchCanvas.height);
+
+ scratchCtx.globalCompositeOperation = 'source-over'; //default
+
+ scratchCtx.drawImage(g_currentImage, offset[0], offset[1], size[0], size[1]);
+
+ scratchCtx.fillStyle = '#fff'; //color doesn't matter, but we want full opacity
+ scratchCtx.globalCompositeOperation = 'destination-in';
+ scratchCtx.beginPath();
+ scratchCtx.arc(288, 294, size[0] / 2, 0, 2 * Math.PI, false);
+ scratchCtx.closePath();
+ scratchCtx.fill();
+
+ // After tinkering with the offset, the 1 in the x-position drew the image
+ // perfectly
+ ctx.drawImage(scratchCanvas, 1, 0);
+ } else {
+ ctx.fillStyle = '#000';
+ ctx.fillRect(offset[0], offset[1], size[0], size[1]);
+ ctx.drawImage(g_currentImage, offset[0], offset[1], size[0], size[1]);
+ }
+
if (resourceImages['fore'] && $('#output-glare').is(':checked')) {
ctx.drawImage(resourceImages['fore'], 0, 0);
}
@@ -546,7 +656,13 @@
.attr('data-downloadurl', ['image/png', filename, imageUrl].join(':')))
.appendTo($('#output').empty());
- $('#frame-customizations').show();
+ if (g_currentDevice.id == 'wear' || g_currentDevice.id == 'wear_round' || g_currentDevice.id == 'wear_square') {
+ $('#wear-customizations').show();
+ $('#frame-customizations').hide();
+ } else {
+ $('#frame-customizations').show();
+ $('#wear-customizations').hide();
+ }
}
}
diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd
index f09ff9e..5710a47 100644
--- a/docs/html/guide/topics/data/backup.jd
+++ b/docs/html/guide/topics/data/backup.jd
@@ -643,7 +643,8 @@
// Allocate a helper and add it to the backup agent
@Override
public void onCreate() {
- SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS);
+ SharedPreferencesBackupHelper helper =
+ new SharedPreferencesBackupHelper(this, PREFS);
addHelper(PREFS_BACKUP_KEY, helper);
}
}
@@ -688,8 +689,10 @@
static final String FILES_BACKUP_KEY = "myfiles";
// Allocate a helper and add it to the backup agent
- void onCreate() {
- FileBackupHelper helper = new FileBackupHelper(this, TOP_SCORES, PLAYER_STATS);
+ @Override
+ public void onCreate() {
+ FileBackupHelper helper = new FileBackupHelper(this,
+ TOP_SCORES, PLAYER_STATS);
addHelper(FILES_BACKUP_KEY, helper);
}
}
diff --git a/docs/html/guide/topics/resources/localization.jd b/docs/html/guide/topics/resources/localization.jd
index 1ee6606..0a96a15 100644
--- a/docs/html/guide/topics/resources/localization.jd
+++ b/docs/html/guide/topics/resources/localization.jd
@@ -433,8 +433,8 @@
<p>To change the locale in the emulator by using the adb shell. </p>
<ol>
- <li>Pick the locale you want to test and determine its language and region codes, for
-example <code>fr</code> for French and <code>CA</code> for Canada.<br>
+ <li>Pick the locale you want to test and determine its BCP-47 language tag, for
+example, Canadian French would be <code>fr-CA</code>.<br>
</li>
<li>Launch an emulator.</li>
<li>From a command-line shell on the host computer, run the following
@@ -444,16 +444,14 @@
the <code>-e</code> option:<br>
<code>adb -e shell</code></li>
<li>At the adb shell prompt (<code>#</code>), run this command: <br>
- <code>setprop persist.sys.language [<em>language code</em>];setprop
-persist.sys.country [<em>country code</em>];stop;sleep 5;start <br>
+ <code>setprop persist.sys.locale [<em>BCP-47 language tag</em>];stop;sleep 5;start <br>
</code>Replace bracketed sections with the appropriate codes from Step
1.</li>
</ol>
<p>For instance, to test in Canadian French:</p>
-<p><code>setprop persist.sys.language fr;setprop persist.sys.country
-CA;stop;sleep 5;start </code></p>
+<p><code>setprop persist.sys.locale fr-CA;stop;sleep 5;start </code></p>
<p>This will cause the emulator to restart. (It will look like a full reboot,
but it is not.) Once the Home screen appears again, re-launch your application (for
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index e47c77e..976115e 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -663,20 +663,21 @@
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
// Creates an Intent for the Activity
Intent notifyIntent =
- new Intent(new ComponentName(this, ResultActivity.class));
+ new Intent(this, ResultActivity.class);
// Sets the Activity to start in a new, empty task
-notifyIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
+notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_CLEAR_TASK);
// Creates the PendingIntent
-PendingIntent notifyIntent =
+PendingIntent notifyPendingIntent =
PendingIntent.getActivity(
this,
0,
- notifyIntent
+ notifyIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
// Puts the PendingIntent into the notification builder
-builder.setContentIntent(notifyIntent);
+builder.setContentIntent(notifyPendingIntent);
// Notifications are issued by sending them to the
// NotificationManager system service.
NotificationManager mNotificationManager =
@@ -715,7 +716,7 @@
<h3 id="FixedProgress">Displaying a fixed-duration progress indicator</h3>
<p>
To display a determinate progress bar, add the bar to your notification by calling
- {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()
+ {@link android.support.v4.app.NotificationCompat.Builder#setProgress
setProgress(max, progress, false)} and then issue the notification. As your operation proceeds,
increment <code>progress</code>, and update the notification. At the end of the operation,
<code>progress</code> should equal <code>max</code>. A common way to call
@@ -727,7 +728,7 @@
You can either leave the progress bar showing when the operation is done, or remove it. In
either case, remember to update the notification text to show that the operation is complete.
To remove the progress bar, call
- {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()
+ {@link android.support.v4.app.NotificationCompat.Builder#setProgress
setProgress(0, 0, false)}. For example:
</p>
<pre>
@@ -783,8 +784,8 @@
<p>
Issue the notification at the beginning of the operation. The animation will run until you
modify your notification. When the operation is done, call
- {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()
- setProgress(0, 0, false)} and then update the notification to remove the activity indicator.
+ {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, false)}
+ and then update the notification to remove the activity indicator.
Always do this; otherwise, the animation will run even when the operation is complete. Also
remember to change the notification text to indicate that the operation is complete.
</p>
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 9e4674b..616aebd 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -322,7 +322,13 @@
return false;
}
- void addLayer(ChildDrawable layer) {
+ /**
+ * Adds a new layer at the end of list of layers and returns its index.
+ *
+ * @param layer The layer to add.
+ * @return The index of the layer.
+ */
+ int addLayer(ChildDrawable layer) {
final LayerState st = mLayerState;
final int N = st.mChildren != null ? st.mChildren.length : 0;
final int i = st.mNum;
@@ -338,12 +344,13 @@
st.mChildren[i] = layer;
st.mNum++;
st.invalidateCache();
+ return i;
}
/**
* Add a new layer to this drawable. The new layer is identified by an id.
*
- * @param layer The drawable to add as a layer.
+ * @param dr The drawable to add as a layer.
* @param themeAttrs Theme attributes extracted from the layer.
* @param id The id of the new layer.
* @param left The left padding of the new layer.
@@ -351,12 +358,11 @@
* @param right The right padding of the new layer.
* @param bottom The bottom padding of the new layer.
*/
- ChildDrawable addLayer(Drawable layer, int[] themeAttrs, int id, int left, int top, int right,
- int bottom) {
- final ChildDrawable childDrawable = new ChildDrawable();
+ ChildDrawable addLayer(Drawable dr, int[] themeAttrs, int id,
+ int left, int top, int right, int bottom) {
+ final ChildDrawable childDrawable = createLayer(dr);
childDrawable.mId = id;
childDrawable.mThemeAttrs = themeAttrs;
- childDrawable.mDrawable = layer;
childDrawable.mDrawable.setAutoMirrored(isAutoMirrored());
childDrawable.mInsetL = left;
childDrawable.mInsetT = top;
@@ -365,12 +371,31 @@
addLayer(childDrawable);
- mLayerState.mChildrenChangingConfigurations |= layer.getChangingConfigurations();
- layer.setCallback(this);
+ mLayerState.mChildrenChangingConfigurations |= dr.getChangingConfigurations();
+ dr.setCallback(this);
return childDrawable;
}
+ private ChildDrawable createLayer(Drawable dr) {
+ final ChildDrawable layer = new ChildDrawable();
+ layer.mDrawable = dr;
+ return layer;
+ }
+
+ /**
+ * Adds a new layer containing the specified {@code drawable} to the end of
+ * the layer list and returns its index.
+ *
+ * @param dr The drawable to add as a new layer.
+ * @return The index of the new layer.
+ */
+ public int addLayer(Drawable dr) {
+ final ChildDrawable layer = createLayer(dr);
+ final int index = addLayer(layer);
+ return index;
+ }
+
/**
* Looks for a layer with the given ID and returns its {@link Drawable}.
* <p>
@@ -395,15 +420,38 @@
/**
* Sets the ID of a layer.
*
- * @param index The index of the layer which will received the ID.
- * @param id The ID to assign to the layer.
+ * @param index The index of the layer to modify, must be in the range
+ * {@code 0...getNumberOfLayers()-1}.
+ * @param id The id to assign to the layer.
+ *
+ * @see #getId(int)
+ * @attr ref android.R.styleable#LayerDrawableItem_id
*/
public void setId(int index, int id) {
mLayerState.mChildren[index].mId = id;
}
/**
- * Returns the number of layers contained within this.
+ * Returns the ID of the specified layer.
+ *
+ * @param index The index of the layer, must be in the range
+ * {@code 0...getNumberOfLayers()-1}.
+ * @return The id of the layer or {@link android.view.View#NO_ID} if the
+ * layer has no id.
+ *
+ * @see #setId(int, int)
+ * @attr ref android.R.styleable#LayerDrawableItem_id
+ */
+ public int getId(int index) {
+ if (index >= mLayerState.mNum) {
+ throw new IndexOutOfBoundsException();
+ }
+ return mLayerState.mChildren[index].mId;
+ }
+
+ /**
+ * Returns the number of layers contained within this layer drawable.
+ *
* @return The number of layers.
*/
public int getNumberOfLayers() {
@@ -411,29 +459,7 @@
}
/**
- * Returns the drawable at the specified layer index.
- *
- * @param index The layer index of the drawable to retrieve.
- *
- * @return The {@link android.graphics.drawable.Drawable} at the specified layer index.
- */
- public Drawable getDrawable(int index) {
- return mLayerState.mChildren[index].mDrawable;
- }
-
- /**
- * Returns the id of the specified layer.
- *
- * @param index The index of the layer.
- *
- * @return The id of the layer or {@link android.view.View#NO_ID} if the layer has no id.
- */
- public int getId(int index) {
- return mLayerState.mChildren[index].mId;
- }
-
- /**
- * Sets (or replaces) the {@link Drawable} for the layer with the given id.
+ * Replaces the {@link Drawable} for the layer with the given id.
*
* @param id The layer ID to search for.
* @param drawable The replacement {@link Drawable}.
@@ -441,31 +467,88 @@
* the id was not found).
*/
public boolean setDrawableByLayerId(int id, Drawable drawable) {
+ final int index = findIndexByLayerId(id);
+ if (index < 0) {
+ return false;
+ }
+
+ setDrawable(index, drawable);
+ return true;
+ }
+
+ /**
+ * Returns the layer with the specified {@code id}.
+ * <p>
+ * If multiple layers have the same ID, returns the layer with the lowest
+ * index.
+ *
+ * @param id The ID of the layer to return.
+ * @return The index of the layer with the specified ID.
+ */
+ public int findIndexByLayerId(int id) {
final ChildDrawable[] layers = mLayerState.mChildren;
final int N = mLayerState.mNum;
for (int i = 0; i < N; i++) {
final ChildDrawable childDrawable = layers[i];
if (childDrawable.mId == id) {
- if (childDrawable.mDrawable != null) {
- if (drawable != null) {
- final Rect bounds = childDrawable.mDrawable.getBounds();
- drawable.setBounds(bounds);
- }
-
- childDrawable.mDrawable.setCallback(null);
- }
-
- if (drawable != null) {
- drawable.setCallback(this);
- }
-
- childDrawable.mDrawable = drawable;
- mLayerState.invalidateCache();
- return true;
+ return i;
}
}
- return false;
+ return -1;
+ }
+
+ /**
+ * Sets the drawable for the layer at the specified index.
+ *
+ * @param index The index of the layer to modify, must be in the range
+ * {@code 0...getNumberOfLayers()-1}.
+ * @param drawable The drawable to set for the layer.
+ *
+ * @see #getDrawable(int)
+ * @attr ref android.R.styleable#LayerDrawableItem_drawable
+ */
+ public void setDrawable(int index, Drawable drawable) {
+ if (index >= mLayerState.mNum) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ final ChildDrawable[] layers = mLayerState.mChildren;
+ final ChildDrawable childDrawable = layers[index];
+ if (childDrawable.mDrawable != null) {
+ if (drawable != null) {
+ final Rect bounds = childDrawable.mDrawable.getBounds();
+ drawable.setBounds(bounds);
+ }
+
+ childDrawable.mDrawable.setCallback(null);
+ }
+
+ if (drawable != null) {
+ drawable.setCallback(this);
+ drawable.setLayoutDirection(getLayoutDirection());
+ drawable.setLevel(getLevel());
+ }
+
+ childDrawable.mDrawable = drawable;
+ mLayerState.invalidateCache();
+ }
+
+ /**
+ * Returns the drawable for the layer at the specified index.
+ *
+ * @param index The index of the layer, must be in the range
+ * {@code 0...getNumberOfLayers()-1}.
+ * @return The {@link Drawable} at the specified layer index.
+ *
+ * @see #setDrawable(int, Drawable)
+ * @attr ref android.R.styleable#LayerDrawableItem_drawable
+ */
+ public Drawable getDrawable(int index) {
+ if (index >= mLayerState.mNum) {
+ throw new IndexOutOfBoundsException();
+ }
+ return mLayerState.mChildren[index].mDrawable;
}
/**
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index d128ffe..cca8a06 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -668,7 +668,8 @@
}
virtual void output(int level, uint32_t logFlags) const override {
- OP_LOG("Draw bitmap %p at %f %f%s", mBitmap, mLocalBounds.left, mLocalBounds.top,
+ OP_LOG("Draw bitmap %p of size %dx%d%s",
+ mBitmap, mBitmap->width(), mBitmap->height(),
mEntry ? " using AssetAtlas" : "");
}
diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h
new file mode 100644
index 0000000..803b9d4
--- /dev/null
+++ b/libs/hwui/FloatColor.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef FLOATCOLOR_H
+#define FLOATCOLOR_H
+
+#include "utils/Macros.h"
+
+namespace android {
+namespace uirenderer {
+
+struct FloatColor {
+ float r;
+ float g;
+ float b;
+ float a;
+};
+
+REQUIRE_COMPATIBLE_LAYOUT(FloatColor);
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* FLOATCOLOR_H */
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index e2adff8..10dbd5c 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_HWUI_GLOP_H
#define ANDROID_HWUI_GLOP_H
+#include "FloatColor.h"
#include "Matrix.h"
#include "Rect.h"
#include "utils/Macros.h"
@@ -29,6 +30,7 @@
namespace uirenderer {
class Program;
+class RoundRectClipState;
/*
* Enumerates optional vertex attributes
@@ -37,30 +39,27 @@
* are enabled/disabled dynamically based on mesh content.
*/
enum VertexAttribFlags {
- // NOTE: position attribute always enabled
kNone_Attrib = 0,
kTextureCoord_Attrib = 1 << 0,
kColor_Attrib = 1 << 1,
kAlpha_Attrib = 1 << 2,
};
-
/**
- * Structure containing all data required to issue a single OpenGL draw
+ * Structure containing all data required to issue an OpenGL draw
*
* Includes all of the mesh, fill, and GL state required to perform
* the operation. Pieces of data are either directly copied into the
* structure, or stored as a pointer or GL object reference to data
- * managed
+ * managed.
+ *
+ * Eventually, a Glop should be able to be drawn multiple times from
+ * a single construction, up until GL context destruction. Currently,
+ * vertex/index/Texture/RoundRectClipState pointers prevent this from
+ * being safe.
*/
// TODO: PREVENT_COPY_AND_ASSIGN(...) or similar
struct Glop {
- struct FloatColor {
- float a, r, g, b;
- };
-
- Rect bounds;
-
/*
* Stores mesh - vertex and index data.
*
@@ -74,12 +73,20 @@
GLuint indexBufferObject;
const void* vertices;
const void* indices;
- int vertexCount;
+ int elementCount;
GLsizei stride;
+ GLvoid* texCoordOffset;
+ TextureVertex mappedVertices[4];
} mesh;
struct Fill {
Program* program;
+
+ Texture* texture;
+ GLenum textureFilter;
+ GLenum textureClamp;
+
+ bool colorEnabled;
FloatColor color;
/* TODO
@@ -104,12 +111,25 @@
bool fudgingOffset;
} transform;
+ const RoundRectClipState* roundRectClipState;
+
+ /**
+ * Blending to be used by this draw - both GL_NONE if blending is disabled.
+ *
+ * Defined by fill step, but can be force-enabled by presence of kAlpha_Attrib
+ */
struct Blend {
GLenum src;
GLenum dst;
} blend;
/**
+ * Bounds of the drawing command in layer space. Only mapped into layer
+ * space once GlopBuilder::build() is called.
+ */
+ Rect bounds;
+
+ /**
* Additional render state to enumerate:
* - scissor + (bits for whether each of LTRB needed?)
* - stencil mode (draw into, mask, count, etc)
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 5373275..91e0f89 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -33,19 +33,91 @@
#define TRIGGER_STAGE(stageFlag) \
LOG_ALWAYS_FATAL_IF(stageFlag & mStageFlags, "Stage %d cannot be run twice"); \
- mStageFlags = static_cast<StageFlags>(mStageFlags | stageFlag)
+ mStageFlags = static_cast<StageFlags>(mStageFlags | (stageFlag))
#define REQUIRE_STAGES(requiredFlags) \
- LOG_ALWAYS_FATAL_IF((mStageFlags & requiredFlags) != requiredFlags, \
+ LOG_ALWAYS_FATAL_IF((mStageFlags & (requiredFlags)) != (requiredFlags), \
"not prepared for current stage")
+static void setUnitQuadTextureCoords(Rect uvs, TextureVertex* quadVertex) {;
+ TextureVertex::setUV(quadVertex++, uvs.left, uvs.top);
+ TextureVertex::setUV(quadVertex++, uvs.right, uvs.top);
+ TextureVertex::setUV(quadVertex++, uvs.left, uvs.bottom);
+ TextureVertex::setUV(quadVertex++, uvs.right, uvs.bottom);
+}
+
GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop)
: mRenderState(renderState)
, mCaches(caches)
- , mOutGlop(outGlop){
+ , mOutGlop(outGlop) {
mStageFlags = kInitialStage;
}
+////////////////////////////////////////////////////////////////////////////////
+// Mesh
+////////////////////////////////////////////////////////////////////////////////
+
+GlopBuilder& GlopBuilder::setMeshUnitQuad() {
+ TRIGGER_STAGE(kMeshStage);
+
+ mOutGlop->mesh.vertexFlags = kNone_Attrib;
+ mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+ mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
+ mOutGlop->mesh.vertices = nullptr;
+ mOutGlop->mesh.indexBufferObject = 0;
+ mOutGlop->mesh.indices = nullptr;
+ mOutGlop->mesh.elementCount = 4;
+ mOutGlop->mesh.stride = kTextureVertexStride;
+ mOutGlop->mesh.texCoordOffset = nullptr;
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper,
+ bool isAlphaMaskTexture) {
+ TRIGGER_STAGE(kMeshStage);
+
+ mOutGlop->mesh.vertexFlags = kTextureCoord_Attrib;
+ mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+
+ if (CC_UNLIKELY(uvMapper)) {
+ Rect uvs(0, 0, 1, 1);
+ uvMapper->map(uvs);
+ setUnitQuadTextureCoords(uvs, &mOutGlop->mesh.mappedVertices[0]);
+
+ mOutGlop->mesh.vertexBufferObject = 0;
+ mOutGlop->mesh.vertices = &mOutGlop->mesh.mappedVertices[0];
+ } else {
+ // standard UV coordinates, use regular unit quad VBO
+ mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
+ mOutGlop->mesh.vertices = nullptr;
+ }
+ mOutGlop->mesh.indexBufferObject = 0;
+ mOutGlop->mesh.indices = nullptr;
+ mOutGlop->mesh.elementCount = 4;
+ mOutGlop->mesh.stride = kTextureVertexStride;
+ mOutGlop->mesh.texCoordOffset = (GLvoid*) kMeshTextureOffset;
+
+ mDescription.hasTexture = true;
+ mDescription.hasAlpha8Texture = isAlphaMaskTexture;
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshIndexedQuads(void* vertexData, int quadCount) {
+ TRIGGER_STAGE(kMeshStage);
+
+ mOutGlop->mesh.vertexFlags = kNone_Attrib;
+ mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
+ mOutGlop->mesh.vertexBufferObject = 0;
+ mOutGlop->mesh.vertices = vertexData;
+ mOutGlop->mesh.indexBufferObject = mRenderState.meshState().getQuadListIBO();
+ mOutGlop->mesh.indices = nullptr;
+ mOutGlop->mesh.elementCount = 6 * quadCount;
+ mOutGlop->mesh.stride = kVertexStride;
+ mOutGlop->mesh.texCoordOffset = nullptr;
+
+ return *this;
+}
+
GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp) {
TRIGGER_STAGE(kMeshStage);
@@ -59,7 +131,7 @@
mOutGlop->mesh.vertices = vertexBuffer.getBuffer();
mOutGlop->mesh.indexBufferObject = 0;
mOutGlop->mesh.indices = vertexBuffer.getIndices();
- mOutGlop->mesh.vertexCount = indices
+ mOutGlop->mesh.elementCount = indices
? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
mOutGlop->mesh.stride = alphaVertex ? kAlphaVertexStride : kVertexStride;
@@ -68,115 +140,35 @@
return *this;
}
-GlopBuilder& GlopBuilder::setMeshUnitQuad() {
- TRIGGER_STAGE(kMeshStage);
+////////////////////////////////////////////////////////////////////////////////
+// Fill
+////////////////////////////////////////////////////////////////////////////////
- mOutGlop->mesh.vertexFlags = kNone_Attrib;
- mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
- mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
- mOutGlop->mesh.vertices = nullptr;
- mOutGlop->mesh.indexBufferObject = 0;
- mOutGlop->mesh.indices = nullptr;
- mOutGlop->mesh.vertexCount = 4;
- mOutGlop->mesh.stride = kTextureVertexStride;
- return *this;
-}
-
-GlopBuilder& GlopBuilder::setMeshIndexedQuads(void* vertexData, int quadCount) {
- TRIGGER_STAGE(kMeshStage);
-
- mOutGlop->mesh.vertexFlags = kNone_Attrib;
- mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
- mOutGlop->mesh.vertexBufferObject = 0;
- mOutGlop->mesh.vertices = vertexData;
- mOutGlop->mesh.indexBufferObject = mRenderState.meshState().getQuadListIBO();
- mOutGlop->mesh.indices = nullptr;
- mOutGlop->mesh.vertexCount = 6 * quadCount;
- mOutGlop->mesh.stride = kVertexStride;
-
- return *this;
-}
-
-GlopBuilder& GlopBuilder::setTransform(const Matrix4& ortho,
- const Matrix4& transform, bool fudgingOffset) {
- TRIGGER_STAGE(kTransformStage);
-
- mOutGlop->transform.ortho.load(ortho);
- mOutGlop->transform.canvas.load(transform);
- mOutGlop->transform.fudgingOffset = fudgingOffset;
- return *this;
-}
-
-GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) {
- TRIGGER_STAGE(kModelViewStage);
-
- mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f);
- mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
- mOutGlop->bounds = destination;
- return *this;
-}
-
-GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) {
- TRIGGER_STAGE(kModelViewStage);
-
- mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
- mOutGlop->bounds = source;
- mOutGlop->bounds.translate(offsetX, offsetY);
- return *this;
-}
-
-GlopBuilder& GlopBuilder::setOptionalPaint(const SkPaint* paint, float alphaScale) {
- if (paint) {
- return setPaint(*paint, alphaScale);
- }
-
- TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
-
- mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale };
-
- const bool SWAP_SRC_DST = false;
- // TODO: account for texture blend
- if (alphaScale < 1.0f
- || (mOutGlop->mesh.vertexFlags & kAlpha_Attrib)) {
- Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
- &mOutGlop->blend.src, &mOutGlop->blend.dst);
- } else {
- mOutGlop->blend = { GL_ZERO, GL_ZERO };
- }
-
- return *this;
-}
-GlopBuilder& GlopBuilder::setPaint(const SkPaint& paint, float alphaScale) {
- TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
-
- const SkShader* shader = paint.getShader();
- const SkColorFilter* colorFilter = paint.getColorFilter();
-
- SkXfermode::Mode mode = PaintUtils::getXfermode(paint.getXfermode());
+void GlopBuilder::setFill(int color, float alphaScale, SkXfermode::Mode mode,
+ const SkShader* shader, const SkColorFilter* colorFilter) {
if (mode != SkXfermode::kClear_Mode) {
- int color = paint.getColor();
float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
if (!shader) {
float colorScale = alpha / 255.0f;
mOutGlop->fill.color = {
- alpha,
colorScale * SkColorGetR(color),
colorScale * SkColorGetG(color),
- colorScale * SkColorGetB(color)
+ colorScale * SkColorGetB(color),
+ alpha
};
} else {
- mOutGlop->fill.color = { alpha, 1, 1, 1 };
+ mOutGlop->fill.color = { 1, 1, 1, alpha };
}
} else {
- mOutGlop->fill.color = { 1, 0, 0, 0 };
+ mOutGlop->fill.color = { 0, 0, 0, 1 };
}
const bool SWAP_SRC_DST = false;
mOutGlop->blend = { GL_ZERO, GL_ZERO };
if (mOutGlop->fill.color.a < 1.0f
|| (mOutGlop->mesh.vertexFlags & kAlpha_Attrib)
+ || (mOutGlop->fill.texture && mOutGlop->fill.texture->blend)
+ || mOutGlop->roundRectClipState
|| PaintUtils::isBlendedShader(shader)
|| PaintUtils::isBlendedColorFilter(colorFilter)
|| mode != SkXfermode::kSrcOver_Mode) {
@@ -218,10 +210,10 @@
const float alpha = SkColorGetA(color) / 255.0f;
float colorScale = alpha / 255.0f;
mOutGlop->fill.filter.color = {
- alpha,
colorScale * SkColorGetR(color),
colorScale * SkColorGetG(color),
colorScale * SkColorGetB(color),
+ alpha,
};
} else if (colorFilter->asColorMatrix(srcColorMatrix)) {
mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorMatrix;
@@ -245,18 +237,173 @@
} else {
mOutGlop->fill.filterMode = ProgramDescription::kColorNone;
}
+}
+GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, bool isAlphaMaskTexture,
+ const SkPaint* paint, float alphaScale) {
+ TRIGGER_STAGE(kFillStage);
+ REQUIRE_STAGES(kMeshStage);
+
+ mOutGlop->fill.texture = &texture;
+ mOutGlop->fill.textureFilter = PaintUtils::getFilter(paint);
+ mOutGlop->fill.textureClamp = GL_CLAMP_TO_EDGE;
+
+ if (paint) {
+ int color = paint->getColor();
+ SkShader* shader = paint->getShader();
+
+ if (!isAlphaMaskTexture) {
+ // Texture defines color, so disable shaders, and reset all non-alpha color channels
+ color |= 0x00FFFFFF;
+ shader = nullptr;
+ }
+ setFill(color, alphaScale, PaintUtils::getXfermode(paint->getXfermode()),
+ shader, paint->getColorFilter());
+ } else {
+ mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale };
+
+ const bool SWAP_SRC_DST = false;
+ if (alphaScale < 1.0f
+ || (mOutGlop->mesh.vertexFlags & kAlpha_Attrib)
+ || texture.blend
+ || mOutGlop->roundRectClipState) {
+ Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
+ &mOutGlop->blend.src, &mOutGlop->blend.dst);
+ } else {
+ mOutGlop->blend = { GL_ZERO, GL_ZERO };
+ }
+ }
+
+ if (isAlphaMaskTexture) {
+ mDescription.modulate = mOutGlop->fill.color.a < 1.0f
+ || mOutGlop->fill.color.r > 0.0f
+ || mOutGlop->fill.color.g > 0.0f
+ || mOutGlop->fill.color.b > 0.0f;
+ } else {
+ mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+ }
return *this;
}
+GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale) {
+ TRIGGER_STAGE(kFillStage);
+ REQUIRE_STAGES(kMeshStage);
+
+ mOutGlop->fill.texture = nullptr;
+ mOutGlop->fill.textureFilter = GL_INVALID_ENUM;
+ mOutGlop->fill.textureClamp = GL_INVALID_ENUM;
+
+ setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
+ paint.getShader(), paint.getColorFilter());
+ mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setFillPathTexturePaint(Texture& texture,
+ const SkPaint& paint, float alphaScale) {
+ TRIGGER_STAGE(kFillStage);
+ REQUIRE_STAGES(kMeshStage);
+
+ mOutGlop->fill.texture = &texture;
+
+ //specify invalid, since these are always static for path textures
+ mOutGlop->fill.textureFilter = GL_INVALID_ENUM;
+ mOutGlop->fill.textureClamp = GL_INVALID_ENUM;
+
+ setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
+ paint.getShader(), paint.getColorFilter());
+
+ mDescription.modulate = mOutGlop->fill.color.a < 1.0f
+ || mOutGlop->fill.color.r > 0.0f
+ || mOutGlop->fill.color.g > 0.0f
+ || mOutGlop->fill.color.b > 0.0f;
+ return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Transform
+////////////////////////////////////////////////////////////////////////////////
+
+GlopBuilder& GlopBuilder::setTransformClip(const Matrix4& ortho,
+ const Matrix4& transform, bool fudgingOffset) {
+ TRIGGER_STAGE(kTransformStage);
+
+ mOutGlop->transform.ortho.load(ortho);
+ mOutGlop->transform.canvas.load(transform);
+ mOutGlop->transform.fudgingOffset = fudgingOffset;
+ return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ModelView
+////////////////////////////////////////////////////////////////////////////////
+
+GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) {
+ TRIGGER_STAGE(kModelViewStage);
+
+ mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f);
+ mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+ mOutGlop->bounds = destination;
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination) {
+ TRIGGER_STAGE(kModelViewStage);
+ REQUIRE_STAGES(kTransformStage | kFillStage);
+
+ float left = destination.left;
+ float top = destination.top;
+
+ const Matrix4& canvasTransform = mOutGlop->transform.canvas;
+ if (CC_LIKELY(canvasTransform.isPureTranslate())) {
+ const float translateX = canvasTransform.getTranslateX();
+ const float translateY = canvasTransform.getTranslateY();
+
+ left = (int) floorf(left + translateX + 0.5f) - translateX;
+ top = (int) floorf(top + translateY + 0.5f) - translateY;
+ mOutGlop->fill.textureFilter = GL_NEAREST;
+ }
+
+ mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f);
+ mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+ mOutGlop->bounds = destination;
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) {
+ TRIGGER_STAGE(kModelViewStage);
+
+ mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+ mOutGlop->bounds = source;
+ mOutGlop->bounds.translate(offsetX, offsetY);
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundRectClipState) {
+ TRIGGER_STAGE(kRoundRectClipStage);
+
+ mOutGlop->roundRectClipState = roundRectClipState;
+ mDescription.hasRoundRectClip = roundRectClipState != nullptr;
+ return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Build
+////////////////////////////////////////////////////////////////////////////////
+
void GlopBuilder::build() {
REQUIRE_STAGES(kAllStages);
- mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
mOutGlop->fill.program = mCaches.programCache.get(mDescription);
mOutGlop->transform.canvas.mapRect(mOutGlop->bounds);
+
+ // duplicates ProgramCache's definition of color uniform presence
+ const bool singleColor = !mDescription.hasTexture
+ && !mDescription.hasExternalTexture
+ && !mDescription.hasGradient
+ && !mDescription.hasBitmap;
+ mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor;
}
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index 48ce81a..d724041 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -38,25 +38,37 @@
GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop);
GlopBuilder& setMeshUnitQuad();
+ GlopBuilder& setMeshTexturedUnitQuad(const UvMapper* uvMapper, bool isAlphaMaskTexture);
GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp);
GlopBuilder& setMeshIndexedQuads(void* vertexData, int quadCount);
- GlopBuilder& setTransform(const Matrix4& ortho, const Matrix4& transform, bool fudgingOffset);
+ GlopBuilder& setFillPaint(const SkPaint& paint, float alphaScale);
+ GlopBuilder& setFillTexturePaint(Texture& texture, bool isAlphaMaskTexture,
+ const SkPaint* paint, float alphaScale);
+ GlopBuilder& setFillPathTexturePaint(Texture& texture,
+ const SkPaint& paint, float alphaScale);
+
+ GlopBuilder& setTransformClip(const Matrix4& ortho, const Matrix4& transform, bool fudgingOffset);
GlopBuilder& setModelViewMapUnitToRect(const Rect destination);
+ GlopBuilder& setModelViewMapUnitToRectSnap(const Rect destination);
GlopBuilder& setModelViewOffsetRect(float offsetX, float offsetY, const Rect source);
- GlopBuilder& setOptionalPaint(const SkPaint* paint, float alphaScale);
- GlopBuilder& setPaint(const SkPaint& paint, float alphaScale);
+ GlopBuilder& setRoundRectClipState(const RoundRectClipState* roundRectClipState);
+
void build();
private:
+ void setFill(int color, float alphaScale, SkXfermode::Mode mode,
+ const SkShader* shader, const SkColorFilter* colorFilter);
+
enum StageFlags {
kInitialStage = 0,
kMeshStage = 1 << 0,
kTransformStage = 1 << 1,
kModelViewStage = 1 << 2,
kFillStage = 1 << 3,
- kAllStages = kMeshStage | kTransformStage | kModelViewStage | kFillStage,
+ kRoundRectClipStage = 1 << 4,
+ kAllStages = kMeshStage | kFillStage | kTransformStage | kModelViewStage | kRoundRectClipStage,
} mStageFlags;
ProgramDescription mDescription;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 61cd16f..a00a2bc 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -57,16 +57,11 @@
#define EVENT_LOGD(...)
#endif
+#define USE_GLOPS true
+
namespace android {
namespace uirenderer {
-static GLenum getFilter(const SkPaint* paint) {
- if (!paint || paint->getFilterLevel() != SkPaint::kNone_FilterLevel) {
- return GL_LINEAR;
- }
- return GL_NEAREST;
-}
-
///////////////////////////////////////////////////////////////////////////////
// Globals
///////////////////////////////////////////////////////////////////////////////
@@ -1586,6 +1581,7 @@
// TODO: specify more clearly when a draw should dirty the layer.
// is writing to the stencil the only time we should ignore this?
dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
+ mDirty = true;
}
}
@@ -1611,7 +1607,7 @@
mSetShaderColor = false;
mColorSet = false;
- mColorA = mColorR = mColorG = mColorB = 0.0f;
+ mColor.a = mColor.r = mColor.g = mColor.b = 0.0f;
mTextureUnit = 0;
mTrackDirtyRegions = true;
@@ -1647,21 +1643,21 @@
}
void OpenGLRenderer::setupDrawColor(int color, int alpha) {
- mColorA = alpha / 255.0f;
- mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
- mColorG = mColorA * ((color >> 8) & 0xFF) / 255.0f;
- mColorB = mColorA * ((color ) & 0xFF) / 255.0f;
+ mColor.a = alpha / 255.0f;
+ mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
+ mColor.g = mColor.a * ((color >> 8) & 0xFF) / 255.0f;
+ mColor.b = mColor.a * ((color ) & 0xFF) / 255.0f;
mColorSet = true;
- mSetShaderColor = mDescription.setColorModulate(mColorA);
+ mSetShaderColor = mDescription.setColorModulate(mColor.a);
}
void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
- mColorA = alpha / 255.0f;
- mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
- mColorG = mColorA * ((color >> 8) & 0xFF) / 255.0f;
- mColorB = mColorA * ((color ) & 0xFF) / 255.0f;
+ mColor.a = alpha / 255.0f;
+ mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
+ mColor.g = mColor.a * ((color >> 8) & 0xFF) / 255.0f;
+ mColor.b = mColor.a * ((color ) & 0xFF) / 255.0f;
mColorSet = true;
- mSetShaderColor = mDescription.setAlpha8ColorModulate(mColorR, mColorG, mColorB, mColorA);
+ mSetShaderColor = mDescription.setAlpha8ColorModulate(mColor.r, mColor.g, mColor.b, mColor.a);
}
void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
@@ -1669,10 +1665,10 @@
}
void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
- mColorA = a;
- mColorR = r;
- mColorG = g;
- mColorB = b;
+ mColor.a = a;
+ mColor.r = r;
+ mColor.g = g;
+ mColor.b = b;
mColorSet = true;
mSetShaderColor = mDescription.setColorModulate(a);
}
@@ -1699,8 +1695,8 @@
void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
if (mColorSet && mode == SkXfermode::kClear_Mode) {
- mColorA = 1.0f;
- mColorR = mColorG = mColorB = 0.0f;
+ mColor.a = 1.0f;
+ mColor.r = mColor.g = mColor.b = 0.0f;
mSetShaderColor = mDescription.modulate = true;
}
}
@@ -1713,7 +1709,7 @@
// TODO: check shader blending, once we have shader drawing support for layers.
bool blend = layer->isBlend()
|| getLayerAlpha(layer) < 1.0f
- || (mColorSet && mColorA < 1.0f)
+ || (mColorSet && mColor.a < 1.0f)
|| PaintUtils::isBlendedColorFilter(layer->getColorFilter());
chooseBlending(blend, mode, mDescription, swapSrcDst);
}
@@ -1723,7 +1719,7 @@
// When the blending mode is kClear_Mode, we need to use a modulate color
// argb=1,0,0,0
accountForClear(mode);
- blend |= (mColorSet && mColorA < 1.0f)
+ blend |= (mColorSet && mColor.a < 1.0f)
|| (getShader(paint) && !getShader(paint)->isOpaque())
|| PaintUtils::isBlendedColorFilter(getColorFilter(paint));
chooseBlending(blend, mode, mDescription, swapSrcDst);
@@ -1775,13 +1771,13 @@
void OpenGLRenderer::setupDrawColorUniforms(bool hasShader) {
if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) {
- mCaches.program().setColor(mColorR, mColorG, mColorB, mColorA);
+ mCaches.program().setColor(mColor);
}
}
void OpenGLRenderer::setupDrawPureColorUniforms() {
if (mSetShaderColor) {
- mCaches.program().setColor(mColorR, mColorG, mColorB, mColorA);
+ mCaches.program().setColor(mColor);
}
}
@@ -1973,22 +1969,34 @@
}
}
-void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top,
- const SkPaint* paint) {
- float x = left;
- float y = top;
+void OpenGLRenderer::drawAlphaBitmap(Texture* texture, const SkPaint* paint) {
+ if (USE_GLOPS && (!paint || !paint->getShader())) {
+ Glop glop;
+ GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+ aBuilder.setMeshTexturedUnitQuad(texture->uvMapper, true)
+ .setFillTexturePaint(*texture, true, paint, currentSnapshot()->alpha)
+ .setTransformClip(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+ .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+ .build();
+ renderGlop(glop);
+ return;
+ }
+
+ float x = 0;
+ float y = 0;
texture->setWrap(GL_CLAMP_TO_EDGE, true);
bool ignoreTransform = false;
if (currentTransform()->isPureTranslate()) {
- x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
- y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
+ x = (int) floorf(currentTransform()->getTranslateX() + 0.5f);
+ y = (int) floorf(currentTransform()->getTranslateY() + 0.5f);
ignoreTransform = true;
texture->setFilter(GL_NEAREST, true);
} else {
- texture->setFilter(getFilter(paint), true);
+ texture->setFilter(PaintUtils::getFilter(paint), true);
}
// No need to check for a UV mapper on the texture object, only ARGB_8888
@@ -2013,7 +2021,7 @@
const AutoTexture autoCleanup(texture);
texture->setWrap(GL_CLAMP_TO_EDGE, true);
- texture->setFilter(pureTranslate ? GL_NEAREST : getFilter(paint), true);
+ texture->setFilter(pureTranslate ? GL_NEAREST : PaintUtils::getFilter(paint), true);
const float x = (int) floorf(bounds.left + 0.5f);
const float y = (int) floorf(bounds.top + 0.5f);
@@ -2043,9 +2051,9 @@
const AutoTexture autoCleanup(texture);
if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
- drawAlphaBitmap(texture, 0, 0, paint);
+ drawAlphaBitmap(texture, paint);
} else {
- drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint);
+ drawTextureRect(texture, paint);
}
mDirty = true;
@@ -2130,7 +2138,7 @@
const AutoTexture autoCleanup(texture);
texture->setWrap(GL_CLAMP_TO_EDGE, true);
- texture->setFilter(getFilter(paint), true);
+ texture->setFilter(PaintUtils::getFilter(paint), true);
int alpha;
SkXfermode::Mode mode;
@@ -2213,10 +2221,10 @@
dstLeft = x;
dstTop = y;
- texture->setFilter(scaled ? getFilter(paint) : GL_NEAREST, true);
+ texture->setFilter(scaled ? PaintUtils::getFilter(paint) : GL_NEAREST, true);
ignoreTransform = true;
} else {
- texture->setFilter(getFilter(paint), true);
+ texture->setFilter(PaintUtils::getFilter(paint), true);
}
if (CC_UNLIKELY(useScaleTransform)) {
@@ -2350,15 +2358,16 @@
return;
}
- if (!paint->getShader() && !currentSnapshot()->roundRectClipState) {
+ if (USE_GLOPS && !paint->getShader()) {
Glop glop;
GlopBuilder aBuilder(mRenderState, mCaches, &glop);
bool fudgeOffset = displayFlags & kVertexBuffer_Offset;
bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
aBuilder.setMeshVertexBuffer(vertexBuffer, shadowInterp)
- .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset)
+ .setFillPaint(*paint, currentSnapshot()->alpha)
+ .setTransformClip(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset)
.setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
- .setPaint(*paint, currentSnapshot()->alpha)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
return;
@@ -2496,7 +2505,7 @@
mDirty = true;
}
-void OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture,
+void OpenGLRenderer::drawShape(float left, float top, PathTexture* texture,
const SkPaint* paint) {
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -2519,7 +2528,7 @@
if (p->getPathEffect() != nullptr) {
mCaches.textureState().activateTexture(0);
- const PathTexture* texture = mCaches.pathCache.getRoundRect(
+ PathTexture* texture = mCaches.pathCache.getRoundRect(
right - left, bottom - top, rx, ry, p);
drawShape(left, top, texture, p);
} else {
@@ -2537,7 +2546,7 @@
}
if (p->getPathEffect() != nullptr) {
mCaches.textureState().activateTexture(0);
- const PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
+ PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
drawShape(x - radius, y - radius, texture, p);
} else {
SkPath path;
@@ -2560,7 +2569,7 @@
if (p->getPathEffect() != nullptr) {
mCaches.textureState().activateTexture(0);
- const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
+ PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
drawShape(left, top, texture, p);
} else {
SkPath path;
@@ -2584,7 +2593,7 @@
// TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) {
mCaches.textureState().activateTexture(0);
- const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
+ PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
startAngle, sweepAngle, useCenter, p);
drawShape(left, top, texture, p);
return;
@@ -2621,7 +2630,7 @@
if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join ||
p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
mCaches.textureState().activateTexture(0);
- const PathTexture* texture =
+ PathTexture* texture =
mCaches.pathCache.getRect(right - left, bottom - top, p);
drawShape(left, top, texture, p);
} else {
@@ -2965,7 +2974,7 @@
mCaches.textureState().activateTexture(0);
- const PathTexture* texture = mCaches.pathCache.get(path, paint);
+ PathTexture* texture = mCaches.pathCache.get(path, paint);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -3098,12 +3107,26 @@
return texture;
}
-void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
+void OpenGLRenderer::drawPathTexture(PathTexture* texture,
float x, float y, const SkPaint* paint) {
if (quickRejectSetupScissor(x, y, x + texture->width, y + texture->height)) {
return;
}
+ if (USE_GLOPS && !paint->getShader()) {
+ Glop glop;
+ GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+ aBuilder.setMeshTexturedUnitQuad(nullptr, true)
+ .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha)
+ .setTransformClip(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+ .setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height))
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+ .build();
+ renderGlop(glop);
+ return;
+ }
+
+
int alpha;
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
@@ -3251,14 +3274,15 @@
return;
}
- if (!paint->getShader() && !currentSnapshot()->roundRectClipState) {
+ if (USE_GLOPS && !paint->getShader()) {
const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
Glop glop;
GlopBuilder aBuilder(mRenderState, mCaches, &glop);
aBuilder.setMeshIndexedQuads(&mesh[0], count / 4)
- .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
+ .setFillPaint(*paint, currentSnapshot()->alpha)
+ .setTransformClip(currentSnapshot()->getOrthoMatrix(), transform, false)
.setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
- .setPaint(*paint, currentSnapshot()->alpha)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
return;
@@ -3296,14 +3320,15 @@
void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
const SkPaint* paint, bool ignoreTransform) {
- if (!paint->getShader() && !currentSnapshot()->roundRectClipState) {
+ if (USE_GLOPS && !paint->getShader()) {
const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
Glop glop;
GlopBuilder aBuilder(mRenderState, mCaches, &glop);
aBuilder.setMeshUnitQuad()
- .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
+ .setFillPaint(*paint, currentSnapshot()->alpha)
+ .setTransformClip(currentSnapshot()->getOrthoMatrix(), transform, false)
.setModelViewMapUnitToRect(Rect(left, top, right, bottom))
- .setPaint(*paint, currentSnapshot()->alpha)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
return;
@@ -3332,8 +3357,20 @@
glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
}
-void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
- Texture* texture, const SkPaint* paint) {
+void OpenGLRenderer::drawTextureRect(Texture* texture, const SkPaint* paint) {
+ if (USE_GLOPS) {
+ Glop glop;
+ GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+ aBuilder.setMeshTexturedUnitQuad(texture->uvMapper, false)
+ .setFillTexturePaint(*texture, false, paint, currentSnapshot()->alpha)
+ .setTransformClip(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+ .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+ .build();
+ renderGlop(glop);
+ return;
+ }
+
texture->setWrap(GL_CLAMP_TO_EDGE, true);
GLvoid* vertices = (GLvoid*) nullptr;
@@ -3350,16 +3387,16 @@
}
if (CC_LIKELY(currentTransform()->isPureTranslate())) {
- const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
- const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
+ const float x = (int) floorf(currentTransform()->getTranslateX() + 0.5f);
+ const float y = (int) floorf(currentTransform()->getTranslateY() + 0.5f);
texture->setFilter(GL_NEAREST, true);
drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
paint, texture->blend, vertices, texCoords,
GL_TRIANGLE_STRIP, kUnitQuadCount, false, true);
} else {
- texture->setFilter(getFilter(paint), true);
- drawTextureMesh(left, top, right, bottom, texture->id, paint,
+ texture->setFilter(PaintUtils::getFilter(paint), true);
+ drawTextureMesh(0, 0, texture->width, texture->height, texture->id, paint,
texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, kUnitQuadCount);
}
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index f097041..851effa5 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -690,18 +690,16 @@
* @param texture The texture reprsenting the shape
* @param paint The paint to draw the shape with
*/
- void drawShape(float left, float top, const PathTexture* texture, const SkPaint* paint);
+ void drawShape(float left, float top, PathTexture* texture, const SkPaint* paint);
/**
* Draws the specified texture as an alpha bitmap. Alpha bitmaps obey
* different compositing rules.
*
* @param texture The texture to draw with
- * @param left The x coordinate of the bitmap
- * @param top The y coordinate of the bitmap
* @param paint The paint to render with
*/
- void drawAlphaBitmap(Texture* texture, float left, float top, const SkPaint* paint);
+ void drawAlphaBitmap(Texture* texture, const SkPaint* paint);
/**
* Renders a strip of polygons with the specified paint, used for tessellated geometry.
@@ -730,18 +728,12 @@
void drawConvexPath(const SkPath& path, const SkPaint* paint);
/**
- * Draws a textured rectangle with the specified texture. The specified coordinates
- * are transformed by the current snapshot's transform matrix.
+ * Draws a textured rectangle with the specified texture.
*
- * @param left The left coordinate of the rectangle
- * @param top The top coordinate of the rectangle
- * @param right The right coordinate of the rectangle
- * @param bottom The bottom coordinate of the rectangle
* @param texture The texture to use
* @param paint The paint containing the alpha, blending mode, etc.
*/
- void drawTextureRect(float left, float top, float right, float bottom,
- Texture* texture, const SkPaint* paint);
+ void drawTextureRect(Texture* texture, const SkPaint* paint);
/**
* Draws a textured mesh with the specified texture. If the indices are omitted,
@@ -827,7 +819,7 @@
* @param y The y coordinate where the texture will be drawn
* @param paint The paint to draw the texture with
*/
- void drawPathTexture(const PathTexture* texture, float x, float y, const SkPaint* paint);
+ void drawPathTexture(PathTexture* texture, float x, float y, const SkPaint* paint);
/**
* Resets the texture coordinates stored in mMeshVertices. Setting the values
@@ -1010,7 +1002,7 @@
ProgramDescription mDescription;
// Color description
bool mColorSet;
- float mColorA, mColorR, mColorG, mColorB;
+ FloatColor mColor;
// Indicates that the shader should get a color
bool mSetShaderColor;
// Current texture unit
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 5f34b34..32713e9b 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -177,12 +177,12 @@
glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]);
}
-void Program::setColor(const float r, const float g, const float b, const float a) {
+void Program::setColor(FloatColor color) {
if (!mHasColorUniform) {
mColorUniform = getUniform("color");
mHasColorUniform = true;
}
- glUniform4f(mColorUniform, r, g, b, a);
+ glUniform4f(mColorUniform, color.r, color.g, color.b, color.a);
}
void Program::use() {
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 01231b5..af1e4a7 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -25,6 +25,7 @@
#include <SkXfermode.h>
#include "Debug.h"
+#include "FloatColor.h"
#include "Matrix.h"
#include "Properties.h"
@@ -363,7 +364,7 @@
/**
* Sets the color associated with this shader.
*/
- void setColor(const float r, const float g, const float b, const float a);
+ void setColor(FloatColor color);
/**
* Name of the texCoords attribute if it exists (kBindingTexCoords), -1 otherwise.
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index 5b80bbd..fd3845d 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -19,11 +19,9 @@
#include "Vector.h"
-#include <type_traits>
+#include "utils/Macros.h"
-#define REQUIRE_COMPATIBLE_LAYOUT(TARGET_TYPE) \
- static_assert(std::is_standard_layout<TARGET_TYPE>::value, \
- #TARGET_TYPE " must have standard layout")
+#include <type_traits>
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp
index c751dba..789f6cc 100644
--- a/libs/hwui/renderstate/Blend.cpp
+++ b/libs/hwui/renderstate/Blend.cpp
@@ -119,7 +119,7 @@
mEnabled = true;
}
- if (srcMode != mSrcMode || dstMode != mSrcMode) {
+ if (srcMode != mSrcMode || dstMode != mDstMode) {
glBlendFunc(srcMode, dstMode);
mSrcMode = srcMode;
mDstMode = dstMode;
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 6394dc1..e35327b 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -209,23 +209,25 @@
void RenderState::render(const Glop& glop) {
const Glop::Mesh& mesh = glop.mesh;
- const Glop::Fill& shader = glop.fill;
+ const Glop::Fill& fill = glop.fill;
- // --------------------------------------------
- // ---------- Shader + uniform setup ----------
- // --------------------------------------------
- mCaches->setProgram(shader.program);
+ // ---------------------------------------------
+ // ---------- Program + uniform setup ----------
+ // ---------------------------------------------
+ mCaches->setProgram(fill.program);
- Glop::FloatColor color = shader.color;
- shader.program->setColor(color.r, color.g, color.b, color.a);
+ if (fill.colorEnabled) {
+ fill.program->setColor(fill.color);
+ }
- shader.program->set(glop.transform.ortho,
+ fill.program->set(glop.transform.ortho,
glop.transform.modelView,
glop.transform.canvas,
glop.transform.fudgingOffset);
+ // Color filter uniforms
if (glop.fill.filterMode == ProgramDescription::kColorBlend) {
- const Glop::FloatColor& color = glop.fill.filter.color;
+ const FloatColor& color = glop.fill.filter.color;
glUniform4f(mCaches->program().getUniform("colorBlend"),
color.r, color.g, color.b, color.a);
} else if (glop.fill.filterMode == ProgramDescription::kColorMatrix) {
@@ -235,11 +237,28 @@
glop.fill.filter.matrix.vector);
}
+ // Round rect clipping uniforms
+ if (glop.roundRectClipState) {
+ // TODO: avoid query, and cache values (or RRCS ptr) in program
+ const RoundRectClipState* state = glop.roundRectClipState;
+ const Rect& innerRect = state->innerRect;
+ glUniform4f(fill.program->getUniform("roundRectInnerRectLTRB"),
+ innerRect.left, innerRect.top,
+ innerRect.right, innerRect.bottom);
+ glUniformMatrix4fv(fill.program->getUniform("roundRectInvTransform"),
+ 1, GL_FALSE, &state->matrix.data[0]);
+
+ // add half pixel to round out integer rect space to cover pixel centers
+ float roundedOutRadius = state->radius + 0.5f;
+ glUniform1f(fill.program->getUniform("roundRectRadius"),
+ roundedOutRadius);
+ }
+
// --------------------------------
// ---------- Mesh setup ----------
// --------------------------------
// vertices
- bool force = meshState().bindMeshBufferInternal(mesh.vertexBufferObject)
+ const bool force = meshState().bindMeshBufferInternal(mesh.vertexBufferObject)
|| (mesh.vertices != nullptr);
meshState().bindPositionVertexPointer(force, mesh.vertices, mesh.stride);
@@ -247,19 +266,30 @@
meshState().bindIndicesBufferInternal(mesh.indexBufferObject);
if (mesh.vertexFlags & kTextureCoord_Attrib) {
- // TODO: support textures
- LOG_ALWAYS_FATAL("textures not yet supported");
+ // TODO: to support shaders, increment texture unit
+ mCaches->textureState().activateTexture(0);
+
+ if (glop.fill.textureClamp != GL_INVALID_ENUM) {
+ glop.fill.texture->setWrap(glop.fill.textureClamp, true);
+ }
+ if (glop.fill.textureFilter != GL_INVALID_ENUM) {
+ glop.fill.texture->setFilter(glop.fill.textureFilter, true);
+ }
+
+ mCaches->textureState().bindTexture(fill.texture->id);
+ meshState().enableTexCoordsVertexArray();
+ meshState().bindTexCoordsVertexPointer(force, mesh.texCoordOffset);
} else {
meshState().disableTexCoordsVertexArray();
}
if (mesh.vertexFlags & kColor_Attrib) {
LOG_ALWAYS_FATAL("color vertex attribute not yet supported");
- // TODO: enable color, disable when done
+ // TODO: enable color attribute, disable when done
}
int alphaSlot = -1;
if (mesh.vertexFlags & kAlpha_Attrib) {
const void* alphaCoords = ((const GLbyte*) glop.mesh.vertices) + kVertexAlphaOffset;
- alphaSlot = shader.program->getAttrib("vtxAlpha");
+ alphaSlot = fill.program->getAttrib("vtxAlpha");
glEnableVertexAttribArray(alphaSlot);
glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
}
@@ -275,7 +305,7 @@
if (mesh.indexBufferObject == meshState().getQuadListIBO()) {
// Since the indexed quad list is of limited length, we loop over
// the glDrawXXX method while updating the vertex pointer
- GLsizei elementsCount = mesh.vertexCount;
+ GLsizei elementsCount = mesh.elementCount;
const GLbyte* vertices = static_cast<const GLbyte*>(mesh.vertices);
while (elementsCount > 0) {
GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
@@ -287,9 +317,9 @@
vertices += (drawCount / 6) * 4 * mesh.stride;
}
} else if (mesh.indexBufferObject || mesh.indices) {
- glDrawElements(mesh.primitiveMode, mesh.vertexCount, GL_UNSIGNED_SHORT, mesh.indices);
+ glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT, mesh.indices);
} else {
- glDrawArrays(mesh.primitiveMode, 0, mesh.vertexCount);
+ glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount);
}
// -----------------------------------
diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h
index fe43fdbb..eae73a9 100644
--- a/libs/hwui/utils/Macros.h
+++ b/libs/hwui/utils/Macros.h
@@ -29,4 +29,8 @@
friend inline int compare_type(const Type& lhs, const Type& rhs) { return lhs.compare(rhs); } \
friend inline hash_t hash_type(const Type& entry) { return entry.hash(); }
+#define REQUIRE_COMPATIBLE_LAYOUT(Type) \
+ static_assert(std::is_standard_layout<Type>::value, \
+ #Type " must have standard layout")
+
#endif /* MACROS_H */
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
index 679e2bf..1a5cbf8 100644
--- a/libs/hwui/utils/PaintUtils.h
+++ b/libs/hwui/utils/PaintUtils.h
@@ -37,6 +37,13 @@
return resultMode;
}
+ static inline GLenum getFilter(const SkPaint* paint) {
+ if (!paint || paint->getFilterLevel() != SkPaint::kNone_FilterLevel) {
+ return GL_LINEAR;
+ }
+ return GL_NEAREST;
+ }
+
// TODO: move to a method on android:Paint? replace with SkPaint::nothingToDraw()?
static inline bool paintWillNotDraw(const SkPaint& paint) {
return paint.getAlpha() == 0
diff --git a/location/java/android/location/GpsClock.java b/location/java/android/location/GpsClock.java
index 22ac1a9..4135a1c 100644
--- a/location/java/android/location/GpsClock.java
+++ b/location/java/android/location/GpsClock.java
@@ -19,7 +19,6 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Log;
/**
* A class containing a GPS clock timestamp.
@@ -29,7 +28,6 @@
*/
@SystemApi
public class GpsClock implements Parcelable {
- private static final String TAG = "GpsClock";
// The following enumerations must be in sync with the values declared in gps.h
@@ -109,17 +107,7 @@
* Sets the type of time reported.
*/
public void setType(byte value) {
- switch (value) {
- case TYPE_UNKNOWN:
- case TYPE_GPS_TIME:
- case TYPE_LOCAL_HW_TIME:
- mType = value;
- break;
- default:
- Log.d(TAG, "Sanitizing invalid 'type': " + value);
- mType = TYPE_UNKNOWN;
- break;
- }
+ mType = value;
}
/**
@@ -135,7 +123,7 @@
case TYPE_LOCAL_HW_TIME:
return "LocalHwClock";
default:
- return "<Invalid>";
+ return "<Invalid:" + mType + ">";
}
}
diff --git a/location/java/android/location/GpsMeasurement.java b/location/java/android/location/GpsMeasurement.java
index 1c50181..05bcf79 100644
--- a/location/java/android/location/GpsMeasurement.java
+++ b/location/java/android/location/GpsMeasurement.java
@@ -19,7 +19,6 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Log;
/**
* A class representing a GPS satellite measurement, containing raw and computed information.
@@ -28,8 +27,6 @@
*/
@SystemApi
public class GpsMeasurement implements Parcelable {
- private static final String TAG = "GpsMeasurement";
-
private int mFlags;
private byte mPrn;
private double mTimeOffsetInNs;
@@ -140,6 +137,12 @@
public static final short STATE_TOW_DECODED = (1<<3);
/**
+ * All the GPS receiver state flags.
+ */
+ private static final short STATE_ALL =
+ STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_SUBFRAME_SYNC | STATE_TOW_DECODED;
+
+ /**
* The state of the 'Accumulated Delta Range' is invalid or unknown.
*/
public static final short ADR_STATE_UNKNOWN = 0;
@@ -159,6 +162,11 @@
*/
public static final short ADR_STATE_CYCLE_SLIP = (1<<2);
+ /**
+ * All the 'Accumulated Delta Range' flags.
+ */
+ private static final short ADR_ALL = ADR_STATE_VALID | ADR_STATE_RESET | ADR_STATE_CYCLE_SLIP;
+
// End enumerations in sync with gps.h
GpsMeasurement() {
@@ -263,19 +271,7 @@
* Sets the sync state.
*/
public void setState(short value) {
- switch (value) {
- case STATE_UNKNOWN:
- case STATE_BIT_SYNC:
- case STATE_CODE_LOCK:
- case STATE_SUBFRAME_SYNC:
- case STATE_TOW_DECODED:
- mState = value;
- break;
- default:
- Log.d(TAG, "Sanitizing invalid 'sync state': " + value);
- mState = STATE_UNKNOWN;
- break;
- }
+ mState = value;
}
/**
@@ -283,20 +279,30 @@
* For internal and logging use only.
*/
private String getStateString() {
- switch (mState) {
- case STATE_UNKNOWN:
- return "Unknown";
- case STATE_BIT_SYNC:
- return "BitSync";
- case STATE_CODE_LOCK:
- return "CodeLock";
- case STATE_SUBFRAME_SYNC:
- return "SubframeSync";
- case STATE_TOW_DECODED:
- return "TowDecoded";
- default:
- return "<Invalid>";
+ if (mState == STATE_UNKNOWN) {
+ return "Unknown";
}
+ StringBuilder builder = new StringBuilder();
+ if ((mState & STATE_CODE_LOCK) == STATE_CODE_LOCK) {
+ builder.append("CodeLock|");
+ }
+ if ((mState & STATE_BIT_SYNC) == STATE_BIT_SYNC) {
+ builder.append("BitSync|");
+ }
+ if ((mState & STATE_SUBFRAME_SYNC) == STATE_SUBFRAME_SYNC) {
+ builder.append("SubframeSync|");
+ }
+ if ((mState & STATE_TOW_DECODED) == STATE_TOW_DECODED) {
+ builder.append("TowDecoded|");
+ }
+ int remainingStates = mState & ~STATE_ALL;
+ if (remainingStates > 0) {
+ builder.append("Other(");
+ builder.append(Integer.toBinaryString(remainingStates));
+ builder.append(")|");
+ }
+ builder.deleteCharAt(builder.length() - 1);
+ return builder.toString();
}
/**
@@ -395,18 +401,7 @@
* Sets the 'Accumulated Delta Range' state.
*/
public void setAccumulatedDeltaRangeState(short value) {
- switch (value) {
- case ADR_STATE_UNKNOWN:
- case ADR_STATE_VALID:
- case ADR_STATE_RESET:
- case ADR_STATE_CYCLE_SLIP:
- mAccumulatedDeltaRangeState = value;
- break;
- default:
- Log.d(TAG, "Sanitizing invalid 'Accumulated Delta Range state': " + value);
- mAccumulatedDeltaRangeState = ADR_STATE_UNKNOWN;
- break;
- }
+ mAccumulatedDeltaRangeState = value;
}
/**
@@ -414,18 +409,27 @@
* For internal and logging use only.
*/
private String getAccumulatedDeltaRangeStateString() {
- switch (mAccumulatedDeltaRangeState) {
- case ADR_STATE_UNKNOWN:
- return "Unknown";
- case ADR_STATE_VALID:
- return "Valid";
- case ADR_STATE_RESET:
- return "Reset";
- case ADR_STATE_CYCLE_SLIP:
- return "CycleSlip";
- default:
- return "<Invalid>";
+ if (mAccumulatedDeltaRangeState == ADR_STATE_UNKNOWN) {
+ return "Unknown";
}
+ StringBuilder builder = new StringBuilder();
+ if ((mAccumulatedDeltaRangeState & ADR_STATE_VALID) == ADR_STATE_VALID) {
+ builder.append("Valid|");
+ }
+ if ((mAccumulatedDeltaRangeState & ADR_STATE_RESET) == ADR_STATE_RESET) {
+ builder.append("Reset|");
+ }
+ if ((mAccumulatedDeltaRangeState & ADR_STATE_CYCLE_SLIP) == ADR_STATE_CYCLE_SLIP) {
+ builder.append("CycleSlip|");
+ }
+ int remainingStates = mAccumulatedDeltaRangeState & ~ADR_ALL;
+ if (remainingStates > 0) {
+ builder.append("Other(");
+ builder.append(Integer.toBinaryString(remainingStates));
+ builder.append(")|");
+ }
+ builder.deleteCharAt(builder.length() - 1);
+ return builder.toString();
}
/**
@@ -744,17 +748,7 @@
* Sets the 'loss of lock' status.
*/
public void setLossOfLock(byte value) {
- switch (value) {
- case LOSS_OF_LOCK_UNKNOWN:
- case LOSS_OF_LOCK_OK:
- case LOSS_OF_LOCK_CYCLE_SLIP:
- mLossOfLock = value;
- break;
- default:
- Log.d(TAG, "Sanitizing invalid 'loss of lock': " + value);
- mLossOfLock = LOSS_OF_LOCK_UNKNOWN;
- break;
- }
+ mLossOfLock = value;
}
/**
@@ -770,7 +764,7 @@
case LOSS_OF_LOCK_CYCLE_SLIP:
return "CycleSlip";
default:
- return "<Invalid>";
+ return "<Invalid:" + mLossOfLock + ">";
}
}
@@ -919,17 +913,7 @@
* Sets the 'multi-path' indicator.
*/
public void setMultipathIndicator(byte value) {
- switch (value) {
- case MULTIPATH_INDICATOR_UNKNOWN:
- case MULTIPATH_INDICATOR_DETECTED:
- case MULTIPATH_INDICATOR_NOT_USED:
- mMultipathIndicator = value;
- break;
- default:
- Log.d(TAG, "Sanitizing invalid 'muti-path indicator': " + value);
- mMultipathIndicator = MULTIPATH_INDICATOR_UNKNOWN;
- break;
- }
+ mMultipathIndicator = value;
}
/**
@@ -945,7 +929,7 @@
case MULTIPATH_INDICATOR_NOT_USED:
return "NotUsed";
default:
- return "<Invalid>";
+ return "<Invalid:" + mMultipathIndicator + ">";
}
}
diff --git a/location/java/android/location/GpsNavigationMessage.java b/location/java/android/location/GpsNavigationMessage.java
index 42f8ee4..b893f3f 100644
--- a/location/java/android/location/GpsNavigationMessage.java
+++ b/location/java/android/location/GpsNavigationMessage.java
@@ -20,7 +20,6 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Log;
import java.security.InvalidParameterException;
@@ -31,7 +30,7 @@
*/
@SystemApi
public class GpsNavigationMessage implements Parcelable {
- private static final String TAG = "GpsNavigationMessage";
+
private static final byte[] EMPTY_ARRAY = new byte[0];
// The following enumerations must be in sync with the values declared in gps.h
@@ -102,19 +101,7 @@
* Sets the type of the navigation message.
*/
public void setType(byte value) {
- switch (value) {
- case TYPE_UNKNOWN:
- case TYPE_L1CA:
- case TYPE_L2CNAV:
- case TYPE_L5CNAV:
- case TYPE_CNAV2:
- mType = value;
- break;
- default:
- Log.d(TAG, "Sanitizing invalid 'type': " + value);
- mType = TYPE_UNKNOWN;
- break;
- }
+ mType = value;
}
/**
@@ -134,7 +121,7 @@
case TYPE_CNAV2:
return "CNAV-2";
default:
- return "<Invalid>";
+ return "<Invalid:" + mType + ">";
}
}
diff --git a/packages/PrintSpooler/res/values-si-rLK/strings.xml b/packages/PrintSpooler/res/values-si-rLK/strings.xml
index a3518e1..dae8a02 100644
--- a/packages/PrintSpooler/res/values-si-rLK/strings.xml
+++ b/packages/PrintSpooler/res/values-si-rLK/strings.xml
@@ -24,7 +24,7 @@
<string name="label_paper_size" msgid="908654383827777759">"කඩදාසියේ ප්රමාණය"</string>
<string name="label_paper_size_summary" msgid="5668204981332138168">"කඩදාසියේ ප්රමාණය:"</string>
<string name="label_color" msgid="1108690305218188969">"වර්ණය"</string>
- <string name="label_duplex" msgid="1263181386446435253">"දෙපත්"</string>
+ <string name="label_duplex" msgid="1263181386446435253">"ඩුප්ලෙක්ස්"</string>
<string name="label_orientation" msgid="2853142581990496477">"දිශානතිය"</string>
<string name="label_pages" msgid="7768589729282182230">"පිටු"</string>
<string name="template_all_pages" msgid="3322235982020148762">"සියලුම <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk
index c16f7b6..2b833b2 100644
--- a/packages/SettingsProvider/Android.mk
+++ b/packages/SettingsProvider/Android.mk
@@ -3,7 +3,8 @@
LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES := $(call all-subdir-java-files) \
+ src/com/android/providers/settings/EventLogTags.logtags
LOCAL_JAVA_LIBRARIES := telephony-common ims-common
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 06e26bd..729efcb 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -58,6 +58,7 @@
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* Database helper class for {@link SettingsProvider}.
@@ -78,6 +79,9 @@
private static final HashSet<String> mValidTables = new HashSet<String>();
+ private static final String DATABASE_JOURNAL_SUFFIX = "-journal";
+ private static final String DATABASE_BACKUP_SUFFIX = "-backup";
+
private static final String TABLE_SYSTEM = "system";
private static final String TABLE_SECURE = "secure";
private static final String TABLE_GLOBAL = "global";
@@ -86,13 +90,13 @@
mValidTables.add(TABLE_SYSTEM);
mValidTables.add(TABLE_SECURE);
mValidTables.add(TABLE_GLOBAL);
- mValidTables.add("bluetooth_devices");
- mValidTables.add("bookmarks");
// These are old.
+ mValidTables.add("bluetooth_devices");
+ mValidTables.add("bookmarks");
mValidTables.add("favorites");
- mValidTables.add("gservices");
mValidTables.add("old_favorites");
+ mValidTables.add("android_metadata");
}
static String dbNameForUser(final int userHandle) {
@@ -118,6 +122,33 @@
return mValidTables.contains(name);
}
+ public void dropDatabase() {
+ close();
+ File databaseFile = mContext.getDatabasePath(getDatabaseName());
+ if (databaseFile.exists()) {
+ databaseFile.delete();
+ }
+ File databaseJournalFile = mContext.getDatabasePath(getDatabaseName()
+ + DATABASE_JOURNAL_SUFFIX);
+ if (databaseJournalFile.exists()) {
+ databaseJournalFile.delete();
+ }
+ }
+
+ public void backupDatabase() {
+ close();
+ File databaseFile = mContext.getDatabasePath(getDatabaseName());
+ if (!databaseFile.exists()) {
+ return;
+ }
+ File backupFile = mContext.getDatabasePath(getDatabaseName()
+ + DATABASE_BACKUP_SUFFIX);
+ if (backupFile.exists()) {
+ return;
+ }
+ databaseFile.renameTo(backupFile);
+ }
+
private void createSecureTable(SQLiteDatabase db) {
db.execSQL("CREATE TABLE secure (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
@@ -1221,9 +1252,11 @@
// Migrate now-global settings. Note that this happens before
// new users can be created.
createGlobalTable(db);
- String[] settingsToMove = hashsetToStringArray(SettingsProvider.sSystemGlobalKeys);
+ String[] settingsToMove = setToStringArray(
+ SettingsProvider.sSystemMovedToGlobalSettings);
moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove, false);
- settingsToMove = hashsetToStringArray(SettingsProvider.sSecureGlobalKeys);
+ settingsToMove = setToStringArray(
+ SettingsProvider.sSecureMovedToGlobalSettings);
moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, false);
db.setTransactionSuccessful();
@@ -1489,9 +1522,11 @@
db.beginTransaction();
try {
// Migrate now-global settings
- String[] settingsToMove = hashsetToStringArray(SettingsProvider.sSystemGlobalKeys);
+ String[] settingsToMove = setToStringArray(
+ SettingsProvider.sSystemMovedToGlobalSettings);
moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove, true);
- settingsToMove = hashsetToStringArray(SettingsProvider.sSecureGlobalKeys);
+ settingsToMove = setToStringArray(
+ SettingsProvider.sSecureMovedToGlobalSettings);
moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, true);
db.setTransactionSuccessful();
@@ -1855,7 +1890,8 @@
try {
stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
+ " VALUES(?,?);");
- loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
+ loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED,
+ ImsConfig.FeatureValueConstants.ON);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
@@ -1895,34 +1931,50 @@
}
upgradeVersion = 118;
}
+
+ /**
+ * IMPORTANT: Do not add any more upgrade steps here as the global,
+ * secure, and system settings are no longer stored in a database
+ * but are kept in memory and persisted to XML. The correct places
+ * for adding upgrade steps are:
+ *
+ * Global: SettingsProvider.UpgradeController#onUpgradeGlobalSettings
+ * Secure: SettingsProvider.UpgradeController#onUpgradeSecureSettings
+ * System: SettingsProvider.UpgradeController#onUpgradeSystemSettings
+ */
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
- Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
- + ", must wipe the settings provider");
- db.execSQL("DROP TABLE IF EXISTS global");
- db.execSQL("DROP TABLE IF EXISTS globalIndex1");
- db.execSQL("DROP TABLE IF EXISTS system");
- db.execSQL("DROP INDEX IF EXISTS systemIndex1");
- db.execSQL("DROP TABLE IF EXISTS secure");
- db.execSQL("DROP INDEX IF EXISTS secureIndex1");
- db.execSQL("DROP TABLE IF EXISTS gservices");
- db.execSQL("DROP INDEX IF EXISTS gservicesIndex1");
- db.execSQL("DROP TABLE IF EXISTS bluetooth_devices");
- db.execSQL("DROP TABLE IF EXISTS bookmarks");
- db.execSQL("DROP INDEX IF EXISTS bookmarksIndex1");
- db.execSQL("DROP INDEX IF EXISTS bookmarksIndex2");
- db.execSQL("DROP TABLE IF EXISTS favorites");
- onCreate(db);
-
- // Added for diagnosing settings.db wipes after the fact
- String wipeReason = oldVersion + "/" + upgradeVersion + "/" + currentVersion;
- db.execSQL("INSERT INTO secure(name,value) values('" +
- "wiped_db_reason" + "','" + wipeReason + "');");
+ recreateDatabase(db, oldVersion, upgradeVersion, currentVersion);
}
}
- private String[] hashsetToStringArray(HashSet<String> set) {
+ public void recreateDatabase(SQLiteDatabase db, int oldVersion,
+ int upgradeVersion, int currentVersion) {
+ db.execSQL("DROP TABLE IF EXISTS global");
+ db.execSQL("DROP TABLE IF EXISTS globalIndex1");
+ db.execSQL("DROP TABLE IF EXISTS system");
+ db.execSQL("DROP INDEX IF EXISTS systemIndex1");
+ db.execSQL("DROP TABLE IF EXISTS secure");
+ db.execSQL("DROP INDEX IF EXISTS secureIndex1");
+ db.execSQL("DROP TABLE IF EXISTS gservices");
+ db.execSQL("DROP INDEX IF EXISTS gservicesIndex1");
+ db.execSQL("DROP TABLE IF EXISTS bluetooth_devices");
+ db.execSQL("DROP TABLE IF EXISTS bookmarks");
+ db.execSQL("DROP INDEX IF EXISTS bookmarksIndex1");
+ db.execSQL("DROP INDEX IF EXISTS bookmarksIndex2");
+ db.execSQL("DROP TABLE IF EXISTS favorites");
+
+ onCreate(db);
+
+ // Added for diagnosing settings.db wipes after the fact
+ String wipeReason = oldVersion + "/" + upgradeVersion + "/" + currentVersion;
+ db.execSQL("INSERT INTO secure(name,value) values('" +
+ "wiped_db_reason" + "','" + wipeReason + "');");
+ }
+
+ private String[] setToStringArray(Set<String> set) {
String[] array = new String[set.size()];
return set.toArray(array);
}
@@ -2639,7 +2691,8 @@
loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
R.bool.def_guest_user_enabled);
- loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
+ loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED,
+ ImsConfig.FeatureValueConstants.ON);
// --- New global settings start here
} finally {
if (stmt != null) stmt.close();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/EventLogTags.logtags b/packages/SettingsProvider/src/com/android/providers/settings/EventLogTags.logtags
new file mode 100644
index 0000000..298d776
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/EventLogTags.logtags
@@ -0,0 +1,5 @@
+# See system/core/logcat/e for a description of the format of this file.
+
+option java_package com.android.providers.settings;
+
+52100 unsupported_settings_query (uri|3),(selection|3),(whereArgs|3)
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 264dcae..8371117 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -110,11 +110,7 @@
private static final String TAG = "SettingsBackupAgent";
- private static final int COLUMN_NAME = 1;
- private static final int COLUMN_VALUE = 2;
-
private static final String[] PROJECTION = {
- Settings.NameValueTable._ID,
Settings.NameValueTable.NAME,
Settings.NameValueTable.VALUE
};
@@ -473,8 +469,8 @@
ParcelFileDescriptor newState) throws IOException {
HashSet<String> movedToGlobal = new HashSet<String>();
- Settings.System.getMovedKeys(movedToGlobal);
- Settings.Secure.getMovedKeys(movedToGlobal);
+ Settings.System.getMovedToGlobalSettings(movedToGlobal);
+ Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
while (data.readNextHeader()) {
final String key = data.getKey();
@@ -577,8 +573,8 @@
if (version <= FULL_BACKUP_VERSION) {
// Generate the moved-to-global lookup table
HashSet<String> movedToGlobal = new HashSet<String>();
- Settings.System.getMovedKeys(movedToGlobal);
- Settings.Secure.getMovedKeys(movedToGlobal);
+ Settings.System.getMovedToGlobalSettings(movedToGlobal);
+ Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
// system settings data first
int nBytes = in.readInt();
@@ -824,11 +820,14 @@
String key = settings[i];
String value = cachedEntries.remove(key);
+ final int nameColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME);
+ final int valueColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
+
// If the value not cached, let us look it up.
if (value == null) {
while (!cursor.isAfterLast()) {
- String cursorKey = cursor.getString(COLUMN_NAME);
- String cursorValue = cursor.getString(COLUMN_VALUE);
+ String cursorKey = cursor.getString(nameColumnIndex);
+ String cursorValue = cursor.getString(valueColumnIndex);
cursor.moveToNext();
if (key.equals(cursorKey)) {
value = cursorValue;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 6828301..5aac06d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -16,1211 +16,461 @@
package com.android.providers.settings;
-import java.io.FileNotFoundException;
-import java.security.SecureRandom;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
+import android.Manifest;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.backup.BackupManager;
import android.content.BroadcastReceiver;
import android.content.ContentProvider;
-import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
-import android.database.AbstractCursor;
import android.database.Cursor;
+import android.database.MatrixCursor;
import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteQueryBuilder;
+import android.hardware.camera2.utils.ArrayUtils;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.DropBoxManager;
-import android.os.FileObserver;
+import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.provider.Settings.Secure;
import android.text.TextUtils;
-import android.util.Log;
-import android.util.LruCache;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+import com.android.providers.settings.SettingsState.Setting;
+
+/**
+ * <p>
+ * This class is a content provider that publishes the system settings.
+ * It can be accessed via the content provider APIs or via custom call
+ * commands. The latter is a bit faster and is the preferred way to access
+ * the platform settings.
+ * </p>
+ * <p>
+ * There are three settings types, global (with signature level protection
+ * and shared across users), secure (with signature permission level
+ * protection and per user), and system (with dangerous permission level
+ * protection and per user). Global settings are stored under the device owner.
+ * Each of these settings is represented by a {@link
+ * com.android.providers.settings.SettingsState} object mapped to an integer
+ * key derived from the setting type in the most significant bits and user
+ * id in the least significant bits. Settings are synchronously loaded on
+ * instantiation of a SettingsState and asynchronously persisted on mutation.
+ * Settings are stored in the user specific system directory.
+ * </p>
+ * <p>
+ * Apps targeting APIs Lollipop MR1 and lower can add custom settings entries
+ * and get a warning. Targeting higher API version prohibits this as the
+ * system settings are not a place for apps to save their state. When a package
+ * is removed the settings it added are deleted. Apps cannot delete system
+ * settings added by the platform. System settings values are validated to
+ * ensure the clients do not put bad values. Global and secure settings are
+ * changed only by trusted parties, therefore no validation is performed. Also
+ * there is a limit on the amount of app specific settings that can be added
+ * to prevent unlimited growth of the system process memory footprint.
+ * </p>
+ */
+@SuppressWarnings("deprecation")
public class SettingsProvider extends ContentProvider {
- private static final String TAG = "SettingsProvider";
- private static final boolean LOCAL_LOGV = false;
+ private static final boolean DEBUG = false;
- private static final boolean USER_CHECK_THROWS = true;
+ private static final boolean DROP_DATABASE_ON_MIGRATION = !Build.IS_DEBUGGABLE;
+
+ private static final String LOG_TAG = "SettingsProvider";
private static final String TABLE_SYSTEM = "system";
private static final String TABLE_SECURE = "secure";
private static final String TABLE_GLOBAL = "global";
+
+ // Old tables no longer exist.
private static final String TABLE_FAVORITES = "favorites";
private static final String TABLE_OLD_FAVORITES = "old_favorites";
+ private static final String TABLE_BLUETOOTH_DEVICES = "bluetooth_devices";
+ private static final String TABLE_BOOKMARKS = "bookmarks";
+ private static final String TABLE_ANDROID_METADATA = "android_metadata";
- private static final String[] COLUMN_VALUE = new String[] { "value" };
-
- // Caches for each user's settings, access-ordered for acting as LRU.
- // Guarded by themselves.
- private static final int MAX_CACHE_ENTRIES = 200;
- private static final SparseArray<SettingsCache> sSystemCaches
- = new SparseArray<SettingsCache>();
- private static final SparseArray<SettingsCache> sSecureCaches
- = new SparseArray<SettingsCache>();
- private static final SettingsCache sGlobalCache = new SettingsCache(TABLE_GLOBAL);
-
- // The count of how many known (handled by SettingsProvider)
- // database mutations are currently being handled for this user.
- // Used by file observers to not reload the database when it's ourselves
- // modifying it.
- private static final SparseArray<AtomicInteger> sKnownMutationsInFlight
- = new SparseArray<AtomicInteger>();
-
- // Each defined user has their own settings
- protected final SparseArray<DatabaseHelper> mOpenHelpers = new SparseArray<DatabaseHelper>();
-
- // Keep the list of managed profiles synced here
- private List<UserInfo> mManagedProfiles = null;
-
- // Over this size we don't reject loading or saving settings but
- // we do consider them broken/malicious and don't keep them in
- // memory at least:
- private static final int MAX_CACHE_ENTRY_SIZE = 500;
-
- private static final Bundle NULL_SETTING = Bundle.forPair("value", null);
-
- // Used as a sentinel value in an instance equality test when we
- // want to cache the existence of a key, but not store its value.
- private static final Bundle TOO_LARGE_TO_CACHE_MARKER = Bundle.forPair("_dummy", null);
-
- private UserManager mUserManager;
- private BackupManager mBackupManager;
-
- /**
- * Settings which need to be treated as global/shared in multi-user environments.
- */
- static final HashSet<String> sSecureGlobalKeys;
- static final HashSet<String> sSystemGlobalKeys;
-
- // Settings that cannot be modified if associated user restrictions are enabled.
- static final Map<String, String> sRestrictedKeys;
-
- private static final String DROPBOX_TAG_USERLOG = "restricted_profile_ssaid";
-
- static final HashSet<String> sSecureCloneToManagedKeys;
- static final HashSet<String> sSystemCloneToManagedKeys;
-
+ // The set of removed legacy tables.
+ private static final Set<String> REMOVED_LEGACY_TABLES = new ArraySet<>();
static {
- // Keys (name column) from the 'secure' table that are now in the owner user's 'global'
- // table, shared across all users
- // These must match Settings.Secure.MOVED_TO_GLOBAL
- sSecureGlobalKeys = new HashSet<String>();
- Settings.Secure.getMovedKeys(sSecureGlobalKeys);
+ REMOVED_LEGACY_TABLES.add(TABLE_FAVORITES);
+ REMOVED_LEGACY_TABLES.add(TABLE_OLD_FAVORITES);
+ REMOVED_LEGACY_TABLES.add(TABLE_BLUETOOTH_DEVICES);
+ REMOVED_LEGACY_TABLES.add(TABLE_BOOKMARKS);
+ REMOVED_LEGACY_TABLES.add(TABLE_ANDROID_METADATA);
+ }
- // Keys from the 'system' table now moved to 'global'
- // These must match Settings.System.MOVED_TO_GLOBAL
- sSystemGlobalKeys = new HashSet<String>();
- Settings.System.getNonLegacyMovedKeys(sSystemGlobalKeys);
+ private static final int MUTATION_OPERATION_INSERT = 1;
+ private static final int MUTATION_OPERATION_DELETE = 2;
+ private static final int MUTATION_OPERATION_UPDATE = 3;
- sRestrictedKeys = new HashMap<String, String>();
- sRestrictedKeys.put(Settings.Secure.LOCATION_MODE, UserManager.DISALLOW_SHARE_LOCATION);
- sRestrictedKeys.put(Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ private static final String[] ALL_COLUMNS = new String[] {
+ Settings.NameValueTable._ID,
+ Settings.NameValueTable.NAME,
+ Settings.NameValueTable.VALUE
+ };
+
+ private static final Bundle NULL_SETTING = Bundle.forPair(Settings.NameValueTable.VALUE, null);
+
+ // Per user settings that cannot be modified if associated user restrictions are enabled.
+ private static final Map<String, String> sSettingToUserRestrictionMap = new ArrayMap<>();
+ static {
+ sSettingToUserRestrictionMap.put(Settings.Secure.LOCATION_MODE,
UserManager.DISALLOW_SHARE_LOCATION);
- sRestrictedKeys.put(Settings.Secure.INSTALL_NON_MARKET_APPS,
+ sSettingToUserRestrictionMap.put(Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ UserManager.DISALLOW_SHARE_LOCATION);
+ sSettingToUserRestrictionMap.put(Settings.Secure.INSTALL_NON_MARKET_APPS,
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
- sRestrictedKeys.put(Settings.Global.ADB_ENABLED, UserManager.DISALLOW_DEBUGGING_FEATURES);
- sRestrictedKeys.put(Settings.Global.PACKAGE_VERIFIER_ENABLE,
+ sSettingToUserRestrictionMap.put(Settings.Global.ADB_ENABLED,
+ UserManager.DISALLOW_DEBUGGING_FEATURES);
+ sSettingToUserRestrictionMap.put(Settings.Global.PACKAGE_VERIFIER_ENABLE,
UserManager.ENSURE_VERIFY_APPS);
- sRestrictedKeys.put(Settings.Global.PREFERRED_NETWORK_MODE,
+ sSettingToUserRestrictionMap.put(Settings.Global.PREFERRED_NETWORK_MODE,
UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
-
- sSecureCloneToManagedKeys = new HashSet<String>();
- for (int i = 0; i < Settings.Secure.CLONE_TO_MANAGED_PROFILE.length; i++) {
- sSecureCloneToManagedKeys.add(Settings.Secure.CLONE_TO_MANAGED_PROFILE[i]);
- }
- sSystemCloneToManagedKeys = new HashSet<String>();
- for (int i = 0; i < Settings.System.CLONE_TO_MANAGED_PROFILE.length; i++) {
- sSystemCloneToManagedKeys.add(Settings.System.CLONE_TO_MANAGED_PROFILE[i]);
- }
}
- private boolean settingMovedToGlobal(final String name) {
- return sSecureGlobalKeys.contains(name) || sSystemGlobalKeys.contains(name);
+ // Per user secure settings that moved to the for all users global settings.
+ static final Set<String> sSecureMovedToGlobalSettings = new ArraySet<>();
+ static {
+ Settings.Secure.getMovedToGlobalSettings(sSecureMovedToGlobalSettings);
}
- /**
- * Decode a content URL into the table, projection, and arguments
- * used to access the corresponding database rows.
- */
- private static class SqlArguments {
- public String table;
- public final String where;
- public final String[] args;
-
- /** Operate on existing rows. */
- SqlArguments(Uri url, String where, String[] args) {
- if (url.getPathSegments().size() == 1) {
- // of the form content://settings/secure, arbitrary where clause
- this.table = url.getPathSegments().get(0);
- if (!DatabaseHelper.isValidTable(this.table)) {
- throw new IllegalArgumentException("Bad root path: " + this.table);
- }
- this.where = where;
- this.args = args;
- } else if (url.getPathSegments().size() != 2) {
- throw new IllegalArgumentException("Invalid URI: " + url);
- } else if (!TextUtils.isEmpty(where)) {
- throw new UnsupportedOperationException("WHERE clause not supported: " + url);
- } else {
- // of the form content://settings/secure/element_name, no where clause
- this.table = url.getPathSegments().get(0);
- if (!DatabaseHelper.isValidTable(this.table)) {
- throw new IllegalArgumentException("Bad root path: " + this.table);
- }
- if (TABLE_SYSTEM.equals(this.table) || TABLE_SECURE.equals(this.table) ||
- TABLE_GLOBAL.equals(this.table)) {
- this.where = Settings.NameValueTable.NAME + "=?";
- final String name = url.getPathSegments().get(1);
- this.args = new String[] { name };
- // Rewrite the table for known-migrated names
- if (TABLE_SYSTEM.equals(this.table) || TABLE_SECURE.equals(this.table)) {
- if (sSecureGlobalKeys.contains(name) || sSystemGlobalKeys.contains(name)) {
- this.table = TABLE_GLOBAL;
- }
- }
- } else {
- // of the form content://bookmarks/19
- this.where = "_id=" + ContentUris.parseId(url);
- this.args = null;
- }
- }
- }
-
- /** Insert new rows (no where clause allowed). */
- SqlArguments(Uri url) {
- if (url.getPathSegments().size() == 1) {
- this.table = url.getPathSegments().get(0);
- if (!DatabaseHelper.isValidTable(this.table)) {
- throw new IllegalArgumentException("Bad root path: " + this.table);
- }
- this.where = null;
- this.args = null;
- } else {
- throw new IllegalArgumentException("Invalid URI: " + url);
- }
- }
+ // Per user system settings that moved to the for all users global settings.
+ static final Set<String> sSystemMovedToGlobalSettings = new ArraySet<>();
+ static {
+ Settings.System.getMovedToGlobalSettings(sSystemMovedToGlobalSettings);
}
- /**
- * Get the content URI of a row added to a table.
- * @param tableUri of the entire table
- * @param values found in the row
- * @param rowId of the row
- * @return the content URI for this particular row
- */
- private Uri getUriFor(Uri tableUri, ContentValues values, long rowId) {
- if (tableUri.getPathSegments().size() != 1) {
- throw new IllegalArgumentException("Invalid URI: " + tableUri);
- }
- String table = tableUri.getPathSegments().get(0);
- if (TABLE_SYSTEM.equals(table) ||
- TABLE_SECURE.equals(table) ||
- TABLE_GLOBAL.equals(table)) {
- String name = values.getAsString(Settings.NameValueTable.NAME);
- return Uri.withAppendedPath(tableUri, name);
- } else {
- return ContentUris.withAppendedId(tableUri, rowId);
- }
+ // Per user system settings that moved to the per user secure settings.
+ static final Set<String> sSystemMovedToSecureSettings = new ArraySet<>();
+ static {
+ Settings.System.getMovedToSecureSettings(sSystemMovedToSecureSettings);
}
- /**
- * Send a notification when a particular content URI changes.
- * Modify the system property used to communicate the version of
- * this table, for tables which have such a property. (The Settings
- * contract class uses these to provide client-side caches.)
- * @param uri to send notifications for
- */
- private void sendNotify(Uri uri, int userHandle) {
- // Update the system property *first*, so if someone is listening for
- // a notification and then using the contract class to get their data,
- // the system property will be updated and they'll get the new data.
-
- boolean backedUpDataChanged = false;
- String property = null, table = uri.getPathSegments().get(0);
- final boolean isGlobal = table.equals(TABLE_GLOBAL);
- if (table.equals(TABLE_SYSTEM)) {
- property = Settings.System.SYS_PROP_SETTING_VERSION;
- backedUpDataChanged = true;
- } else if (table.equals(TABLE_SECURE)) {
- property = Settings.Secure.SYS_PROP_SETTING_VERSION;
- backedUpDataChanged = true;
- } else if (isGlobal) {
- property = Settings.Global.SYS_PROP_SETTING_VERSION; // this one is global
- backedUpDataChanged = true;
- }
-
- if (property != null) {
- long version = SystemProperties.getLong(property, 0) + 1;
- if (LOCAL_LOGV) Log.v(TAG, "property: " + property + "=" + version);
- SystemProperties.set(property, Long.toString(version));
- }
-
- // Inform the backup manager about a data change
- if (backedUpDataChanged) {
- mBackupManager.dataChanged();
- }
- // Now send the notification through the content framework.
-
- String notify = uri.getQueryParameter("notify");
- if (notify == null || "true".equals(notify)) {
- final int notifyTarget = isGlobal ? UserHandle.USER_ALL : userHandle;
- final long oldId = Binder.clearCallingIdentity();
- try {
- getContext().getContentResolver().notifyChange(uri, null, true, notifyTarget);
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- if (LOCAL_LOGV) Log.v(TAG, "notifying for " + notifyTarget + ": " + uri);
- } else {
- if (LOCAL_LOGV) Log.v(TAG, "notification suppressed: " + uri);
- }
+ // Per all users global settings that moved to the per user secure settings.
+ static final Set<String> sGlobalMovedToSecureSettings = new ArraySet<>();
+ static {
+ Settings.Global.getMovedToSecureSettings(sGlobalMovedToSecureSettings);
}
- /**
- * Make sure the caller has permission to write this data.
- * @param args supplied by the caller
- * @throws SecurityException if the caller is forbidden to write.
- */
- private void checkWritePermissions(SqlArguments args) {
- if ((TABLE_SECURE.equals(args.table) || TABLE_GLOBAL.equals(args.table)) &&
- getContext().checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- String.format("Permission denial: writing to secure settings requires %1$s",
- android.Manifest.permission.WRITE_SECURE_SETTINGS));
- }
+ // Per user secure settings that are cloned for the managed profiles of the user.
+ private static final Set<String> sSecureCloneToManagedSettings = new ArraySet<>();
+ static {
+ Settings.Secure.getCloneToManagedProfileSettings(sSecureCloneToManagedSettings);
}
- private void checkUserRestrictions(String setting, int userId) {
- String userRestriction = sRestrictedKeys.get(setting);
- if (!TextUtils.isEmpty(userRestriction)
- && mUserManager.hasUserRestriction(userRestriction, new UserHandle(userId))) {
- throw new SecurityException(
- "Permission denial: user is restricted from changing this setting.");
- }
+ // Per user system settings that are cloned for the managed profiles of the user.
+ private static final Set<String> sSystemCloneToManagedSettings = new ArraySet<>();
+ static {
+ Settings.System.getCloneToManagedProfileSettings(sSystemCloneToManagedSettings);
}
- // FileObserver for external modifications to the database file.
- // Note that this is for platform developers only with
- // userdebug/eng builds who should be able to tinker with the
- // sqlite database out from under the SettingsProvider, which is
- // normally the exclusive owner of the database. But we keep this
- // enabled all the time to minimize development-vs-user
- // differences in testing.
- private static SparseArray<SettingsFileObserver> sObserverInstances
- = new SparseArray<SettingsFileObserver>();
- private class SettingsFileObserver extends FileObserver {
- private final AtomicBoolean mIsDirty = new AtomicBoolean(false);
- private final int mUserHandle;
- private final String mPath;
+ private final Object mLock = new Object();
- public SettingsFileObserver(int userHandle, String path) {
- super(path, FileObserver.CLOSE_WRITE |
- FileObserver.CREATE | FileObserver.DELETE |
- FileObserver.MOVED_TO | FileObserver.MODIFY);
- mUserHandle = userHandle;
- mPath = path;
- }
+ @GuardedBy("mLock")
+ private SettingsRegistry mSettingsRegistry;
- public void onEvent(int event, String path) {
- final AtomicInteger mutationCount;
- synchronized (SettingsProvider.this) {
- mutationCount = sKnownMutationsInFlight.get(mUserHandle);
- }
- if (mutationCount != null && mutationCount.get() > 0) {
- // our own modification.
- return;
- }
- Log.d(TAG, "User " + mUserHandle + " external modification to " + mPath
- + "; event=" + event);
- if (!mIsDirty.compareAndSet(false, true)) {
- // already handled. (we get a few update events
- // during an sqlite write)
- return;
- }
- Log.d(TAG, "User " + mUserHandle + " updating our caches for " + mPath);
- fullyPopulateCaches(mUserHandle);
- mIsDirty.set(false);
- }
- }
+ @GuardedBy("mLock")
+ private UserManager mUserManager;
+
+ @GuardedBy("mLock")
+ private AppOpsManager mAppOpsManager;
+
+ @GuardedBy("mLock")
+ private PackageManager mPackageManager;
@Override
public boolean onCreate() {
- mBackupManager = new BackupManager(getContext());
- mUserManager = UserManager.get(getContext());
-
- setAppOps(AppOpsManager.OP_NONE, AppOpsManager.OP_WRITE_SETTINGS);
- establishDbTracking(UserHandle.USER_OWNER);
-
- IntentFilter userFilter = new IntentFilter();
- userFilter.addAction(Intent.ACTION_USER_REMOVED);
- userFilter.addAction(Intent.ACTION_USER_ADDED);
- getContext().registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- UserHandle.USER_OWNER);
- if (intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
- onUserRemoved(userHandle);
- } else if (intent.getAction().equals(Intent.ACTION_USER_ADDED)) {
- onProfilesChanged();
- }
- }
- }, userFilter);
-
- onProfilesChanged();
-
+ synchronized (mLock) {
+ mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+ mAppOpsManager = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+ mPackageManager = getContext().getPackageManager();
+ mSettingsRegistry = new SettingsRegistry();
+ }
+ registerBroadcastReceivers();
return true;
}
- void onUserRemoved(int userHandle) {
- synchronized (this) {
- // the db file itself will be deleted automatically, but we need to tear down
- // our caches and other internal bookkeeping.
- FileObserver observer = sObserverInstances.get(userHandle);
- if (observer != null) {
- observer.stopWatching();
- sObserverInstances.delete(userHandle);
- }
-
- mOpenHelpers.delete(userHandle);
- sSystemCaches.delete(userHandle);
- sSecureCaches.delete(userHandle);
- sKnownMutationsInFlight.delete(userHandle);
- onProfilesChanged();
- }
- }
-
- /**
- * Updates the list of managed profiles. It assumes that only the primary user
- * can have managed profiles. Modify this code if that changes in the future.
- */
- void onProfilesChanged() {
- synchronized (this) {
- mManagedProfiles = mUserManager.getProfiles(UserHandle.USER_OWNER);
- if (mManagedProfiles != null) {
- // Remove the primary user from the list
- for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
- if (mManagedProfiles.get(i).id == UserHandle.USER_OWNER) {
- mManagedProfiles.remove(i);
- }
- }
- // If there are no managed profiles, reset the variable
- if (mManagedProfiles.size() == 0) {
- mManagedProfiles = null;
- }
- }
- if (LOCAL_LOGV) {
- Slog.d(TAG, "Managed Profiles = " + mManagedProfiles);
- }
- }
- }
-
- private void establishDbTracking(int userHandle) {
- if (LOCAL_LOGV) {
- Slog.i(TAG, "Installing settings db helper and caches for user " + userHandle);
- }
-
- DatabaseHelper dbhelper;
-
- synchronized (this) {
- dbhelper = mOpenHelpers.get(userHandle);
- if (dbhelper == null) {
- dbhelper = new DatabaseHelper(getContext(), userHandle);
- mOpenHelpers.append(userHandle, dbhelper);
-
- sSystemCaches.append(userHandle, new SettingsCache(TABLE_SYSTEM));
- sSecureCaches.append(userHandle, new SettingsCache(TABLE_SECURE));
- sKnownMutationsInFlight.append(userHandle, new AtomicInteger(0));
- }
- }
-
- // Initialization of the db *outside* the locks. It's possible that racing
- // threads might wind up here, the second having read the cache entries
- // written by the first, but that's benign: the SQLite helper implementation
- // manages concurrency itself, and it's important that we not run the db
- // initialization with any of our own locks held, so we're fine.
- SQLiteDatabase db = dbhelper.getWritableDatabase();
-
- // Watch for external modifications to the database files,
- // keeping our caches in sync. We synchronize the observer set
- // separately, and of course it has to run after the db file
- // itself was set up by the DatabaseHelper.
- synchronized (sObserverInstances) {
- if (sObserverInstances.get(userHandle) == null) {
- SettingsFileObserver observer = new SettingsFileObserver(userHandle, db.getPath());
- sObserverInstances.append(userHandle, observer);
- observer.startWatching();
- }
- }
-
- ensureAndroidIdIsSet(userHandle);
-
- startAsyncCachePopulation(userHandle);
- }
-
- class CachePrefetchThread extends Thread {
- private int mUserHandle;
-
- CachePrefetchThread(int userHandle) {
- super("populate-settings-caches");
- mUserHandle = userHandle;
- }
-
- @Override
- public void run() {
- fullyPopulateCaches(mUserHandle);
- }
- }
-
- private void startAsyncCachePopulation(int userHandle) {
- new CachePrefetchThread(userHandle).start();
- }
-
- private void fullyPopulateCaches(final int userHandle) {
- DatabaseHelper dbHelper;
- synchronized (this) {
- dbHelper = mOpenHelpers.get(userHandle);
- }
- if (dbHelper == null) {
- // User is gone.
- return;
- }
- // Only populate the globals cache once, for the owning user
- if (userHandle == UserHandle.USER_OWNER) {
- fullyPopulateCache(dbHelper, TABLE_GLOBAL, sGlobalCache);
- }
- fullyPopulateCache(dbHelper, TABLE_SECURE, sSecureCaches.get(userHandle));
- fullyPopulateCache(dbHelper, TABLE_SYSTEM, sSystemCaches.get(userHandle));
- }
-
- // Slurp all values (if sane in number & size) into cache.
- private void fullyPopulateCache(DatabaseHelper dbHelper, String table, SettingsCache cache) {
- SQLiteDatabase db = dbHelper.getReadableDatabase();
- Cursor c = db.query(
- table,
- new String[] { Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE },
- null, null, null, null, null,
- "" + (MAX_CACHE_ENTRIES + 1) /* limit */);
- try {
- synchronized (cache) {
- cache.evictAll();
- cache.setFullyMatchesDisk(true); // optimistic
- int rows = 0;
- while (c.moveToNext()) {
- rows++;
- String name = c.getString(0);
- String value = c.getString(1);
- cache.populate(name, value);
- }
- if (rows > MAX_CACHE_ENTRIES) {
- // Somewhat redundant, as removeEldestEntry() will
- // have already done this, but to be explicit:
- cache.setFullyMatchesDisk(false);
- Log.d(TAG, "row count exceeds max cache entries for table " + table);
- }
- if (LOCAL_LOGV) Log.d(TAG, "cache for settings table '" + table
- + "' rows=" + rows + "; fullycached=" + cache.fullyMatchesDisk());
- }
- } finally {
- c.close();
- }
- }
-
- private boolean ensureAndroidIdIsSet(int userHandle) {
- final Cursor c = queryForUser(Settings.Secure.CONTENT_URI,
- new String[] { Settings.NameValueTable.VALUE },
- Settings.NameValueTable.NAME + "=?",
- new String[] { Settings.Secure.ANDROID_ID }, null,
- userHandle);
- try {
- final String value = c.moveToNext() ? c.getString(0) : null;
- if (value == null) {
- // sanity-check the user before touching the db
- final UserInfo user = mUserManager.getUserInfo(userHandle);
- if (user == null) {
- // can happen due to races when deleting users; treat as benign
- return false;
+ @Override
+ public Bundle call(String method, String name, Bundle args) {
+ synchronized (mLock) {
+ final int requestingUserId = getRequestingUserId(args);
+ switch (method) {
+ case Settings.CALL_METHOD_GET_GLOBAL: {
+ Setting setting = getGlobalSettingLocked(name);
+ return packageValueForCallResult(setting);
}
- final SecureRandom random = new SecureRandom();
- final String newAndroidIdValue = Long.toHexString(random.nextLong());
- final ContentValues values = new ContentValues();
- values.put(Settings.NameValueTable.NAME, Settings.Secure.ANDROID_ID);
- values.put(Settings.NameValueTable.VALUE, newAndroidIdValue);
- final Uri uri = insertForUser(Settings.Secure.CONTENT_URI, values, userHandle);
- if (uri == null) {
- Slog.e(TAG, "Unable to generate new ANDROID_ID for user " + userHandle);
- return false;
+ case Settings.CALL_METHOD_GET_SECURE: {
+ Setting setting = getSecureSettingLocked(name, requestingUserId);
+ return packageValueForCallResult(setting);
}
- Slog.d(TAG, "Generated and saved new ANDROID_ID [" + newAndroidIdValue
- + "] for user " + userHandle);
- // Write a dropbox entry if it's a restricted profile
- if (user.isRestricted()) {
- DropBoxManager dbm = (DropBoxManager)
- getContext().getSystemService(Context.DROPBOX_SERVICE);
- if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) {
- dbm.addText(DROPBOX_TAG_USERLOG, System.currentTimeMillis()
- + ",restricted_profile_ssaid,"
- + newAndroidIdValue + "\n");
- }
+
+ case Settings.CALL_METHOD_GET_SYSTEM: {
+ Setting setting = getSystemSettingLocked(name, requestingUserId);
+ return packageValueForCallResult(setting);
}
- }
- return true;
- } finally {
- c.close();
- }
- }
- // Lazy-initialize the settings caches for non-primary users
- private SettingsCache getOrConstructCache(int callingUser, SparseArray<SettingsCache> which) {
- getOrEstablishDatabase(callingUser); // ignore return value; we don't need it
- return which.get(callingUser);
- }
+ case Settings.CALL_METHOD_PUT_GLOBAL: {
+ String value = getSettingValue(args);
+ insertGlobalSettingLocked(name, value, requestingUserId);
+ } break;
- // Lazy initialize the database helper and caches for this user, if necessary
- private DatabaseHelper getOrEstablishDatabase(int callingUser) {
- if (callingUser >= Process.SYSTEM_UID) {
- if (USER_CHECK_THROWS) {
- throw new IllegalArgumentException("Uid rather than user handle: " + callingUser);
- } else {
- Slog.wtf(TAG, "establish db for uid rather than user: " + callingUser);
- }
- }
+ case Settings.CALL_METHOD_PUT_SECURE: {
+ String value = getSettingValue(args);
+ insertSecureSettingLocked(name, value, requestingUserId);
+ } break;
- long oldId = Binder.clearCallingIdentity();
- try {
- DatabaseHelper dbHelper;
- synchronized (this) {
- dbHelper = mOpenHelpers.get(callingUser);
- }
- if (null == dbHelper) {
- establishDbTracking(callingUser);
- synchronized (this) {
- dbHelper = mOpenHelpers.get(callingUser);
- }
- }
- return dbHelper;
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- }
+ case Settings.CALL_METHOD_PUT_SYSTEM: {
+ String value = getSettingValue(args);
+ insertSystemSettingLocked(name, value, requestingUserId);
+ } break;
- public SettingsCache cacheForTable(final int callingUser, String tableName) {
- if (TABLE_SYSTEM.equals(tableName)) {
- return getOrConstructCache(callingUser, sSystemCaches);
- }
- if (TABLE_SECURE.equals(tableName)) {
- return getOrConstructCache(callingUser, sSecureCaches);
- }
- if (TABLE_GLOBAL.equals(tableName)) {
- return sGlobalCache;
+ default: {
+ Slog.w(LOG_TAG, "call() with invalid method: " + method);
+ } break;
+ }
}
return null;
}
- /**
- * Used for wiping a whole cache on deletes when we're not
- * sure what exactly was deleted or changed.
- */
- public void invalidateCache(final int callingUser, String tableName) {
- SettingsCache cache = cacheForTable(callingUser, tableName);
- if (cache == null) {
- return;
- }
- synchronized (cache) {
- cache.evictAll();
- cache.mCacheFullyMatchesDisk = false;
- }
- }
-
- /**
- * Checks if the calling user is a managed profile of the primary user.
- * Currently only the primary user (USER_OWNER) can have managed profiles.
- * @param callingUser the user trying to read/write settings
- * @return true if it is a managed profile of the primary user
- */
- private boolean isManagedProfile(int callingUser) {
- synchronized (this) {
- if (mManagedProfiles == null) return false;
- for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
- if (mManagedProfiles.get(i).id == callingUser) {
- return true;
- }
- }
- return false;
- }
- }
-
- /**
- * Fast path that avoids the use of chatty remoted Cursors.
- */
@Override
- public Bundle call(String method, String request, Bundle args) {
- int callingUser = UserHandle.getCallingUserId();
- if (args != null) {
- int reqUser = args.getInt(Settings.CALL_METHOD_USER_KEY, callingUser);
- if (reqUser != callingUser) {
- callingUser = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), reqUser, false, true,
- "get/set setting for user", null);
- if (LOCAL_LOGV) Slog.v(TAG, " access setting for user " + callingUser);
- }
- }
-
- // Note: we assume that get/put operations for moved-to-global names have already
- // been directed to the new location on the caller side (otherwise we'd fix them
- // up here).
- DatabaseHelper dbHelper;
- SettingsCache cache;
-
- // Get methods
- if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call(system:" + request + ") for " + callingUser);
- // Check if this request should be (re)directed to the primary user's db
- if (callingUser != UserHandle.USER_OWNER
- && shouldShadowParentProfile(callingUser, sSystemCloneToManagedKeys, request)) {
- callingUser = UserHandle.USER_OWNER;
- }
- dbHelper = getOrEstablishDatabase(callingUser);
- cache = sSystemCaches.get(callingUser);
- return lookupValue(dbHelper, TABLE_SYSTEM, cache, request);
- }
- if (Settings.CALL_METHOD_GET_SECURE.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call(secure:" + request + ") for " + callingUser);
- // Check if this is a setting to be copied from the primary user
- if (shouldShadowParentProfile(callingUser, sSecureCloneToManagedKeys, request)) {
- // If the request if for location providers and there's a restriction, return none
- if (Secure.LOCATION_PROVIDERS_ALLOWED.equals(request)
- && mUserManager.hasUserRestriction(
- UserManager.DISALLOW_SHARE_LOCATION, new UserHandle(callingUser))) {
- return sSecureCaches.get(callingUser).putIfAbsent(request, "");
- }
- callingUser = UserHandle.USER_OWNER;
- }
- dbHelper = getOrEstablishDatabase(callingUser);
- cache = sSecureCaches.get(callingUser);
- return lookupValue(dbHelper, TABLE_SECURE, cache, request);
- }
- if (Settings.CALL_METHOD_GET_GLOBAL.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call(global:" + request + ") for " + callingUser);
- // fast path: owner db & cache are immutable after onCreate() so we need not
- // guard on the attempt to look them up
- return lookupValue(getOrEstablishDatabase(UserHandle.USER_OWNER), TABLE_GLOBAL,
- sGlobalCache, request);
- }
-
- // Put methods - new value is in the args bundle under the key named by
- // the Settings.NameValueTable.VALUE static.
- final String newValue = (args == null)
- ? null : args.getString(Settings.NameValueTable.VALUE);
-
- // Framework can't do automatic permission checking for calls, so we need
- // to do it here.
- if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- String.format("Permission denial: writing to settings requires %1$s",
- android.Manifest.permission.WRITE_SETTINGS));
- }
-
- // Also need to take care of app op.
- if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SETTINGS, Binder.getCallingUid(),
- getCallingPackage()) != AppOpsManager.MODE_ALLOWED) {
- return null;
- }
-
- final ContentValues values = new ContentValues();
- values.put(Settings.NameValueTable.NAME, request);
- values.put(Settings.NameValueTable.VALUE, newValue);
- if (Settings.CALL_METHOD_PUT_SYSTEM.equals(method)) {
- if (LOCAL_LOGV) {
- Slog.v(TAG, "call_put(system:" + request + "=" + newValue + ") for "
- + callingUser);
- }
- // Extra check for USER_OWNER to optimize for the 99%
- if (callingUser != UserHandle.USER_OWNER && shouldShadowParentProfile(callingUser,
- sSystemCloneToManagedKeys, request)) {
- // Don't write these settings, as they are cloned from the parent profile
- return null;
- }
- insertForUser(Settings.System.CONTENT_URI, values, callingUser);
- // Clone the settings to the managed profiles so that notifications can be sent out
- if (callingUser == UserHandle.USER_OWNER && mManagedProfiles != null
- && sSystemCloneToManagedKeys.contains(request)) {
- final long token = Binder.clearCallingIdentity();
- try {
- for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
- if (LOCAL_LOGV) {
- Slog.v(TAG, "putting to additional user "
- + mManagedProfiles.get(i).id);
- }
- insertForUser(Settings.System.CONTENT_URI, values,
- mManagedProfiles.get(i).id);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- } else if (Settings.CALL_METHOD_PUT_SECURE.equals(method)) {
- if (LOCAL_LOGV) {
- Slog.v(TAG, "call_put(secure:" + request + "=" + newValue + ") for "
- + callingUser);
- }
- // Extra check for USER_OWNER to optimize for the 99%
- if (callingUser != UserHandle.USER_OWNER && shouldShadowParentProfile(callingUser,
- sSecureCloneToManagedKeys, request)) {
- // Don't write these settings, as they are cloned from the parent profile
- return null;
- }
- insertForUser(Settings.Secure.CONTENT_URI, values, callingUser);
- // Clone the settings to the managed profiles so that notifications can be sent out
- if (callingUser == UserHandle.USER_OWNER && mManagedProfiles != null
- && sSecureCloneToManagedKeys.contains(request)) {
- final long token = Binder.clearCallingIdentity();
- try {
- for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
- if (LOCAL_LOGV) {
- Slog.v(TAG, "putting to additional user "
- + mManagedProfiles.get(i).id);
- }
- try {
- insertForUser(Settings.Secure.CONTENT_URI, values,
- mManagedProfiles.get(i).id);
- } catch (SecurityException e) {
- // Temporary fix, see b/17450158
- Slog.w(TAG, "Cannot clone request '" + request + "' with value '"
- + newValue + "' to managed profile (id "
- + mManagedProfiles.get(i).id + ")", e);
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- } else if (Settings.CALL_METHOD_PUT_GLOBAL.equals(method)) {
- if (LOCAL_LOGV) {
- Slog.v(TAG, "call_put(global:" + request + "=" + newValue + ") for "
- + callingUser);
- }
- insertForUser(Settings.Global.CONTENT_URI, values, callingUser);
- } else {
- Slog.w(TAG, "call() with invalid method: " + method);
- }
-
- return null;
- }
-
- /**
- * Check if the user is a managed profile and name is one of the settings to be cloned
- * from the parent profile.
- */
- private boolean shouldShadowParentProfile(int userId, HashSet<String> keys, String name) {
- return isManagedProfile(userId) && keys.contains(name);
- }
-
- // Looks up value 'key' in 'table' and returns either a single-pair Bundle,
- // possibly with a null value, or null on failure.
- private Bundle lookupValue(DatabaseHelper dbHelper, String table,
- final SettingsCache cache, String key) {
- if (cache == null) {
- Slog.e(TAG, "cache is null for user " + UserHandle.getCallingUserId() + " : key=" + key);
- return null;
- }
- synchronized (cache) {
- Bundle value = cache.get(key);
- if (value != null) {
- if (value != TOO_LARGE_TO_CACHE_MARKER) {
- return value;
- }
- // else we fall through and read the value from disk
- } else if (cache.fullyMatchesDisk()) {
- // Fast path (very common). Don't even try touch disk
- // if we know we've slurped it all in. Trying to
- // touch the disk would mean waiting for yaffs2 to
- // give us access, which could takes hundreds of
- // milliseconds. And we're very likely being called
- // from somebody's UI thread...
- return NULL_SETTING;
- }
- }
-
- SQLiteDatabase db = dbHelper.getReadableDatabase();
- Cursor cursor = null;
- try {
- cursor = db.query(table, COLUMN_VALUE, "name=?", new String[]{key},
- null, null, null, null);
- if (cursor != null && cursor.getCount() == 1) {
- cursor.moveToFirst();
- return cache.putIfAbsent(key, cursor.getString(0));
- }
- } catch (SQLiteException e) {
- Log.w(TAG, "settings lookup error", e);
- return null;
- } finally {
- if (cursor != null) cursor.close();
- }
- cache.putIfAbsent(key, null);
- return NULL_SETTING;
- }
-
- @Override
- public Cursor query(Uri url, String[] select, String where, String[] whereArgs, String sort) {
- return queryForUser(url, select, where, whereArgs, sort, UserHandle.getCallingUserId());
- }
-
- private Cursor queryForUser(Uri url, String[] select, String where, String[] whereArgs,
- String sort, int forUser) {
- if (LOCAL_LOGV) Slog.v(TAG, "query(" + url + ") for user " + forUser);
- SqlArguments args = new SqlArguments(url, where, whereArgs);
- DatabaseHelper dbH;
- dbH = getOrEstablishDatabase(
- TABLE_GLOBAL.equals(args.table) ? UserHandle.USER_OWNER : forUser);
- SQLiteDatabase db = dbH.getReadableDatabase();
-
- // The favorites table was moved from this provider to a provider inside Home
- // Home still need to query this table to upgrade from pre-cupcake builds
- // However, a cupcake+ build with no data does not contain this table which will
- // cause an exception in the SQL stack. The following line is a special case to
- // let the caller of the query have a chance to recover and avoid the exception
- if (TABLE_FAVORITES.equals(args.table)) {
- return null;
- } else if (TABLE_OLD_FAVORITES.equals(args.table)) {
- args.table = TABLE_FAVORITES;
- Cursor cursor = db.rawQuery("PRAGMA table_info(favorites);", null);
- if (cursor != null) {
- boolean exists = cursor.getCount() > 0;
- cursor.close();
- if (!exists) return null;
- } else {
- return null;
- }
- }
-
- SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- qb.setTables(args.table);
-
- Cursor ret = qb.query(db, select, args.where, args.args, null, null, sort);
- // the default Cursor interface does not support per-user observation
- try {
- AbstractCursor c = (AbstractCursor) ret;
- c.setNotificationUri(getContext().getContentResolver(), url, forUser);
- } catch (ClassCastException e) {
- // details of the concrete Cursor implementation have changed and this code has
- // not been updated to match -- complain and fail hard.
- Log.wtf(TAG, "Incompatible cursor derivation!");
- throw e;
- }
- return ret;
- }
-
- @Override
- public String getType(Uri url) {
- // If SqlArguments supplies a where clause, then it must be an item
- // (because we aren't supplying our own where clause).
- SqlArguments args = new SqlArguments(url, null, null);
- if (TextUtils.isEmpty(args.where)) {
+ public String getType(Uri uri) {
+ Arguments args = new Arguments(uri, null, null, true);
+ if (TextUtils.isEmpty(args.name)) {
return "vnd.android.cursor.dir/" + args.table;
} else {
- return "vnd.android.cursor.item/" + args.table;
+ return "vnd.android.cursor.item/" + args.table;
}
}
@Override
- public int bulkInsert(Uri uri, ContentValues[] values) {
- final int callingUser = UserHandle.getCallingUserId();
- if (LOCAL_LOGV) Slog.v(TAG, "bulkInsert() for user " + callingUser);
- SqlArguments args = new SqlArguments(uri);
- if (TABLE_FAVORITES.equals(args.table)) {
- return 0;
- }
- checkWritePermissions(args);
- SettingsCache cache = cacheForTable(callingUser, args.table);
-
- final AtomicInteger mutationCount;
- synchronized (this) {
- mutationCount = sKnownMutationsInFlight.get(callingUser);
- }
- if (mutationCount != null) {
- mutationCount.incrementAndGet();
- }
- DatabaseHelper dbH = getOrEstablishDatabase(
- TABLE_GLOBAL.equals(args.table) ? UserHandle.USER_OWNER : callingUser);
- SQLiteDatabase db = dbH.getWritableDatabase();
- db.beginTransaction();
- try {
- int numValues = values.length;
- for (int i = 0; i < numValues; i++) {
- checkUserRestrictions(values[i].getAsString(Settings.Secure.NAME), callingUser);
- if (db.insert(args.table, null, values[i]) < 0) return 0;
- SettingsCache.populate(cache, values[i]);
- if (LOCAL_LOGV) Log.v(TAG, args.table + " <- " + values[i]);
- }
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- if (mutationCount != null) {
- mutationCount.decrementAndGet();
- }
+ public Cursor query(Uri uri, String[] projection, String where, String[] whereArgs,
+ String order) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "query() for user: " + UserHandle.getCallingUserId());
}
- sendNotify(uri, callingUser);
- return values.length;
- }
+ Arguments args = new Arguments(uri, where, whereArgs, true);
+ String[] normalizedProjection = normalizeProjection(projection);
- /*
- * Used to parse changes to the value of Settings.Secure.LOCATION_PROVIDERS_ALLOWED.
- * This setting contains a list of the currently enabled location providers.
- * But helper functions in android.providers.Settings can enable or disable
- * a single provider by using a "+" or "-" prefix before the provider name.
- *
- * @returns whether the database needs to be updated or not, also modifying
- * 'initialValues' if needed.
- */
- private boolean parseProviderList(Uri url, ContentValues initialValues, int desiredUser) {
- String value = initialValues.getAsString(Settings.Secure.VALUE);
- String newProviders = null;
- if (value != null && value.length() > 1) {
- char prefix = value.charAt(0);
- if (prefix == '+' || prefix == '-') {
- // skip prefix
- value = value.substring(1);
+ // If a legacy table that is gone, done.
+ if (REMOVED_LEGACY_TABLES.contains(args.table)) {
+ return new MatrixCursor(normalizedProjection, 0);
+ }
- // read list of enabled providers into "providers"
- String providers = "";
- String[] columns = {Settings.Secure.VALUE};
- String where = Settings.Secure.NAME + "=\'" + Settings.Secure.LOCATION_PROVIDERS_ALLOWED + "\'";
- Cursor cursor = queryForUser(url, columns, where, null, null, desiredUser);
- if (cursor != null && cursor.getCount() == 1) {
- try {
- cursor.moveToFirst();
- providers = cursor.getString(0);
- } finally {
- cursor.close();
- }
- }
-
- int index = providers.indexOf(value);
- int end = index + value.length();
- // check for commas to avoid matching on partial string
- if (index > 0 && providers.charAt(index - 1) != ',') index = -1;
- if (end < providers.length() && providers.charAt(end) != ',') index = -1;
-
- if (prefix == '+' && index < 0) {
- // append the provider to the list if not present
- if (providers.length() == 0) {
- newProviders = value;
+ synchronized (mLock) {
+ switch (args.table) {
+ case TABLE_GLOBAL: {
+ if (args.name != null) {
+ Setting setting = getGlobalSettingLocked(args.name);
+ return packageSettingForQuery(setting, normalizedProjection);
} else {
- newProviders = providers + ',' + value;
+ return getAllGlobalSettingsLocked(projection);
}
- } else if (prefix == '-' && index >= 0) {
- // remove the provider from the list if present
- // remove leading or trailing comma
- if (index > 0) {
- index--;
- } else if (end < providers.length()) {
- end++;
- }
-
- newProviders = providers.substring(0, index);
- if (end < providers.length()) {
- newProviders += providers.substring(end);
- }
- } else {
- // nothing changed, so no need to update the database
- return false;
}
- if (newProviders != null) {
- initialValues.put(Settings.Secure.VALUE, newProviders);
+ case TABLE_SECURE: {
+ final int userId = UserHandle.getCallingUserId();
+ if (args.name != null) {
+ Setting setting = getSecureSettingLocked(args.name, userId);
+ return packageSettingForQuery(setting, normalizedProjection);
+ } else {
+ return getAllSecureSettingsLocked(userId, projection);
+ }
+ }
+
+ case TABLE_SYSTEM: {
+ final int userId = UserHandle.getCallingUserId();
+ if (args.name != null) {
+ Setting setting = getSystemSettingLocked(args.name, userId);
+ return packageSettingForQuery(setting, normalizedProjection);
+ } else {
+ return getAllSystemSettingsLocked(userId, projection);
+ }
+ }
+
+ default: {
+ throw new IllegalArgumentException("Invalid Uri path:" + uri);
}
}
}
-
- return true;
}
@Override
- public Uri insert(Uri url, ContentValues initialValues) {
- return insertForUser(url, initialValues, UserHandle.getCallingUserId());
- }
-
- // Settings.put*ForUser() always winds up here, so this is where we apply
- // policy around permission to write settings for other users.
- private Uri insertForUser(Uri url, ContentValues initialValues, int desiredUserHandle) {
- final int callingUser = UserHandle.getCallingUserId();
- if (callingUser != desiredUserHandle) {
- getContext().enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "Not permitted to access settings for other users");
+ public Uri insert(Uri uri, ContentValues values) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "insert() for user: " + UserHandle.getCallingUserId());
}
- if (LOCAL_LOGV) Slog.v(TAG, "insert(" + url + ") for user " + desiredUserHandle
- + " by " + callingUser);
+ String table = getValidTableOrThrow(uri);
- SqlArguments args = new SqlArguments(url);
- if (TABLE_FAVORITES.equals(args.table)) {
+ // If a legacy table that is gone, done.
+ if (REMOVED_LEGACY_TABLES.contains(table)) {
return null;
}
- // Special case LOCATION_PROVIDERS_ALLOWED.
- // Support enabling/disabling a single provider (using "+" or "-" prefix)
- String name = initialValues.getAsString(Settings.Secure.NAME);
- if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
- if (!parseProviderList(url, initialValues, desiredUserHandle)) return null;
+ String name = values.getAsString(Settings.Secure.NAME);
+ if (TextUtils.isEmpty(name)) {
+ return null;
}
- // If this is an insert() of a key that has been migrated to the global store,
- // redirect the operation to that store
- if (name != null) {
- if (sSecureGlobalKeys.contains(name) || sSystemGlobalKeys.contains(name)) {
- if (!TABLE_GLOBAL.equals(args.table)) {
- if (LOCAL_LOGV) Slog.i(TAG, "Rewrite of insert() of now-global key " + name);
+ String value = values.getAsString(Settings.Secure.VALUE);
+
+ synchronized (mLock) {
+ switch (table) {
+ case TABLE_GLOBAL: {
+ if (insertGlobalSettingLocked(name, value, UserHandle.getCallingUserId())) {
+ return Uri.withAppendedPath(Settings.Global.CONTENT_URI, name);
+ }
+ } break;
+
+ case TABLE_SECURE: {
+ if (insertSecureSettingLocked(name, value, UserHandle.getCallingUserId())) {
+ return Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
+ }
+ } break;
+
+ case TABLE_SYSTEM: {
+ if (insertSystemSettingLocked(name, value, UserHandle.getCallingUserId())) {
+ return Uri.withAppendedPath(Settings.System.CONTENT_URI, name);
+ }
+ } break;
+
+ default: {
+ throw new IllegalArgumentException("Bad Uri path:" + uri);
}
- args.table = TABLE_GLOBAL; // next condition will rewrite the user handle
}
}
- // Check write permissions only after determining which table the insert will touch
- checkWritePermissions(args);
-
- checkUserRestrictions(name, desiredUserHandle);
-
- // The global table is stored under the owner, always
- if (TABLE_GLOBAL.equals(args.table)) {
- desiredUserHandle = UserHandle.USER_OWNER;
- }
-
- SettingsCache cache = cacheForTable(desiredUserHandle, args.table);
- String value = initialValues.getAsString(Settings.NameValueTable.VALUE);
- if (SettingsCache.isRedundantSetValue(cache, name, value)) {
- return Uri.withAppendedPath(url, name);
- }
-
- final AtomicInteger mutationCount;
- synchronized (this) {
- mutationCount = sKnownMutationsInFlight.get(callingUser);
- }
- if (mutationCount != null) {
- mutationCount.incrementAndGet();
- }
- DatabaseHelper dbH = getOrEstablishDatabase(desiredUserHandle);
- SQLiteDatabase db = dbH.getWritableDatabase();
- final long rowId = db.insert(args.table, null, initialValues);
- if (mutationCount != null) {
- mutationCount.decrementAndGet();
- }
- if (rowId <= 0) return null;
-
- SettingsCache.populate(cache, initialValues); // before we notify
-
- if (LOCAL_LOGV) Log.v(TAG, args.table + " <- " + initialValues
- + " for user " + desiredUserHandle);
- // Note that we use the original url here, not the potentially-rewritten table name
- url = getUriFor(url, initialValues, rowId);
- sendNotify(url, desiredUserHandle);
- return url;
+ return null;
}
@Override
- public int delete(Uri url, String where, String[] whereArgs) {
- int callingUser = UserHandle.getCallingUserId();
- if (LOCAL_LOGV) Slog.v(TAG, "delete() for user " + callingUser);
- SqlArguments args = new SqlArguments(url, where, whereArgs);
- if (TABLE_FAVORITES.equals(args.table)) {
- return 0;
- } else if (TABLE_OLD_FAVORITES.equals(args.table)) {
- args.table = TABLE_FAVORITES;
- } else if (TABLE_GLOBAL.equals(args.table)) {
- callingUser = UserHandle.USER_OWNER;
+ public int bulkInsert(Uri uri, ContentValues[] allValues) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "bulkInsert() for user: " + UserHandle.getCallingUserId());
}
- checkWritePermissions(args);
- final AtomicInteger mutationCount;
- synchronized (this) {
- mutationCount = sKnownMutationsInFlight.get(callingUser);
+ int insertionCount = 0;
+ final int valuesCount = allValues.length;
+ for (int i = 0; i < valuesCount; i++) {
+ ContentValues values = allValues[i];
+ if (insert(uri, values) != null) {
+ insertionCount++;
+ }
}
- if (mutationCount != null) {
- mutationCount.incrementAndGet();
- }
- DatabaseHelper dbH = getOrEstablishDatabase(callingUser);
- SQLiteDatabase db = dbH.getWritableDatabase();
- int count = db.delete(args.table, args.where, args.args);
- if (mutationCount != null) {
- mutationCount.decrementAndGet();
- }
- if (count > 0) {
- invalidateCache(callingUser, args.table); // before we notify
- sendNotify(url, callingUser);
- }
- startAsyncCachePopulation(callingUser);
- if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) deleted");
- return count;
+
+ return insertionCount;
}
@Override
- public int update(Uri url, ContentValues initialValues, String where, String[] whereArgs) {
- // NOTE: update() is never called by the front-end Settings API, and updates that
- // wind up affecting rows in Secure that are globally shared will not have the
- // intended effect (the update will be invisible to the rest of the system).
- // This should have no practical effect, since writes to the Secure db can only
- // be done by system code, and that code should be using the correct API up front.
- int callingUser = UserHandle.getCallingUserId();
- if (LOCAL_LOGV) Slog.v(TAG, "update() for user " + callingUser);
- SqlArguments args = new SqlArguments(url, where, whereArgs);
- if (TABLE_FAVORITES.equals(args.table)) {
- return 0;
- } else if (TABLE_GLOBAL.equals(args.table)) {
- callingUser = UserHandle.USER_OWNER;
+ public int delete(Uri uri, String where, String[] whereArgs) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "delete() for user: " + UserHandle.getCallingUserId());
}
- checkWritePermissions(args);
- checkUserRestrictions(initialValues.getAsString(Settings.Secure.NAME), callingUser);
- final AtomicInteger mutationCount;
- synchronized (this) {
- mutationCount = sKnownMutationsInFlight.get(callingUser);
+ Arguments args = new Arguments(uri, where, whereArgs, false);
+
+ // If a legacy table that is gone, done.
+ if (REMOVED_LEGACY_TABLES.contains(args.table)) {
+ return 0;
}
- if (mutationCount != null) {
- mutationCount.incrementAndGet();
+
+ if (TextUtils.isEmpty(args.name)) {
+ return 0;
}
- DatabaseHelper dbH = getOrEstablishDatabase(callingUser);
- SQLiteDatabase db = dbH.getWritableDatabase();
- int count = db.update(args.table, initialValues, args.where, args.args);
- if (mutationCount != null) {
- mutationCount.decrementAndGet();
+
+ synchronized (mLock) {
+ switch (args.table) {
+ case TABLE_GLOBAL: {
+ final int userId = UserHandle.getCallingUserId();
+ return deleteGlobalSettingLocked(args.name, userId) ? 1 : 0;
+ }
+
+ case TABLE_SECURE: {
+ final int userId = UserHandle.getCallingUserId();
+ return deleteSecureSettingLocked(args.name, userId) ? 1 : 0;
+ }
+
+ case TABLE_SYSTEM: {
+ final int userId = UserHandle.getCallingUserId();
+ return deleteSystemSettingLocked(args.name, userId) ? 1 : 0;
+ }
+
+ default: {
+ throw new IllegalArgumentException("Bad Uri path:" + uri);
+ }
+ }
}
- if (count > 0) {
- invalidateCache(callingUser, args.table); // before we notify
- sendNotify(url, callingUser);
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "update() for user: " + UserHandle.getCallingUserId());
}
- startAsyncCachePopulation(callingUser);
- if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) <- " + initialValues);
- return count;
+
+ Arguments args = new Arguments(uri, where, whereArgs, false);
+
+ // If a legacy table that is gone, done.
+ if (REMOVED_LEGACY_TABLES.contains(args.table)) {
+ return 0;
+ }
+
+ String value = values.getAsString(Settings.Secure.VALUE);
+ if (TextUtils.isEmpty(value)) {
+ return 0;
+ }
+
+ synchronized (mLock) {
+ switch (args.table) {
+ case TABLE_GLOBAL: {
+ final int userId = UserHandle.getCallingUserId();
+ return updateGlobalSettingLocked(args.name, value, userId) ? 1 : 0;
+ }
+
+ case TABLE_SECURE: {
+ final int userId = UserHandle.getCallingUserId();
+ return updateSecureSettingLocked(args.name, value, userId) ? 1 : 0;
+ }
+
+ case TABLE_SYSTEM: {
+ final int userId = UserHandle.getCallingUserId();
+ return updateSystemSettingLocked(args.name, value, userId) ? 1 : 0;
+ }
+
+ default: {
+ throw new IllegalArgumentException("Invalid Uri path:" + uri);
+ }
+ }
+ }
}
@Override
@@ -1229,102 +479,1366 @@
+ "ringtone playback is available through android.media.Ringtone");
}
- /**
- * In-memory LRU Cache of system and secure settings, along with
- * associated helper functions to keep cache coherent with the
- * database.
+ private void registerBroadcastReceivers() {
+ IntentFilter userFilter = new IntentFilter();
+ userFilter.addAction(Intent.ACTION_USER_REMOVED);
+ userFilter.addAction(Intent.ACTION_USER_STOPPED);
+
+ getContext().registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ UserHandle.USER_OWNER);
+
+ switch (intent.getAction()) {
+ case Intent.ACTION_USER_REMOVED: {
+ mSettingsRegistry.removeUserStateLocked(userId, true);
+ } break;
+
+ case Intent.ACTION_USER_STOPPED: {
+ mSettingsRegistry.removeUserStateLocked(userId, false);
+ } break;
+ }
+ }
+ }, userFilter);
+
+ PackageMonitor monitor = new PackageMonitor() {
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ synchronized (mLock) {
+ mSettingsRegistry.onPackageRemovedLocked(packageName,
+ UserHandle.getUserId(uid));
+ }
+ }
+ };
+
+ // package changes
+ monitor.register(getContext(), BackgroundThread.getHandler().getLooper(),
+ UserHandle.ALL, true);
+ }
+
+ private Cursor getAllGlobalSettingsLocked(String[] projection) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "getAllGlobalSettingsLocked()");
+ }
+
+ // Get the settings.
+ SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
+ SettingsRegistry.SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+
+ List<String> names = settingsState.getSettingNamesLocked();
+
+ final int nameCount = names.size();
+
+ String[] normalizedProjection = normalizeProjection(projection);
+ MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
+
+ // Anyone can get the global settings, so no security checks.
+ for (int i = 0; i < nameCount; i++) {
+ String name = names.get(i);
+ Setting setting = settingsState.getSettingLocked(name);
+ appendSettingToCursor(result, setting);
+ }
+
+ return result;
+ }
+
+ private Setting getGlobalSettingLocked(String name) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "getGlobalSetting(" + name + ")");
+ }
+
+ // Get the value.
+ return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+ UserHandle.USER_OWNER, name);
+ }
+
+ private boolean updateGlobalSettingLocked(String name, String value, int requestingUserId) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "updateGlobalSettingLocked(" + name + ", " + value + ")");
+ }
+ return mutateGlobalSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
+ }
+
+ private boolean insertGlobalSettingLocked(String name, String value, int requestingUserId) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "insertGlobalSettingLocked(" + name + ", " + value + ")");
+ }
+ return mutateGlobalSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
+ }
+
+ private boolean deleteGlobalSettingLocked(String name, int requestingUserId) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "deleteGlobalSettingLocked(" + name + ")");
+ }
+ return mutateGlobalSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
+ }
+
+ private boolean mutateGlobalSettingLocked(String name, String value, int requestingUserId,
+ int operation) {
+ // Make sure the caller can change the settings - treated as secure.
+ enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
+
+ // Verify whether this operation is allowed for the calling package.
+ if (!isAppOpWriteSettingsAllowedForCallingPackage()) {
+ return false;
+ }
+
+ // Resolve the userId on whose behalf the call is made.
+ final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
+
+ // If this is a setting that is currently restricted for this user, done.
+ if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId)) {
+ return false;
+ }
+
+ // Perform the mutation.
+ switch (operation) {
+ case MUTATION_OPERATION_INSERT: {
+ return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+ UserHandle.USER_OWNER, name, value, getCallingPackage());
+ }
+
+ case MUTATION_OPERATION_DELETE: {
+ return mSettingsRegistry.deleteSettingLocked(
+ SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+ UserHandle.USER_OWNER, name);
+ }
+
+ case MUTATION_OPERATION_UPDATE: {
+ return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+ UserHandle.USER_OWNER, name, value, getCallingPackage());
+ }
+ }
+
+ return false;
+ }
+
+ private Cursor getAllSecureSettingsLocked(int userId, String[] projection) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "getAllSecureSettings(" + userId + ")");
+ }
+
+ // Resolve the userId on whose behalf the call is made.
+ final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
+
+ List<String> names = mSettingsRegistry.getSettingsNamesLocked(
+ SettingsRegistry.SETTINGS_TYPE_SECURE, callingUserId);
+
+ final int nameCount = names.size();
+
+ String[] normalizedProjection = normalizeProjection(projection);
+ MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
+
+ for (int i = 0; i < nameCount; i++) {
+ String name = names.get(i);
+
+ // Determine the owning user as some profile settings are cloned from the parent.
+ final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
+
+ // Special case for location (sigh).
+ if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
+ return null;
+ }
+
+ Setting setting = mSettingsRegistry.getSettingLocked(
+ SettingsRegistry.SETTINGS_TYPE_SECURE, owningUserId, name);
+ appendSettingToCursor(result, setting);
+ }
+
+ return result;
+ }
+
+ private Setting getSecureSettingLocked(String name, int requestingUserId) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "getSecureSetting(" + name + ", " + requestingUserId + ")");
+ }
+
+ // Resolve the userId on whose behalf the call is made.
+ final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
+
+ // Determine the owning user as some profile settings are cloned from the parent.
+ final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
+
+ // Special case for location (sigh).
+ if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
+ return null;
+ }
+
+ // Get the value.
+ return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
+ owningUserId, name);
+ }
+
+ private boolean insertSecureSettingLocked(String name, String value, int requestingUserId) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "insertSecureSettingLocked(" + name + ", " + value + ", "
+ + requestingUserId + ")");
+ }
+
+ return mutateSecureSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
+ }
+
+ private boolean deleteSecureSettingLocked(String name, int requestingUserId) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "deleteSecureSettingLocked(" + name + ", " + requestingUserId + ")");
+ }
+
+ return mutateSecureSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
+ }
+
+ private boolean updateSecureSettingLocked(String name, String value, int requestingUserId) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "updateSecureSettingLocked(" + name + ", " + value + ", "
+ + requestingUserId + ")");
+ }
+
+ return mutateSecureSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
+ }
+
+ private boolean mutateSecureSettingLocked(String name, String value, int requestingUserId,
+ int operation) {
+ // Make sure the caller can change the settings.
+ enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
+
+ // Verify whether this operation is allowed for the calling package.
+ if (!isAppOpWriteSettingsAllowedForCallingPackage()) {
+ return false;
+ }
+
+ // Resolve the userId on whose behalf the call is made.
+ final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
+
+ // If this is a setting that is currently restricted for this user, done.
+ if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId)) {
+ return false;
+ }
+
+ // Determine the owning user as some profile settings are cloned from the parent.
+ final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
+
+ // Only the owning user can change the setting.
+ if (owningUserId != callingUserId) {
+ return false;
+ }
+
+ // Special cases for location providers (sigh).
+ if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
+ return updateLocationProvidersAllowed(value, owningUserId);
+ }
+
+ // Mutate the value.
+ switch(operation) {
+ case MUTATION_OPERATION_INSERT: {
+ return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
+ owningUserId, name, value, getCallingPackage());
+ }
+
+ case MUTATION_OPERATION_DELETE: {
+ return mSettingsRegistry.deleteSettingLocked(
+ SettingsRegistry.SETTINGS_TYPE_SECURE,
+ owningUserId, name);
+ }
+
+ case MUTATION_OPERATION_UPDATE: {
+ return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
+ owningUserId, name, value, getCallingPackage());
+ }
+ }
+
+ return false;
+ }
+
+ private Cursor getAllSystemSettingsLocked(int userId, String[] projection) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "getAllSecureSystemLocked(" + userId + ")");
+ }
+
+ // Resolve the userId on whose behalf the call is made.
+ final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
+
+ List<String> names = mSettingsRegistry.getSettingsNamesLocked(
+ SettingsRegistry.SETTINGS_TYPE_SYSTEM, callingUserId);
+
+ final int nameCount = names.size();
+
+ String[] normalizedProjection = normalizeProjection(projection);
+ MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
+
+ for (int i = 0; i < nameCount; i++) {
+ String name = names.get(i);
+
+ // Determine the owning user as some profile settings are cloned from the parent.
+ final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
+
+ Setting setting = mSettingsRegistry.getSettingLocked(
+ SettingsRegistry.SETTINGS_TYPE_SYSTEM, owningUserId, name);
+ appendSettingToCursor(result, setting);
+ }
+
+ return result;
+ }
+
+ private Setting getSystemSettingLocked(String name, int requestingUserId) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "getSystemSetting(" + name + ", " + requestingUserId + ")");
+ }
+
+ // Resolve the userId on whose behalf the call is made.
+ final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
+
+ // Determine the owning user as some profile settings are cloned from the parent.
+ final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
+
+ // Get the value.
+ return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+ owningUserId, name);
+ }
+
+ private boolean insertSystemSettingLocked(String name, String value, int requestingUserId) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "insertSystemSettingLocked(" + name + ", " + value + ", "
+ + requestingUserId + ")");
+ }
+
+ return mutateSystemSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
+ }
+
+ private boolean deleteSystemSettingLocked(String name, int requestingUserId) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "deleteSystemSettingLocked(" + name + ", " + requestingUserId + ")");
+ }
+
+ return mutateSystemSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
+ }
+
+ private boolean updateSystemSettingLocked(String name, String value, int requestingUserId) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "updateSystemSettingLocked(" + name + ", " + value + ", "
+ + requestingUserId + ")");
+ }
+
+ return mutateSystemSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
+ }
+
+ private boolean mutateSystemSettingLocked(String name, String value, int runAsUserId,
+ int operation) {
+ // Make sure the caller can change the settings.
+ enforceWritePermission(Manifest.permission.WRITE_SETTINGS);
+
+ // Verify whether this operation is allowed for the calling package.
+ if (!isAppOpWriteSettingsAllowedForCallingPackage()) {
+ return false;
+ }
+
+ // Enforce what the calling package can mutate in the system settings.
+ enforceRestrictedSystemSettingsMutationForCallingPackageLocked(operation, name);
+
+ // Resolve the userId on whose behalf the call is made.
+ final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(runAsUserId);
+
+ // Determine the owning user as some profile settings are cloned from the parent.
+ final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
+
+ // Only the owning user id can change the setting.
+ if (owningUserId != callingUserId) {
+ return false;
+ }
+
+ // Mutate the value.
+ switch (operation) {
+ case MUTATION_OPERATION_INSERT: {
+ validateSystemSettingValue(name, value);
+ return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+ owningUserId, name, value, getCallingPackage());
+ }
+
+ case MUTATION_OPERATION_DELETE: {
+ return mSettingsRegistry.deleteSettingLocked(
+ SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+ owningUserId, name);
+ }
+
+ case MUTATION_OPERATION_UPDATE: {
+ validateSystemSettingValue(name, value);
+ return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+ owningUserId, name, value, getCallingPackage());
+ }
+ }
+
+ return false;
+ }
+
+ private void validateSystemSettingValue(String name, String value) {
+ Settings.System.Validator validator = Settings.System.VALIDATORS.get(name);
+ if (validator != null && !validator.validate(value)) {
+ throw new IllegalArgumentException("Invalid value: " + value
+ + " for setting: " + name);
+ }
+ }
+
+ private boolean isLocationProvidersAllowedRestricted(String name, int callingUserId,
+ int owningUserId) {
+ // Optimization - location providers are restricted only for managed profiles.
+ if (callingUserId == owningUserId) {
+ return false;
+ }
+ if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)
+ && mUserManager.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
+ new UserHandle(callingUserId))) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isGlobalOrSecureSettingRestrictedForUser(String setting, int userId) {
+ String restriction = sSettingToUserRestrictionMap.get(setting);
+ if (restriction == null) {
+ return false;
+ }
+ return mUserManager.hasUserRestriction(restriction, new UserHandle(userId));
+ }
+
+ private int resolveOwningUserIdForSecureSettingLocked(int userId, String setting) {
+ return resolveOwningUserIdLocked(userId, sSecureCloneToManagedSettings, setting);
+ }
+
+ private int resolveOwningUserIdForSystemSettingLocked(int userId, String setting) {
+ return resolveOwningUserIdLocked(userId, sSystemCloneToManagedSettings, setting);
+ }
+
+ private int resolveOwningUserIdLocked(int userId, Set<String> keys, String name) {
+ final int parentId = getGroupParentLocked(userId);
+ if (parentId != userId && keys.contains(name)) {
+ return parentId;
+ }
+ return userId;
+ }
+
+ private void enforceRestrictedSystemSettingsMutationForCallingPackageLocked(int operation,
+ String name) {
+ // System/root/shell can mutate whatever secure settings they want.
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid == android.os.Process.SYSTEM_UID
+ || callingUid == Process.SHELL_UID
+ || callingUid == Process.ROOT_UID) {
+ return;
+ }
+
+ switch (operation) {
+ case MUTATION_OPERATION_INSERT:
+ // Insert updates.
+ case MUTATION_OPERATION_UPDATE: {
+ if (Settings.System.PUBLIC_SETTINGS.contains(name)) {
+ return;
+ }
+
+ // The calling package is already verified.
+ PackageInfo packageInfo = getCallingPackageInfoOrThrow();
+
+ // Privileged apps can do whatever they want.
+ if ((packageInfo.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
+ return;
+ }
+
+ warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
+ packageInfo.applicationInfo.targetSdkVersion, name);
+ } break;
+
+ case MUTATION_OPERATION_DELETE: {
+ if (Settings.System.PUBLIC_SETTINGS.contains(name)
+ || Settings.System.PRIVATE_SETTINGS.contains(name)) {
+ throw new IllegalArgumentException("You cannot delete system defined"
+ + " secure settings.");
+ }
+
+ // The calling package is already verified.
+ PackageInfo packageInfo = getCallingPackageInfoOrThrow();
+
+ // Privileged apps can do whatever they want.
+ if ((packageInfo.applicationInfo.privateFlags &
+ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
+ return;
+ }
+
+ warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
+ packageInfo.applicationInfo.targetSdkVersion, name);
+ } break;
+ }
+ }
+
+ private PackageInfo getCallingPackageInfoOrThrow() {
+ try {
+ return mPackageManager.getPackageInfo(getCallingPackage(), 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalStateException("Calling package doesn't exist");
+ }
+ }
+
+ private int getGroupParentLocked(int userId) {
+ // Most frequent use case.
+ if (userId == UserHandle.USER_OWNER) {
+ return userId;
+ }
+ // We are in the same process with the user manager and the returned
+ // user info is a cached instance, so just look up instead of cache.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ UserInfo userInfo = mUserManager.getProfileParent(userId);
+ return (userInfo != null) ? userInfo.id : userId;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private boolean isAppOpWriteSettingsAllowedForCallingPackage() {
+ final int callingUid = Binder.getCallingUid();
+
+ mAppOpsManager.checkPackage(Binder.getCallingUid(), getCallingPackage());
+
+ return mAppOpsManager.noteOp(AppOpsManager.OP_WRITE_SETTINGS, callingUid,
+ getCallingPackage()) == AppOpsManager.MODE_ALLOWED;
+ }
+
+ private void enforceWritePermission(String permission) {
+ if (getContext().checkCallingOrSelfPermission(permission)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Permission denial: writing to settings requires:"
+ + permission);
+ }
+ }
+
+ /*
+ * Used to parse changes to the value of Settings.Secure.LOCATION_PROVIDERS_ALLOWED.
+ * This setting contains a list of the currently enabled location providers.
+ * But helper functions in android.providers.Settings can enable or disable
+ * a single provider by using a "+" or "-" prefix before the provider name.
+ *
+ * @returns whether the enabled location providers changed.
*/
- private static final class SettingsCache extends LruCache<String, Bundle> {
-
- private final String mCacheName;
- private boolean mCacheFullyMatchesDisk = false; // has the whole database slurped.
-
- public SettingsCache(String name) {
- super(MAX_CACHE_ENTRIES);
- mCacheName = name;
+ private boolean updateLocationProvidersAllowed(String value, int owningUserId) {
+ if (TextUtils.isEmpty(value)) {
+ return false;
}
- /**
- * Is the whole database table slurped into this cache?
- */
- public boolean fullyMatchesDisk() {
- synchronized (this) {
- return mCacheFullyMatchesDisk;
+ final char prefix = value.charAt(0);
+ if (prefix != '+' && prefix != '-') {
+ return false;
+ }
+
+ // skip prefix
+ value = value.substring(1);
+
+ Setting settingValue = getSecureSettingLocked(
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED, owningUserId);
+
+ String oldProviders = (settingValue != null) ? settingValue.getValue() : "";
+
+ int index = oldProviders.indexOf(value);
+ int end = index + value.length();
+
+ // check for commas to avoid matching on partial string
+ if (index > 0 && oldProviders.charAt(index - 1) != ',') {
+ index = -1;
+ }
+
+ // check for commas to avoid matching on partial string
+ if (end < oldProviders.length() && oldProviders.charAt(end) != ',') {
+ index = -1;
+ }
+
+ String newProviders;
+
+ if (prefix == '+' && index < 0) {
+ // append the provider to the list if not present
+ if (oldProviders.length() == 0) {
+ newProviders = value;
+ } else {
+ newProviders = oldProviders + ',' + value;
+ }
+ } else if (prefix == '-' && index >= 0) {
+ // remove the provider from the list if present
+ // remove leading or trailing comma
+ if (index > 0) {
+ index--;
+ } else if (end < oldProviders.length()) {
+ end++;
+ }
+
+ newProviders = oldProviders.substring(0, index);
+ if (end < oldProviders.length()) {
+ newProviders += oldProviders.substring(end);
+ }
+ } else {
+ // nothing changed, so no need to update the database
+ return false;
+ }
+
+ updateSecureSettingLocked(Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ newProviders, owningUserId);
+
+ return true;
+ }
+
+ private void sendNotify(Uri uri, int userId) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ getContext().getContentResolver().notifyChange(uri, null, true, userId);
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "Notifying for " + userId + ": " + uri);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private static void warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
+ int targetSdkVersion, String name) {
+ // If the app targets Lollipop MR1 or older SDK we warn, otherwise crash.
+ if (targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+ if (Settings.System.PRIVATE_SETTINGS.contains(name)) {
+ Slog.w(LOG_TAG, "You shouldn't not change private system settings."
+ + " This will soon become an error.");
+ } else {
+ Slog.w(LOG_TAG, "You shouldn't keep your settings in the secure settings."
+ + " This will soon become an error.");
+ }
+ } else {
+ if (Settings.System.PRIVATE_SETTINGS.contains(name)) {
+ throw new IllegalArgumentException("You cannot change private secure settings.");
+ } else {
+ throw new IllegalArgumentException("You cannot keep your settings in"
+ + " the secure settings.");
+ }
+ }
+ }
+
+ private static int resolveCallingUserIdEnforcingPermissionsLocked(int requestingUserId) {
+ if (requestingUserId == UserHandle.getCallingUserId()) {
+ return requestingUserId;
+ }
+ return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), requestingUserId, false, true,
+ "get/set setting for user", null);
+ }
+
+ private static Bundle packageValueForCallResult(Setting setting) {
+ if (setting == null) {
+ return NULL_SETTING;
+ }
+ return Bundle.forPair(Settings.NameValueTable.VALUE, setting.getValue());
+ }
+
+ private static int getRequestingUserId(Bundle args) {
+ final int callingUserId = UserHandle.getCallingUserId();
+ return (args != null) ? args.getInt(Settings.CALL_METHOD_USER_KEY, callingUserId)
+ : callingUserId;
+ }
+
+ private static String getSettingValue(Bundle args) {
+ return (args != null) ? args.getString(Settings.NameValueTable.VALUE) : null;
+ }
+
+ private static String getValidTableOrThrow(Uri uri) {
+ if (uri.getPathSegments().size() > 0) {
+ String table = uri.getPathSegments().get(0);
+ if (DatabaseHelper.isValidTable(table)) {
+ return table;
+ }
+ throw new IllegalArgumentException("Bad root path: " + table);
+ }
+ throw new IllegalArgumentException("Invalid URI:" + uri);
+ }
+
+ private static MatrixCursor packageSettingForQuery(Setting setting, String[] projection) {
+ if (setting == null) {
+ return new MatrixCursor(projection, 0);
+ }
+ MatrixCursor cursor = new MatrixCursor(projection, 1);
+ appendSettingToCursor(cursor, setting);
+ return cursor;
+ }
+
+ private static String[] normalizeProjection(String[] projection) {
+ if (projection == null) {
+ return ALL_COLUMNS;
+ }
+
+ final int columnCount = projection.length;
+ for (int i = 0; i < columnCount; i++) {
+ String column = projection[i];
+ if (!ArrayUtils.contains(ALL_COLUMNS, column)) {
+ throw new IllegalArgumentException("Invalid column: " + column);
}
}
- public void setFullyMatchesDisk(boolean value) {
- synchronized (this) {
- mCacheFullyMatchesDisk = value;
+ return projection;
+ }
+
+ private static void appendSettingToCursor(MatrixCursor cursor, Setting setting) {
+ final int columnCount = cursor.getColumnCount();
+
+ String[] values = new String[columnCount];
+
+ for (int i = 0; i < columnCount; i++) {
+ String column = cursor.getColumnName(i);
+
+ switch (column) {
+ case Settings.NameValueTable._ID: {
+ values[i] = setting.getId();
+ } break;
+
+ case Settings.NameValueTable.NAME: {
+ values[i] = setting.getName();
+ } break;
+
+ case Settings.NameValueTable.VALUE: {
+ values[i] = setting.getValue();
+ } break;
}
}
- @Override
- protected void entryRemoved(boolean evicted, String key, Bundle oldValue, Bundle newValue) {
- if (evicted) {
- mCacheFullyMatchesDisk = false;
- }
- }
+ cursor.addRow(values);
+ }
- /**
- * Atomic cache population, conditional on size of value and if
- * we lost a race.
- *
- * @returns a Bundle to send back to the client from call(), even
- * if we lost the race.
- */
- public Bundle putIfAbsent(String key, String value) {
- Bundle bundle = (value == null) ? NULL_SETTING : Bundle.forPair("value", value);
- if (value == null || value.length() <= MAX_CACHE_ENTRY_SIZE) {
- synchronized (this) {
- if (get(key) == null) {
- put(key, bundle);
+ private static final class Arguments {
+ private static final Pattern WHERE_PATTERN_WITH_PARAM_NO_BRACKETS =
+ Pattern.compile("[\\s]*name[\\s]*=[\\s]*\\?[\\s]*");
+
+ private static final Pattern WHERE_PATTERN_WITH_PARAM_IN_BRACKETS =
+ Pattern.compile("[\\s]*\\([\\s]*name[\\s]*=[\\s]*\\?[\\s]*\\)[\\s]*");
+
+ private static final Pattern WHERE_PATTERN_NO_PARAM_IN_BRACKETS =
+ Pattern.compile("[\\s]*\\([\\s]*name[\\s]*=[\\s]*['\"].*['\"][\\s]*\\)[\\s]*");
+
+ private static final Pattern WHERE_PATTERN_NO_PARAM_NO_BRACKETS =
+ Pattern.compile("[\\s]*name[\\s]*=[\\s]*['\"].*['\"][\\s]*");
+
+ public final String table;
+ public final String name;
+
+ public Arguments(Uri uri, String where, String[] whereArgs, boolean supportAll) {
+ final int segmentSize = uri.getPathSegments().size();
+ switch (segmentSize) {
+ case 1: {
+ if (where != null
+ && (WHERE_PATTERN_WITH_PARAM_NO_BRACKETS.matcher(where).matches()
+ || WHERE_PATTERN_WITH_PARAM_IN_BRACKETS.matcher(where).matches())
+ && whereArgs.length == 1) {
+ name = whereArgs[0];
+ table = computeTableForSetting(uri, name);
+ return;
+ } else if (where != null
+ && (WHERE_PATTERN_NO_PARAM_NO_BRACKETS.matcher(where).matches()
+ || WHERE_PATTERN_NO_PARAM_IN_BRACKETS.matcher(where).matches())) {
+ final int startIndex = Math.max(where.indexOf("'"),
+ where.indexOf("\"")) + 1;
+ final int endIndex = Math.max(where.lastIndexOf("'"),
+ where.lastIndexOf("\""));
+ name = where.substring(startIndex, endIndex);
+ table = computeTableForSetting(uri, name);
+ return;
+ } else if (supportAll && where == null && whereArgs == null) {
+ name = null;
+ table = computeTableForSetting(uri, null);
+ return;
}
+ } break;
+
+ case 2: {
+ if (where == null && whereArgs == null) {
+ name = uri.getPathSegments().get(1);
+ table = computeTableForSetting(uri, name);
+ return;
+ }
+ } break;
+ }
+
+ EventLogTags.writeUnsupportedSettingsQuery(
+ uri.toSafeString(), where, Arrays.toString(whereArgs));
+ String message = String.format( "Supported SQL:\n"
+ + " uri content://some_table/some_property with null where and where args\n"
+ + " uri content://some_table with query name=? and single name as arg\n"
+ + " uri content://some_table with query name=some_name and null args\n"
+ + " but got - uri:%1s, where:%2s whereArgs:%3s", uri, where,
+ Arrays.toString(whereArgs));
+ throw new IllegalArgumentException(message);
+ }
+
+ private static String computeTableForSetting(Uri uri, String name) {
+ String table = getValidTableOrThrow(uri);
+
+ if (name != null) {
+ if (sSystemMovedToSecureSettings.contains(name)) {
+ table = TABLE_SECURE;
+ }
+
+ if (sSystemMovedToGlobalSettings.contains(name)) {
+ table = TABLE_GLOBAL;
+ }
+
+ if (sSecureMovedToGlobalSettings.contains(name)) {
+ table = TABLE_GLOBAL;
+ }
+
+ if (sGlobalMovedToSecureSettings.contains(name)) {
+ table = TABLE_SECURE;
}
}
- return bundle;
+
+ return table;
+ }
+ }
+
+ final class SettingsRegistry {
+ private static final String DROPBOX_TAG_USERLOG = "restricted_profile_ssaid";
+
+ private static final int SETTINGS_TYPE_GLOBAL = 0;
+ private static final int SETTINGS_TYPE_SYSTEM = 1;
+ private static final int SETTINGS_TYPE_SECURE = 2;
+
+ private static final int SETTINGS_TYPE_MASK = 0xF0000000;
+ private static final int SETTINGS_TYPE_SHIFT = 28;
+
+ private static final String SETTINGS_FILE_GLOBAL = "settings_global.xml";
+ private static final String SETTINGS_FILE_SYSTEM = "settings_system.xml";
+ private static final String SETTINGS_FILE_SECURE = "settings_secure.xml";
+
+ private final SparseArray<SettingsState> mSettingsStates = new SparseArray<>();
+
+ private final BackupManager mBackupManager;
+
+ public SettingsRegistry() {
+ mBackupManager = new BackupManager(getContext());
+ migrateAllLegacySettingsIfNeeded();
}
- /**
- * Populates a key in a given (possibly-null) cache.
- */
- public static void populate(SettingsCache cache, ContentValues contentValues) {
- if (cache == null) {
- return;
- }
- String name = contentValues.getAsString(Settings.NameValueTable.NAME);
- if (name == null) {
- Log.w(TAG, "null name populating settings cache.");
- return;
- }
- String value = contentValues.getAsString(Settings.NameValueTable.VALUE);
- cache.populate(name, value);
+ public List<String> getSettingsNamesLocked(int type, int userId) {
+ final int key = makeKey(type, userId);
+ SettingsState settingsState = peekSettingsStateLocked(key);
+ return settingsState.getSettingNamesLocked();
}
- public void populate(String name, String value) {
- synchronized (this) {
- if (value == null || value.length() <= MAX_CACHE_ENTRY_SIZE) {
- put(name, Bundle.forPair(Settings.NameValueTable.VALUE, value));
+ public SettingsState getSettingsLocked(int type, int userId) {
+ final int key = makeKey(type, userId);
+ return peekSettingsStateLocked(key);
+ }
+
+ public void ensureSettingsForUserLocked(int userId) {
+ // Migrate the setting for this user if needed.
+ migrateLegacySettingsForUserIfNeededLocked(userId);
+
+ // Ensure global settings loaded if owner.
+ if (userId == UserHandle.USER_OWNER) {
+ final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+ ensureSettingsStateLocked(globalKey);
+ }
+
+ // Ensure secure settings loaded.
+ final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+ ensureSettingsStateLocked(secureKey);
+
+ // Make sure the secure settings have an Android id set.
+ SettingsState secureSettings = getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
+ ensureSecureSettingAndroidIdSetLocked(secureSettings);
+
+ // Ensure system settings loaded.
+ final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
+ ensureSettingsStateLocked(systemKey);
+
+ // Upgrade the settings to the latest version.
+ UpgradeController upgrader = new UpgradeController(userId);
+ upgrader.upgradeIfNeededLocked();
+ }
+
+ private void ensureSettingsStateLocked(int key) {
+ if (mSettingsStates.get(key) == null) {
+ final int maxBytesPerPackage = getMaxBytesPerPackageForType(getTypeFromKey(key));
+ SettingsState settingsState = new SettingsState(mLock, getSettingsFile(key), key,
+ maxBytesPerPackage);
+ mSettingsStates.put(key, settingsState);
+ }
+ }
+
+ public void removeUserStateLocked(int userId, boolean permanently) {
+ // We always keep the global settings in memory.
+
+ // Nuke system settings.
+ final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
+ final SettingsState systemSettingsState = mSettingsStates.get(systemKey);
+ if (systemSettingsState != null) {
+ if (permanently) {
+ mSettingsStates.remove(systemKey);
+ systemSettingsState.destroyLocked(null);
} else {
- put(name, TOO_LARGE_TO_CACHE_MARKER);
+ systemSettingsState.destroyLocked(new Runnable() {
+ @Override
+ public void run() {
+ mSettingsStates.remove(systemKey);
+ }
+ });
+ }
+ }
+
+ // Nuke secure settings.
+ final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+ final SettingsState secureSettingsState = mSettingsStates.get(secureKey);
+ if (secureSettingsState != null) {
+ if (permanently) {
+ mSettingsStates.remove(secureKey);
+ secureSettingsState.destroyLocked(null);
+ } else {
+ secureSettingsState.destroyLocked(new Runnable() {
+ @Override
+ public void run() {
+ mSettingsStates.remove(secureKey);
+ }
+ });
}
}
}
- /**
- * For suppressing duplicate/redundant settings inserts early,
- * checking our cache first (but without faulting it in),
- * before going to sqlite with the mutation.
- */
- public static boolean isRedundantSetValue(SettingsCache cache, String name, String value) {
- if (cache == null) return false;
- synchronized (cache) {
- Bundle bundle = cache.get(name);
- if (bundle == null) return false;
- String oldValue = bundle.getPairValue();
- if (oldValue == null && value == null) return true;
- if ((oldValue == null) != (value == null)) return false;
- return oldValue.equals(value);
+ public boolean insertSettingLocked(int type, int userId, String name, String value,
+ String packageName) {
+ final int key = makeKey(type, userId);
+
+ SettingsState settingsState = peekSettingsStateLocked(key);
+ final boolean success = settingsState.insertSettingLocked(name, value, packageName);
+
+ if (success) {
+ notifyForSettingsChange(key, name);
+ }
+ return success;
+ }
+
+ public boolean deleteSettingLocked(int type, int userId, String name) {
+ final int key = makeKey(type, userId);
+
+ SettingsState settingsState = peekSettingsStateLocked(key);
+ final boolean success = settingsState.deleteSettingLocked(name);
+
+ if (success) {
+ notifyForSettingsChange(key, name);
+ }
+ return success;
+ }
+
+ public Setting getSettingLocked(int type, int userId, String name) {
+ final int key = makeKey(type, userId);
+
+ SettingsState settingsState = peekSettingsStateLocked(key);
+ return settingsState.getSettingLocked(name);
+ }
+
+ public boolean updateSettingLocked(int type, int userId, String name, String value,
+ String packageName) {
+ final int key = makeKey(type, userId);
+
+ SettingsState settingsState = peekSettingsStateLocked(key);
+ final boolean success = settingsState.updateSettingLocked(name, value, packageName);
+
+ if (success) {
+ notifyForSettingsChange(key, name);
+ }
+
+ return success;
+ }
+
+ public void onPackageRemovedLocked(String packageName, int userId) {
+ final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+ SettingsState globalSettings = mSettingsStates.get(globalKey);
+ globalSettings.onPackageRemovedLocked(packageName);
+
+ final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+ SettingsState secureSettings = mSettingsStates.get(secureKey);
+ secureSettings.onPackageRemovedLocked(packageName);
+
+ final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
+ SettingsState systemSettings = mSettingsStates.get(systemKey);
+ systemSettings.onPackageRemovedLocked(packageName);
+ }
+
+ private SettingsState peekSettingsStateLocked(int key) {
+ SettingsState settingsState = mSettingsStates.get(key);
+ if (settingsState != null) {
+ return settingsState;
+ }
+
+ ensureSettingsForUserLocked(getUserIdFromKey(key));
+ return mSettingsStates.get(key);
+ }
+
+ private void migrateAllLegacySettingsIfNeeded() {
+ synchronized (mLock) {
+ final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+ File globalFile = getSettingsFile(key);
+ if (globalFile.exists()) {
+ return;
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ List<UserInfo> users = mUserManager.getUsers(true);
+
+ final int userCount = users.size();
+ for (int i = 0; i < userCount; i++) {
+ final int userId = users.get(i).id;
+
+ DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
+ SQLiteDatabase database = dbHelper.getWritableDatabase();
+ migrateLegacySettingsForUserLocked(dbHelper, database, userId);
+
+ // Upgrade to the latest version.
+ UpgradeController upgrader = new UpgradeController(userId);
+ upgrader.upgradeIfNeededLocked();
+
+ // Drop from memory if not a running user.
+ if (!mUserManager.isUserRunning(new UserHandle(userId))) {
+ removeUserStateLocked(userId, false);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ private void migrateLegacySettingsForUserIfNeededLocked(int userId) {
+ // Every user has secure settings and if no file we need to migrate.
+ final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+ File secureFile = getSettingsFile(secureKey);
+ if (secureFile.exists()) {
+ return;
+ }
+
+ DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
+ SQLiteDatabase database = dbHelper.getWritableDatabase();
+
+ migrateLegacySettingsForUserLocked(dbHelper, database, userId);
+ }
+
+ private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,
+ SQLiteDatabase database, int userId) {
+ // Move over the global settings if owner.
+ if (userId == UserHandle.USER_OWNER) {
+ final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, userId);
+ ensureSettingsStateLocked(globalKey);
+ SettingsState globalSettings = mSettingsStates.get(globalKey);
+ migrateLegacySettingsLocked(globalSettings, database, TABLE_GLOBAL);
+ globalSettings.persistSyncLocked();
+ }
+
+ // Move over the secure settings.
+ final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+ ensureSettingsStateLocked(secureKey);
+ SettingsState secureSettings = mSettingsStates.get(secureKey);
+ migrateLegacySettingsLocked(secureSettings, database, TABLE_SECURE);
+ ensureSecureSettingAndroidIdSetLocked(secureSettings);
+ secureSettings.persistSyncLocked();
+
+ // Move over the system settings.
+ final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
+ ensureSettingsStateLocked(systemKey);
+ SettingsState systemSettings = mSettingsStates.get(systemKey);
+ migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);
+ systemSettings.persistSyncLocked();
+
+ // Drop the database as now all is moved and persisted.
+ if (DROP_DATABASE_ON_MIGRATION) {
+ dbHelper.dropDatabase();
+ } else {
+ dbHelper.backupDatabase();
+ }
+ }
+
+ private void migrateLegacySettingsLocked(SettingsState settingsState,
+ SQLiteDatabase database, String table) {
+ SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
+ queryBuilder.setTables(table);
+
+ Cursor cursor = queryBuilder.query(database, ALL_COLUMNS,
+ null, null, null, null, null);
+
+ if (cursor == null) {
+ return;
+ }
+
+ try {
+ if (!cursor.moveToFirst()) {
+ return;
+ }
+
+ final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
+ final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
+
+ settingsState.setVersionLocked(database.getVersion());
+
+ while (!cursor.isAfterLast()) {
+ String name = cursor.getString(nameColumnIdx);
+ String value = cursor.getString(valueColumnIdx);
+ settingsState.insertSettingLocked(name, value,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ cursor.moveToNext();
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ private void ensureSecureSettingAndroidIdSetLocked(SettingsState secureSettings) {
+ Setting value = secureSettings.getSettingLocked(Settings.Secure.ANDROID_ID);
+
+ if (value != null) {
+ return;
+ }
+
+ final int userId = getUserIdFromKey(secureSettings.mKey);
+
+ final UserInfo user;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ user = mUserManager.getUserInfo(userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ if (user == null) {
+ // Can happen due to races when deleting users - treat as benign.
+ return;
+ }
+
+ String androidId = Long.toHexString(new SecureRandom().nextLong());
+ secureSettings.insertSettingLocked(Settings.Secure.ANDROID_ID, androidId,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+
+ Slog.d(LOG_TAG, "Generated and saved new ANDROID_ID [" + androidId
+ + "] for user " + userId);
+
+ // Write a drop box entry if it's a restricted profile
+ if (user.isRestricted()) {
+ DropBoxManager dbm = (DropBoxManager) getContext().getSystemService(
+ Context.DROPBOX_SERVICE);
+ if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) {
+ dbm.addText(DROPBOX_TAG_USERLOG, System.currentTimeMillis()
+ + "," + DROPBOX_TAG_USERLOG + "," + androidId + "\n");
+ }
+ }
+ }
+
+ private void notifyForSettingsChange(int key, String name) {
+ // Update the system property *first*, so if someone is listening for
+ // a notification and then using the contract class to get their data,
+ // the system property will be updated and they'll get the new data.
+
+ boolean backedUpDataChanged = false;
+ String property = null;
+ if (isGlobalSettingsKey(key)) {
+ property = Settings.Global.SYS_PROP_SETTING_VERSION;
+ backedUpDataChanged = true;
+ } else if (isSecureSettingsKey(key)) {
+ property = Settings.Secure.SYS_PROP_SETTING_VERSION;
+ backedUpDataChanged = true;
+ } else if (isSystemSettingsKey(key)) {
+ property = Settings.System.SYS_PROP_SETTING_VERSION;
+ backedUpDataChanged = true;
+ }
+
+ if (property != null) {
+ final long version = SystemProperties.getLong(property, 0) + 1;
+ SystemProperties.set(property, Long.toString(version));
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "System property " + property + "=" + version);
+ }
+ }
+
+ // Inform the backup manager about a data change
+ if (backedUpDataChanged) {
+ mBackupManager.dataChanged();
+ }
+
+ // Now send the notification through the content framework.
+
+ final int userId = getUserIdFromKey(key);
+ Uri uri = getNotificationUriFor(key, name);
+
+ sendNotify(uri, userId);
+ }
+
+ private int makeKey(int type, int userId) {
+ return (type << SETTINGS_TYPE_SHIFT) | userId;
+ }
+
+ private int getTypeFromKey(int key) {
+ return key >> SETTINGS_TYPE_SHIFT;
+ }
+
+ private int getUserIdFromKey(int key) {
+ return key & ~SETTINGS_TYPE_MASK;
+ }
+
+ private boolean isGlobalSettingsKey(int key) {
+ return getTypeFromKey(key) == SETTINGS_TYPE_GLOBAL;
+ }
+
+ private boolean isSystemSettingsKey(int key) {
+ return getTypeFromKey(key) == SETTINGS_TYPE_SYSTEM;
+ }
+
+ private boolean isSecureSettingsKey(int key) {
+ return getTypeFromKey(key) == SETTINGS_TYPE_SECURE;
+ }
+
+ private File getSettingsFile(int key) {
+ if (isGlobalSettingsKey(key)) {
+ final int userId = getUserIdFromKey(key);
+ return new File(Environment.getUserSystemDirectory(userId),
+ SETTINGS_FILE_GLOBAL);
+ } else if (isSystemSettingsKey(key)) {
+ final int userId = getUserIdFromKey(key);
+ return new File(Environment.getUserSystemDirectory(userId),
+ SETTINGS_FILE_SYSTEM);
+ } else if (isSecureSettingsKey(key)) {
+ final int userId = getUserIdFromKey(key);
+ return new File(Environment.getUserSystemDirectory(userId),
+ SETTINGS_FILE_SECURE);
+ } else {
+ throw new IllegalArgumentException("Invalid settings key:" + key);
+ }
+ }
+
+ private Uri getNotificationUriFor(int key, String name) {
+ if (isGlobalSettingsKey(key)) {
+ return (name != null) ? Uri.withAppendedPath(Settings.Global.CONTENT_URI, name)
+ : Settings.Global.CONTENT_URI;
+ } else if (isSecureSettingsKey(key)) {
+ return (name != null) ? Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name)
+ : Settings.Secure.CONTENT_URI;
+ } else if (isSystemSettingsKey(key)) {
+ return (name != null) ? Uri.withAppendedPath(Settings.System.CONTENT_URI, name)
+ : Settings.System.CONTENT_URI;
+ } else {
+ throw new IllegalArgumentException("Invalid settings key:" + key);
+ }
+ }
+
+ private int getMaxBytesPerPackageForType(int type) {
+ switch (type) {
+ case SETTINGS_TYPE_GLOBAL:
+ case SETTINGS_TYPE_SECURE: {
+ return SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED;
+ }
+
+ default: {
+ return SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED;
+ }
+ }
+ }
+
+ private final class UpgradeController {
+ private static final int SETTINGS_VERSION = 118;
+
+ private final int mUserId;
+
+ public UpgradeController(int userId) {
+ mUserId = userId;
+ }
+
+ public void upgradeIfNeededLocked() {
+ // The version of all settings for a user is the same (all users have secure).
+ SettingsState secureSettings = getSettingsLocked(
+ SettingsRegistry.SETTINGS_TYPE_SECURE, mUserId);
+
+ // Try an update from the current state.
+ final int oldVersion = secureSettings.getVersionLocked();
+ final int newVersion = SETTINGS_VERSION;
+
+ // If up do data - done.
+ if (oldVersion == newVersion) {
+ return;
+ }
+
+ // Try to upgrade.
+ final int curVersion = onUpgradeLocked(mUserId, oldVersion, newVersion);
+
+ // If upgrade failed start from scratch and upgrade.
+ if (curVersion != newVersion) {
+ // Drop state we have for this user.
+ removeUserStateLocked(mUserId, true);
+
+ // Recreate the database.
+ DatabaseHelper dbHelper = new DatabaseHelper(getContext(), mUserId);
+ SQLiteDatabase database = dbHelper.getWritableDatabase();
+ dbHelper.recreateDatabase(database, newVersion, curVersion, oldVersion);
+
+ // Migrate the settings for this user.
+ migrateLegacySettingsForUserLocked(dbHelper, database, mUserId);
+
+ // Now upgrade should work fine.
+ onUpgradeLocked(mUserId, oldVersion, newVersion);
+ }
+
+ // Set the global settings version if owner.
+ if (mUserId == UserHandle.USER_OWNER) {
+ SettingsState globalSettings = getSettingsLocked(
+ SettingsRegistry.SETTINGS_TYPE_GLOBAL, mUserId);
+ globalSettings.setVersionLocked(newVersion);
+ }
+
+ // Set the secure settings version.
+ secureSettings.setVersionLocked(newVersion);
+
+ // Set the system settings version.
+ SettingsState systemSettings = getSettingsLocked(
+ SettingsRegistry.SETTINGS_TYPE_SYSTEM, mUserId);
+ systemSettings.setVersionLocked(newVersion);
+ }
+
+ private SettingsState getGlobalSettingsLocked() {
+ return getSettingsLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+ }
+
+ private SettingsState getSecureSettingsLocked(int userId) {
+ return getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
+ }
+
+ private SettingsState getSystemSettingsLocked(int userId) {
+ return getSettingsLocked(SETTINGS_TYPE_SYSTEM, userId);
+ }
+
+ private int onUpgradeLocked(int userId, int oldVersion, int newVersion) {
+ if (DEBUG) {
+ Slog.w(LOG_TAG, "Upgrading settings for user: " + userId + " from version: "
+ + oldVersion + " to version: " + newVersion);
+ }
+
+ // You must perform all necessary mutations to bring the settings
+ // for this user from the old to the new version. When you add a new
+ // upgrade step you *must* update SETTINGS_VERSION.
+
+ /**
+ * This is an example of moving a setting from secure to global.
+ *
+ * int currentVersion = oldVersion;
+ * if (currentVersion == 118) {
+ * // Remove from the secure settings.
+ * SettingsState secureSettings = getSecureSettingsLocked(userId);
+ * String name = "example_setting_to_move";
+ * String value = secureSettings.getSetting(name);
+ * secureSettings.deleteSetting(name);
+ *
+ * // Add to the global settings.
+ * SettingsState globalSettings = getGlobalSettingsLocked();
+ * globalSettings.insertSetting(name, value, SettingsState.SYSTEM_PACKAGE_NAME);
+ *
+ * // Update the current version.
+ * currentVersion = 119;
+ * }
+ *
+ * // Return the current version.
+ * return currentVersion;
+ */
+
+ return SettingsState.VERSION_UNDEFINED;
}
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
new file mode 100644
index 0000000..833638c
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -0,0 +1,575 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.settings;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+import libcore.io.IoUtils;
+import libcore.util.Objects;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+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.List;
+
+/**
+ * This class contains the state for one type of settings. It is responsible
+ * for saving the state asynchronously to an XML file after a mutation and
+ * loading the from an XML file on construction.
+ * <p>
+ * This class uses the same lock as the settings provider to ensure that
+ * multiple changes made by the settings provider, e,g, upgrade, bulk insert,
+ * etc, are atomically persisted since the asynchronous persistence is using
+ * the same lock to grab the current state to write to disk.
+ * </p>
+ */
+final class SettingsState {
+ private static final boolean DEBUG = false;
+ private static final boolean DEBUG_PERSISTENCE = false;
+
+ private static final String LOG_TAG = "SettingsState";
+
+ private static final long WRITE_SETTINGS_DELAY_MILLIS = 200;
+ private static final long MAX_WRITE_SETTINGS_DELAY_MILLIS = 2000;
+
+ public static final int MAX_BYTES_PER_APP_PACKAGE_UNLIMITED = -1;
+ public static final int MAX_BYTES_PER_APP_PACKAGE_LIMITED = 20000;
+
+ public static final String SYSTEM_PACKAGE_NAME = "android";
+
+ public static final int VERSION_UNDEFINED = -1;
+
+ private static final String TAG_SETTINGS = "settings";
+ private static final String TAG_SETTING = "setting";
+ private static final String ATTR_PACKAGE = "package";
+
+ private static final String ATTR_VERSION = "version";
+ private static final String ATTR_ID = "id";
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_VALUE = "value";
+
+ private static final String NULL_VALUE = "null";
+
+ private final Object mLock;
+
+ private final Handler mHandler = new MyHandler();
+
+ @GuardedBy("mLock")
+ private final ArrayMap<String, Setting> mSettings = new ArrayMap<>();
+
+ @GuardedBy("mLock")
+ private final ArrayMap<String, Integer> mPackageToMemoryUsage;
+
+ @GuardedBy("mLock")
+ private final int mMaxBytesPerAppPackage;
+
+ @GuardedBy("mLock")
+ private final File mStatePersistFile;
+
+ public final int mKey;
+
+ @GuardedBy("mLock")
+ private int mVersion = VERSION_UNDEFINED;
+
+ @GuardedBy("mLock")
+ private long mLastNotWrittenMutationTimeMillis;
+
+ @GuardedBy("mLock")
+ private boolean mDirty;
+
+ @GuardedBy("mLock")
+ private boolean mWriteScheduled;
+
+ public SettingsState(Object lock, File file, int key, int maxBytesPerAppPackage) {
+ // It is important that we use the same lock as the settings provider
+ // to ensure multiple mutations on this state are atomicaly persisted
+ // as the async persistence should be blocked while we make changes.
+ mLock = lock;
+ mStatePersistFile = file;
+ mKey = key;
+ if (maxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_LIMITED) {
+ mMaxBytesPerAppPackage = maxBytesPerAppPackage;
+ mPackageToMemoryUsage = new ArrayMap<>();
+ } else {
+ mMaxBytesPerAppPackage = maxBytesPerAppPackage;
+ mPackageToMemoryUsage = null;
+ }
+ synchronized (mLock) {
+ readStateSyncLocked();
+ }
+ }
+
+ // The settings provider must hold its lock when calling here.
+ public int getVersionLocked() {
+ return mVersion;
+ }
+
+ // The settings provider must hold its lock when calling here.
+ public void setVersionLocked(int version) {
+ if (version == mVersion) {
+ return;
+ }
+ mVersion = version;
+
+ scheduleWriteIfNeededLocked();
+ }
+
+ // The settings provider must hold its lock when calling here.
+ public void onPackageRemovedLocked(String packageName) {
+ boolean removedSomething = false;
+
+ final int settingCount = mSettings.size();
+ for (int i = settingCount - 1; i >= 0; i--) {
+ String name = mSettings.keyAt(i);
+ // Settings defined by use are never dropped.
+ if (Settings.System.PUBLIC_SETTINGS.contains(name)
+ || Settings.System.PRIVATE_SETTINGS.contains(name)) {
+ continue;
+ }
+ Setting setting = mSettings.valueAt(i);
+ if (packageName.equals(setting.packageName)) {
+ mSettings.removeAt(i);
+ removedSomething = true;
+ }
+ }
+
+ if (removedSomething) {
+ scheduleWriteIfNeededLocked();
+ }
+ }
+
+ // The settings provider must hold its lock when calling here.
+ public List<String> getSettingNamesLocked() {
+ ArrayList<String> names = new ArrayList<>();
+ final int settingsCount = mSettings.size();
+ for (int i = 0; i < settingsCount; i++) {
+ String name = mSettings.keyAt(i);
+ names.add(name);
+ }
+ return names;
+ }
+
+ // The settings provider must hold its lock when calling here.
+ public Setting getSettingLocked(String name) {
+ if (TextUtils.isEmpty(name)) {
+ return null;
+ }
+ return mSettings.get(name);
+ }
+
+ // The settings provider must hold its lock when calling here.
+ public boolean updateSettingLocked(String name, String value, String packageName) {
+ if (!hasSettingLocked(name)) {
+ return false;
+ }
+
+ return insertSettingLocked(name, value, packageName);
+ }
+
+ // The settings provider must hold its lock when calling here.
+ public boolean insertSettingLocked(String name, String value, String packageName) {
+ if (TextUtils.isEmpty(name)) {
+ return false;
+ }
+
+ Setting oldState = mSettings.get(name);
+ String oldValue = (oldState != null) ? oldState.value : null;
+
+ if (oldState != null) {
+ if (!oldState.update(value, packageName)) {
+ return false;
+ }
+ } else {
+ Setting state = new Setting(name, value, packageName);
+ mSettings.put(name, state);
+ }
+
+ updateMemoryUsagePerPackageLocked(packageName, oldValue, value);
+
+ scheduleWriteIfNeededLocked();
+
+ return true;
+ }
+
+ // The settings provider must hold its lock when calling here.
+ public void persistSyncLocked() {
+ mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS);
+ doWriteState();
+ }
+
+ // The settings provider must hold its lock when calling here.
+ public boolean deleteSettingLocked(String name) {
+ if (TextUtils.isEmpty(name) || !hasSettingLocked(name)) {
+ return false;
+ }
+
+ Setting oldState = mSettings.remove(name);
+
+ updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value, null);
+
+ scheduleWriteIfNeededLocked();
+
+ return true;
+ }
+
+ // The settings provider must hold its lock when calling here.
+ public void destroyLocked(Runnable callback) {
+ mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS);
+ if (callback != null) {
+ if (mDirty) {
+ // Do it without a delay.
+ mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS,
+ callback).sendToTarget();
+ return;
+ }
+ callback.run();
+ }
+ }
+
+ private void updateMemoryUsagePerPackageLocked(String packageName, String oldValue,
+ String newValue) {
+ if (mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED) {
+ return;
+ }
+
+ if (SYSTEM_PACKAGE_NAME.equals(packageName)) {
+ return;
+ }
+
+ final int oldValueSize = (oldValue != null) ? oldValue.length() : 0;
+ final int newValueSize = (newValue != null) ? newValue.length() : 0;
+ final int deltaSize = newValueSize - oldValueSize;
+
+ Integer currentSize = mPackageToMemoryUsage.get(packageName);
+ final int newSize = Math.max((currentSize != null)
+ ? currentSize + deltaSize : deltaSize, 0);
+
+ if (newSize > mMaxBytesPerAppPackage) {
+ throw new IllegalStateException("You are adding too many system settings. "
+ + "You should stop using system settings for app specific data"
+ + " package: " + packageName);
+ }
+
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Settings for package: " + packageName
+ + " size: " + newSize + " bytes.");
+ }
+
+ mPackageToMemoryUsage.put(packageName, newSize);
+ }
+
+ private boolean hasSettingLocked(String name) {
+ return mSettings.indexOfKey(name) >= 0;
+ }
+
+ private void scheduleWriteIfNeededLocked() {
+ // If dirty then we have a write already scheduled.
+ if (!mDirty) {
+ mDirty = true;
+ writeStateAsyncLocked();
+ }
+ }
+
+ private void writeStateAsyncLocked() {
+ final long currentTimeMillis = SystemClock.uptimeMillis();
+
+ if (mWriteScheduled) {
+ mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS);
+
+ // If enough time passed, write without holding off anymore.
+ final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis
+ - mLastNotWrittenMutationTimeMillis;
+ if (timeSinceLastNotWrittenMutationMillis >= MAX_WRITE_SETTINGS_DELAY_MILLIS) {
+ mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS).sendToTarget();
+ return;
+ }
+
+ // Hold off a bit more as settings are frequently changing.
+ final long maxDelayMillis = Math.max(mLastNotWrittenMutationTimeMillis
+ + MAX_WRITE_SETTINGS_DELAY_MILLIS - currentTimeMillis, 0);
+ final long writeDelayMillis = Math.min(WRITE_SETTINGS_DELAY_MILLIS, maxDelayMillis);
+
+ Message message = mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS);
+ mHandler.sendMessageDelayed(message, writeDelayMillis);
+ } else {
+ mLastNotWrittenMutationTimeMillis = currentTimeMillis;
+ Message message = mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS);
+ mHandler.sendMessageDelayed(message, WRITE_SETTINGS_DELAY_MILLIS);
+ mWriteScheduled = true;
+ }
+ }
+
+ private void doWriteState() {
+ if (DEBUG_PERSISTENCE) {
+ Slog.i(LOG_TAG, "[PERSIST START]");
+ }
+
+ AtomicFile destination = new AtomicFile(mStatePersistFile);
+
+ final int version;
+ final ArrayMap<String, Setting> settings;
+
+ synchronized (mLock) {
+ version = mVersion;
+ settings = new ArrayMap<>(mSettings);
+ mDirty = false;
+ mWriteScheduled = false;
+ }
+
+ FileOutputStream out = null;
+ try {
+ out = destination.startWrite();
+
+ XmlSerializer serializer = Xml.newSerializer();
+ serializer.setOutput(out, "utf-8");
+ serializer.startDocument(null, true);
+ serializer.startTag(null, TAG_SETTINGS);
+ serializer.attribute(null, ATTR_VERSION, String.valueOf(version));
+
+ final int settingCount = settings.size();
+ for (int i = 0; i < settingCount; i++) {
+ Setting setting = settings.valueAt(i);
+
+ serializer.startTag(null, TAG_SETTING);
+ serializer.attribute(null, ATTR_ID, setting.getId());
+ serializer.attribute(null, ATTR_NAME, setting.getName());
+ serializer.attribute(null, ATTR_VALUE, packValue(setting.getValue()));
+ serializer.attribute(null, ATTR_PACKAGE, packValue(setting.getPackageName()));
+ serializer.endTag(null, TAG_SETTING);
+
+ if (DEBUG_PERSISTENCE) {
+ Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "=" + setting.getValue());
+ }
+ }
+
+ serializer.endTag(null, TAG_SETTINGS);
+ serializer.endDocument();
+ destination.finishWrite(out);
+
+ if (DEBUG_PERSISTENCE) {
+ Slog.i(LOG_TAG, "[PERSIST END]");
+ }
+
+ } catch (IOException e) {
+ Slog.w(LOG_TAG, "Failed to write settings, restoring backup", e);
+ destination.failWrite(out);
+ } finally {
+ IoUtils.closeQuietly(out);
+ }
+ }
+
+ private void readStateSyncLocked() {
+ FileInputStream in;
+ if (!mStatePersistFile.exists()) {
+ return;
+ }
+ try {
+ in = new FileInputStream(mStatePersistFile);
+ } catch (FileNotFoundException fnfe) {
+ Slog.i(LOG_TAG, "No settings state");
+ return;
+ }
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ parseStateLocked(parser);
+ } catch (XmlPullParserException | IOException ise) {
+ throw new IllegalStateException("Failed parsing settings file: "
+ + mStatePersistFile , ise);
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+
+ private void parseStateLocked(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ parser.next();
+ skipEmptyTextTags(parser);
+ expect(parser, XmlPullParser.START_TAG, TAG_SETTINGS);
+
+ mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTR_VERSION));
+
+ parser.next();
+
+ while (parseSettingLocked(parser)) {
+ parser.next();
+ }
+
+ skipEmptyTextTags(parser);
+ expect(parser, XmlPullParser.END_TAG, TAG_SETTINGS);
+ }
+
+ private boolean parseSettingLocked(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ skipEmptyTextTags(parser);
+ if (!accept(parser, XmlPullParser.START_TAG, TAG_SETTING)) {
+ return false;
+ }
+
+ String id = parser.getAttributeValue(null, ATTR_ID);
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ String value = parser.getAttributeValue(null, ATTR_VALUE);
+ String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+ mSettings.put(name, new Setting(name, unpackValue(value),
+ unpackValue(packageName), id));
+
+ if (DEBUG_PERSISTENCE) {
+ Slog.i(LOG_TAG, "[RESTORED] " + name + "=" + value);
+ }
+
+ parser.next();
+
+ skipEmptyTextTags(parser);
+ expect(parser, XmlPullParser.END_TAG, TAG_SETTING);
+
+ return true;
+ }
+
+ private void expect(XmlPullParser parser, int type, String tag)
+ throws IOException, XmlPullParserException {
+ if (!accept(parser, type, tag)) {
+ throw new XmlPullParserException("Expected event: " + type
+ + " and tag: " + tag + " but got event: " + parser.getEventType()
+ + " and tag:" + parser.getName());
+ }
+ }
+
+ private void skipEmptyTextTags(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ while (accept(parser, XmlPullParser.TEXT, null)
+ && "\n".equals(parser.getText())) {
+ parser.next();
+ }
+ }
+
+ private boolean accept(XmlPullParser parser, int type, String tag)
+ throws IOException, XmlPullParserException {
+ if (parser.getEventType() != type) {
+ return false;
+ }
+ if (tag != null) {
+ if (!tag.equals(parser.getName())) {
+ return false;
+ }
+ } else if (parser.getName() != null) {
+ return false;
+ }
+ return true;
+ }
+
+ private final class MyHandler extends Handler {
+ public static final int MSG_PERSIST_SETTINGS = 1;
+
+ public MyHandler() {
+ super(BackgroundThread.getHandler().getLooper());
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_PERSIST_SETTINGS: {
+ Runnable callback = (Runnable) message.obj;
+ doWriteState();
+ if (callback != null) {
+ callback.run();
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ private static String packValue(String value) {
+ if (value == null) {
+ return NULL_VALUE;
+ }
+ return value;
+ }
+
+ private static String unpackValue(String value) {
+ if (NULL_VALUE.equals(value)) {
+ return null;
+ }
+ return value;
+ }
+
+ public static final class Setting {
+ private static long sNextId;
+
+ private String name;
+ private String value;
+ private String packageName;
+ private String id;
+
+ public Setting(String name, String value, String packageName) {
+ init(name, value, packageName, String.valueOf(sNextId++));
+ }
+
+ public Setting(String name, String value, String packageName, String id) {
+ sNextId = Math.max(sNextId, Long.valueOf(id));
+ init(name, value, packageName, String.valueOf(sNextId));
+ }
+
+ private void init(String name, String value, String packageName, String id) {
+ this.name = name;
+ this.value = value;
+ this.packageName = packageName;
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public boolean update(String value, String packageName) {
+ if (Objects.equal(value, this.value)) {
+ return false;
+ }
+ this.value = value;
+ this.packageName = packageName;
+ this.id = String.valueOf(sNextId++);
+ return true;
+ }
+ }
+}
diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk
new file mode 100644
index 0000000..01c6ccf
--- /dev/null
+++ b/packages/SettingsProvider/test/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SettingsProviderTest
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/packages/SettingsProvider/test/AndroidManifest.xml b/packages/SettingsProvider/test/AndroidManifest.xml
new file mode 100644
index 0000000..7a86b5f
--- /dev/null
+++ b/packages/SettingsProvider/test/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.providers.setting.test">
+
+ <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
+
+ <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+ <uses-permission android:name="android.permission.MANAGE_USERS"/>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.providers.setting.test"
+ android:label="Settings Provider Tests" />
+</manifest>
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
new file mode 100644
index 0000000..8473db4
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.settings;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+
+import java.util.List;
+
+/**
+ * Base class for the SettingContentProvider tests.
+ */
+abstract class BaseSettingsProviderTest extends AndroidTestCase {
+ protected static final int SETTING_TYPE_GLOBAL = 1;
+ protected static final int SETTING_TYPE_SECURE = 2;
+ protected static final int SETTING_TYPE_SYSTEM = 3;
+
+ protected static final String FAKE_SETTING_NAME = "fake_setting_name";
+ protected static final String FAKE_SETTING_NAME_1 = "fake_setting_name1";
+ protected static final String FAKE_SETTING_VALUE = "fake_setting_value";
+ protected static final String FAKE_SETTING_VALUE_1 = "fake_setting_value_1";
+
+ private static final String[] NAME_VALUE_COLUMNS = new String[] {
+ Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE
+ };
+
+ protected int mSecondaryUserId = UserHandle.USER_OWNER;
+
+ @Override
+ public void setContext(Context context) {
+ super.setContext(context);
+
+ UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ List<UserInfo> users = userManager.getUsers();
+ final int userCount = users.size();
+ for (int i = 0; i < userCount; i++) {
+ UserInfo user = users.get(i);
+ if (!user.isPrimary() && !user.isManagedProfile()) {
+ mSecondaryUserId = user.id;
+ break;
+ }
+ }
+ }
+
+ protected void setStringViaFrontEndApiSetting(int type, String name, String value, int userId) {
+ ContentResolver contentResolver = getContext().getContentResolver();
+
+ switch (type) {
+ case SETTING_TYPE_GLOBAL: {
+ Settings.Global.putStringForUser(contentResolver, name, value, userId);
+ } break;
+
+ case SETTING_TYPE_SECURE: {
+ Settings.Secure.putStringForUser(contentResolver, name, value, userId);
+ } break;
+
+ case SETTING_TYPE_SYSTEM: {
+ Settings.System.putStringForUser(contentResolver, name, value, userId);
+ } break;
+
+ default: {
+ throw new IllegalArgumentException("Invalid type: " + type);
+ }
+ }
+ }
+
+ protected String getStringViaFrontEndApiSetting(int type, String name, int userId) {
+ ContentResolver contentResolver = getContext().getContentResolver();
+
+ switch (type) {
+ case SETTING_TYPE_GLOBAL: {
+ return Settings.Global.getStringForUser(contentResolver, name, userId);
+ }
+
+ case SETTING_TYPE_SECURE: {
+ return Settings.Secure.getStringForUser(contentResolver, name, userId);
+ }
+
+ case SETTING_TYPE_SYSTEM: {
+ return Settings.System.getStringForUser(contentResolver, name, userId);
+ }
+
+ default: {
+ throw new IllegalArgumentException("Invalid type: " + type);
+ }
+ }
+ }
+
+ protected Uri insertStringViaProviderApi(int type, String name, String value,
+ boolean withTableRowUri) {
+ Uri uri = getBaseUriForType(type);
+ if (withTableRowUri) {
+ uri = Uri.withAppendedPath(uri, name);
+ }
+ ContentValues values = new ContentValues();
+ values.put(Settings.NameValueTable.NAME, name);
+ values.put(Settings.NameValueTable.VALUE, value);
+
+ return getContext().getContentResolver().insert(uri, values);
+ }
+
+ protected int deleteStringViaProviderApi(int type, String name) {
+ Uri uri = getBaseUriForType(type);
+ return getContext().getContentResolver().delete(uri, "name=?", new String[]{name});
+ }
+
+ protected int updateStringViaProviderApiSetting(int type, String name, String value) {
+ Uri uri = getBaseUriForType(type);
+ ContentValues values = new ContentValues();
+ values.put(Settings.NameValueTable.NAME, name);
+ values.put(Settings.NameValueTable.VALUE, value);
+ return getContext().getContentResolver().update(uri, values, "name=?",
+ new String[]{name});
+ }
+
+ protected String queryStringViaProviderApi(int type, String name) {
+ return queryStringViaProviderApi(type, name, false, false);
+ }
+
+ protected String queryStringViaProviderApi(int type, String name, boolean queryStringInQuotes,
+ boolean appendNameToUri) {
+ final Uri uri;
+ final String queryString;
+ final String[] queryArgs;
+
+ if (appendNameToUri) {
+ uri = Uri.withAppendedPath(getBaseUriForType(type), name);
+ queryString = null;
+ queryArgs = null;
+ } else {
+ uri = getBaseUriForType(type);
+ queryString = queryStringInQuotes ? "(name=?)" : "name=?";
+ queryArgs = new String[]{name};
+ }
+
+ Cursor cursor = getContext().getContentResolver().query(uri, NAME_VALUE_COLUMNS,
+ queryString, queryArgs, null);
+
+ if (cursor == null) {
+ return null;
+ }
+
+ try {
+ if (cursor.moveToFirst()) {
+ final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
+ return cursor.getString(valueColumnIdx);
+ }
+ } finally {
+ cursor.close();
+ }
+
+ return null;
+ }
+
+ protected static Uri getBaseUriForType(int type) {
+ switch (type) {
+ case SETTING_TYPE_GLOBAL: {
+ return Settings.Global.CONTENT_URI;
+ }
+
+ case SETTING_TYPE_SECURE: {
+ return Settings.Secure.CONTENT_URI;
+ }
+
+ case SETTING_TYPE_SYSTEM: {
+ return Settings.System.CONTENT_URI;
+ }
+
+ default: {
+ throw new IllegalArgumentException("Invalid type: " + type);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java
new file mode 100644
index 0000000..d581f3b
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.settings;
+
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Log;
+
+/**
+* Performance tests for the SettingContentProvider.
+*/
+public class SettingsProviderPerformanceTest extends BaseSettingsProviderTest {
+ private static final String LOG_TAG = "SettingsProviderPerformanceTest";
+
+ private static final int ITERATION_COUNT = 100;
+
+ private static final int MICRO_SECONDS_IN_MILLISECOND = 1000;
+
+ private static final long MAX_AVERAGE_SET_AND_GET_SETTING_DURATION_MILLIS = 20;
+
+ public void testSetAndGetPerformanceForGlobalViaFrontEndApi() throws Exception {
+ // Start with a clean slate.
+ insertStringViaProviderApi(SETTING_TYPE_GLOBAL,
+ FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
+
+ final long startTimeMicro = SystemClock.currentTimeMicro();
+
+ try {
+ for (int i = 0; i < ITERATION_COUNT; i++) {
+ // Set the setting to its first value.
+ updateStringViaProviderApiSetting(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME,
+ FAKE_SETTING_VALUE);
+
+ // Make sure the setting changed.
+ String firstValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
+ FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+ assertEquals("Setting value didn't change", FAKE_SETTING_VALUE, firstValue);
+
+ // Set the setting to its second value.
+ updateStringViaProviderApiSetting(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME,
+ FAKE_SETTING_VALUE_1);
+
+ // Make sure the setting changed.
+ String secondValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
+ FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+ assertEquals("Setting value didn't change", FAKE_SETTING_VALUE_1, secondValue);
+ }
+ } finally {
+ // Clean up.
+ deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
+ }
+
+ final long elapsedTimeMicro = SystemClock.currentTimeMicro() - startTimeMicro;
+
+ final long averageTimePerIterationMillis = (long) ((((float) elapsedTimeMicro)
+ / ITERATION_COUNT) / MICRO_SECONDS_IN_MILLISECOND);
+
+ Log.i(LOG_TAG, "Average time to set and get setting via provider APIs: "
+ + averageTimePerIterationMillis + " ms");
+
+ assertTrue("Setting and getting a settings takes too long.", averageTimePerIterationMillis
+ < MAX_AVERAGE_SET_AND_GET_SETTING_DURATION_MILLIS);
+ }
+
+ public void testSetAndGetPerformanceForGlobalViaProviderApi() throws Exception {
+ // Start with a clean slate.
+ deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
+
+ final long startTimeMicro = SystemClock.currentTimeMicro();
+
+ try {
+ for (int i = 0; i < ITERATION_COUNT; i++) {
+ // Set the setting to its first value.
+ setStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME,
+ FAKE_SETTING_VALUE, UserHandle.USER_OWNER);
+
+ // Make sure the setting changed.
+ String firstValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
+ FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+ assertEquals("Setting value didn't change", FAKE_SETTING_VALUE, firstValue);
+
+ // Set the setting to its second value.
+ setStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME,
+ FAKE_SETTING_VALUE_1, UserHandle.USER_OWNER);
+
+ // Make sure the setting changed.
+ String secondValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
+ FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+ assertEquals("Setting value didn't change", FAKE_SETTING_VALUE_1, secondValue);
+ }
+ } finally {
+ // Clean up.
+ deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
+ }
+
+ final long elapsedTimeMicro = SystemClock.currentTimeMicro() - startTimeMicro;
+
+ final long averageTimePerIterationMillis = (long) ((((float) elapsedTimeMicro)
+ / ITERATION_COUNT) / MICRO_SECONDS_IN_MILLISECOND);
+
+ Log.i(LOG_TAG, "Average time to set and get setting via front-eng APIs: "
+ + averageTimePerIterationMillis + " ms");
+
+ assertTrue("Setting and getting a settings takes too long.", averageTimePerIterationMillis
+ < MAX_AVERAGE_SET_AND_GET_SETTING_DURATION_MILLIS);
+ }
+}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
new file mode 100644
index 0000000..b89fb10
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.settings;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Tests for the SettingContentProvider.
+ *
+ * Before you run this test you must add a secondary user.
+ */
+public class SettingsProviderTest extends BaseSettingsProviderTest {
+ private static final String LOG_TAG = "SettingsProviderTest";
+
+ private static final long WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec
+
+ private static final String[] NAME_VALUE_COLUMNS = new String[]{
+ Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE
+ };
+
+ private final Object mLock = new Object();
+
+ public void testSetAndGetGlobalViaFrontEndApiForOwnerUser() throws Exception {
+ performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, UserHandle.USER_OWNER);
+ }
+
+ public void testSetAndGetGlobalViaFrontEndApiForNonOwnerUser() throws Exception {
+ if (mSecondaryUserId == UserHandle.USER_OWNER) {
+ Log.w(LOG_TAG, "No secondary user. Skipping "
+ + "testSetAndGetGlobalViaFrontEndApiForNonOwnerUser");
+ return;
+ }
+ performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, mSecondaryUserId);
+ }
+
+ public void testSetAndGetSecureViaFrontEndApiForOwnerUser() throws Exception {
+ performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, UserHandle.USER_OWNER);
+ }
+
+ public void testSetAndGetSecureViaFrontEndApiForNonOwnerUser() throws Exception {
+ if (mSecondaryUserId == UserHandle.USER_OWNER) {
+ Log.w(LOG_TAG, "No secondary user. Skipping "
+ + "testSetAndGetSecureViaFrontEndApiForNonOwnerUser");
+ return;
+ }
+ performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, mSecondaryUserId);
+ }
+
+ public void testSetAndGetSystemViaFrontEndApiForOwnerUser() throws Exception {
+ performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, UserHandle.USER_OWNER);
+ }
+
+ public void testSetAndGetSystemViaFrontEndApiForNonOwnerUser() throws Exception {
+ if (mSecondaryUserId == UserHandle.USER_OWNER) {
+ Log.w(LOG_TAG, "No secondary user. Skipping "
+ + "testSetAndGetSystemViaFrontEndApiForNonOwnerUser");
+ return;
+ }
+ performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, mSecondaryUserId);
+ }
+
+ public void testSetAndGetGlobalViaProviderApi() throws Exception {
+ performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_GLOBAL);
+ }
+
+ public void testSetAndGetSecureViaProviderApi() throws Exception {
+ performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SECURE);
+ }
+
+ public void testSetAndGetSystemViaProviderApi() throws Exception {
+ performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SYSTEM);
+ }
+
+ public void testSelectAllGlobalViaProviderApi() throws Exception {
+ setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_GLOBAL,
+ FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
+ try {
+ queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_GLOBAL,
+ FAKE_SETTING_NAME);
+ } finally {
+ deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
+ }
+ }
+
+ public void testSelectAllSecureViaProviderApi() throws Exception {
+ setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SECURE,
+ FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
+ try {
+ queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_SECURE,
+ FAKE_SETTING_NAME);
+ } finally {
+ deleteStringViaProviderApi(SETTING_TYPE_SECURE, FAKE_SETTING_NAME);
+ }
+ }
+
+ public void testSelectAllSystemViaProviderApi() throws Exception {
+ setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SYSTEM,
+ FAKE_SETTING_NAME, FAKE_SETTING_VALUE, true);
+ try {
+ queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_SYSTEM,
+ FAKE_SETTING_NAME);
+ } finally {
+ deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
+ }
+ }
+
+ public void testQueryUpdateDeleteGlobalViaProviderApi() throws Exception {
+ doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_GLOBAL);
+ }
+
+ public void testQueryUpdateDeleteSecureViaProviderApi() throws Exception {
+ doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SECURE);
+ }
+
+ public void testQueryUpdateDeleteSystemViaProviderApi() throws Exception {
+ doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SYSTEM);
+ }
+
+ public void testBulkInsertGlobalViaProviderApi() throws Exception {
+ toTestBulkInsertViaProviderApiForType(SETTING_TYPE_GLOBAL);
+ }
+
+ public void testBulkInsertSystemViaProviderApi() throws Exception {
+ toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SYSTEM);
+ }
+
+ public void testBulkInsertSecureViaProviderApi() throws Exception {
+ toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SECURE);
+ }
+
+ public void testAppCannotRunsSystemOutOfMemoryWritingSystemSettings() throws Exception {
+ int insertedCount = 0;
+ try {
+ for (; insertedCount < 1200; insertedCount++) {
+ Log.w(LOG_TAG, "Adding app specific setting: " + insertedCount);
+ insertStringViaProviderApi(SETTING_TYPE_SYSTEM,
+ String.valueOf(insertedCount), FAKE_SETTING_VALUE, false);
+ }
+ fail("Adding app specific settings must be bound.");
+ } catch (Exception e) {
+ for (; insertedCount >= 0; insertedCount--) {
+ Log.w(LOG_TAG, "Removing app specific setting: " + insertedCount);
+ deleteStringViaProviderApi(SETTING_TYPE_SYSTEM,
+ String.valueOf(insertedCount));
+ }
+ }
+ }
+
+ public void testQueryStringInBracketsGlobalViaProviderApiForType() throws Exception {
+ doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_GLOBAL);
+ }
+
+ public void testQueryStringInBracketsSecureViaProviderApiForType() throws Exception {
+ doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SECURE);
+ }
+
+ public void testQueryStringInBracketsSystemViaProviderApiForType() throws Exception {
+ doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SYSTEM);
+ }
+
+ public void testQueryStringWithAppendedNameToUriViaProviderApi() throws Exception {
+ // Make sure we have a clean slate.
+ deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
+
+ try {
+ // Insert the setting.
+ final Uri uri = insertStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME,
+ FAKE_SETTING_VALUE, false);
+ Uri expectUri = Uri.withAppendedPath(getBaseUriForType(SETTING_TYPE_SYSTEM),
+ FAKE_SETTING_NAME);
+ assertEquals("Did not get expected Uri.", expectUri, uri);
+
+ // Make sure the first setting is there.
+ String firstValue = queryStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME,
+ false, true);
+ assertEquals("Setting must be present", FAKE_SETTING_VALUE, firstValue);
+ } finally {
+ // Clean up.
+ deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
+ }
+ }
+
+ private void doTestQueryStringInBracketsViaProviderApiForType(int type) {
+ // Make sure we have a clean slate.
+ deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+
+ try {
+ // Insert the setting.
+ final Uri uri = insertStringViaProviderApi(type, FAKE_SETTING_NAME,
+ FAKE_SETTING_VALUE, false);
+ Uri expectUri = Uri.withAppendedPath(getBaseUriForType(type), FAKE_SETTING_NAME);
+ assertEquals("Did not get expected Uri.", expectUri, uri);
+
+ // Make sure the first setting is there.
+ String firstValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME, true, false);
+ assertEquals("Setting must be present", FAKE_SETTING_VALUE, firstValue);
+ } finally {
+ // Clean up.
+ deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+ }
+ }
+
+ private void toTestBulkInsertViaProviderApiForType(int type) {
+ // Make sure we have a clean slate.
+ deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+ deleteStringViaProviderApi(type, FAKE_SETTING_NAME_1);
+
+ try {
+ Uri uri = getBaseUriForType(type);
+ ContentValues[] allValues = new ContentValues[2];
+
+ // Insert the first setting.
+ ContentValues firstValues = new ContentValues();
+ firstValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME);
+ firstValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE);
+ allValues[0] = firstValues;
+
+ // Insert the first setting.
+ ContentValues secondValues = new ContentValues();
+ secondValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME_1);
+ secondValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE_1);
+ allValues[1] = secondValues;
+
+ // Verify insertion count.
+ final int insertCount = getContext().getContentResolver().bulkInsert(uri, allValues);
+ assertSame("Couldn't insert both values", 2, insertCount);
+
+ // Make sure the first setting is there.
+ String firstValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+ assertEquals("First setting must be present", FAKE_SETTING_VALUE, firstValue);
+
+ // Make sure the second setting is there.
+ String secondValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME_1);
+ assertEquals("Second setting must be present", FAKE_SETTING_VALUE_1, secondValue);
+ } finally {
+ // Clean up.
+ deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+ deleteStringViaProviderApi(type, FAKE_SETTING_NAME_1);
+ }
+ }
+
+ private void doTestQueryUpdateDeleteGlobalViaProviderApiForType(int type) throws Exception {
+ // Make sure it is not there.
+ deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+
+ // Now selection should return nothing.
+ String value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+ assertNull("Setting should not be present.", value);
+
+ // Insert the setting.
+ Uri uri = insertStringViaProviderApi(type,
+ FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
+ Uri expectUri = Uri.withAppendedPath(getBaseUriForType(type), FAKE_SETTING_NAME);
+ assertEquals("Did not get expected Uri.", expectUri, uri);
+
+ // Now selection should return the setting.
+ value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+ assertEquals("Setting should be present.", FAKE_SETTING_VALUE, value);
+
+ // Update the setting.
+ final int changeCount = updateStringViaProviderApiSetting(type,
+ FAKE_SETTING_NAME, FAKE_SETTING_VALUE_1);
+ assertEquals("Did not get expected change count.", 1, changeCount);
+
+ // Now selection should return the new setting.
+ value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+ assertEquals("Setting should be present.", FAKE_SETTING_VALUE_1, value);
+
+ // Delete the setting.
+ final int deletedCount = deleteStringViaProviderApi(type,
+ FAKE_SETTING_NAME);
+ assertEquals("Did not get expected deleted count", 1, deletedCount);
+
+ // Now selection should return nothing.
+ value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+ assertNull("Setting should not be present.", value);
+ }
+
+ private void performSetAndGetSettingTestViaFrontEndApi(int type, int userId)
+ throws Exception {
+ try {
+ // Change the setting and assert a successful change.
+ setSettingViaFrontEndApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME,
+ FAKE_SETTING_VALUE, userId);
+ } finally {
+ // Remove the setting.
+ setStringViaFrontEndApiSetting(type, FAKE_SETTING_NAME, null, userId);
+ }
+ }
+
+ private void performSetAndGetSettingTestViaProviderApi(int type)
+ throws Exception {
+ try {
+ // Change the setting and assert a successful change.
+ setSettingViaProviderApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME,
+ FAKE_SETTING_VALUE, true);
+ } finally {
+ // Remove the setting.
+ setSettingViaProviderApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME, null,
+ true);
+ }
+ }
+
+ private void setSettingViaFrontEndApiAndAssertSuccessfulChange(final int type,
+ final String name, final String value, final int userId) throws Exception {
+ setSettingAndAssertSuccessfulChange(new Runnable() {
+ @Override
+ public void run() {
+ setStringViaFrontEndApiSetting(type, name, value, userId);
+ }
+ }, type, name, value, userId);
+ }
+
+ private void setSettingViaProviderApiAndAssertSuccessfulChange(final int type,
+ final String name, final String value, final boolean withTableRowUri)
+ throws Exception {
+ setSettingAndAssertSuccessfulChange(new Runnable() {
+ @Override
+ public void run() {
+ insertStringViaProviderApi(type, name, value, withTableRowUri);
+ }
+ }, type, name, value, UserHandle.USER_OWNER);
+ }
+
+ private void setSettingAndAssertSuccessfulChange(Runnable setCommand, final int type,
+ final String name, final String value, final int userId) throws Exception {
+ ContentResolver contentResolver = getContext().getContentResolver();
+
+ final Uri settingUri = getBaseUriForType(type);
+
+ final AtomicBoolean success = new AtomicBoolean();
+
+ ContentObserver contentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
+ public void onChange(boolean selfChange, Uri changeUri, int changeId) {
+ Log.i(LOG_TAG, "onChange(" + selfChange + ", " + changeUri + ", " + changeId + ")");
+ assertEquals("Wrong change Uri", changeUri, settingUri);
+ assertEquals("Wrong user id", userId, changeId);
+ String changeValue = getStringViaFrontEndApiSetting(type, name, userId);
+ assertEquals("Wrong setting value", value, changeValue);
+
+ success.set(true);
+
+ synchronized (mLock) {
+ mLock.notifyAll();
+ }
+ }
+ };
+
+ contentResolver.registerContentObserver(settingUri, false, contentObserver, userId);
+
+ try {
+ setCommand.run();
+
+ final long startTimeMillis = SystemClock.uptimeMillis();
+ synchronized (mLock) {
+ if (success.get()) {
+ return;
+ }
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ if (elapsedTimeMillis > WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) {
+ fail("Could not change setting for "
+ + WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms");
+ }
+ final long remainingTimeMillis = WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS
+ - elapsedTimeMillis;
+ try {
+ mLock.wait(remainingTimeMillis);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ } finally {
+ contentResolver.unregisterContentObserver(contentObserver);
+ }
+ }
+
+ private void queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(int type,
+ String name) {
+ Uri uri = getBaseUriForType(type);
+
+ Cursor cursor = getContext().getContentResolver().query(uri, NAME_VALUE_COLUMNS,
+ null, null, null);
+
+ if (cursor == null || !cursor.moveToFirst()) {
+ fail("Nothing selected");
+ }
+
+ try {
+ final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
+
+ while (cursor.moveToNext()) {
+ String currentName = cursor.getString(nameColumnIdx);
+ if (name.equals(currentName)) {
+ return;
+ }
+ }
+
+ fail("Not found setting: " + name);
+ } finally {
+ cursor.close();
+ }
+ }
+}
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 6d3f976..532e1b7 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -22,9 +22,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:focusable="true"
- android:fitsSystemWindows="true"
- android:descendantFocusability="afterDescendants">
+ android:fitsSystemWindows="true">
<com.android.systemui.statusbar.BackDropView
android:id="@+id/backdrop"
@@ -45,7 +43,8 @@
<com.android.systemui.statusbar.ScrimView android:id="@+id/scrim_behind"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ android:importantForAccessibility="no" />
<include layout="@layout/status_bar"
android:layout_width="match_parent"
@@ -82,6 +81,7 @@
<com.android.systemui.statusbar.ScrimView android:id="@+id/scrim_in_front"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ android:importantForAccessibility="no" />
</com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
index c6b76f1..74391eb 100644
--- a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
+++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
@@ -72,16 +72,22 @@
@Override
public String resolvePacFile(String host, String url) throws RemoteException {
try {
+ if (host == null) {
+ throw new IllegalArgumentException("The host must not be null");
+ }
+ if (url == null) {
+ throw new IllegalArgumentException("The URL must not be null");
+ }
// Check for characters that could be used for an injection attack.
new URL(url);
for (char c : host.toCharArray()) {
if (!Character.isLetterOrDigit(c) && (c != '.') && (c != '-')) {
- throw new RemoteException("Invalid host was passed");
+ throw new IllegalArgumentException("Invalid host was passed");
}
}
return mPacNative.makeProxyRequest(url, host);
} catch (MalformedURLException e) {
- throw new RemoteException("Invalid URL was passed");
+ throw new IllegalArgumentException("Invalid URL was passed");
}
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index c1e4994..4d7ebed 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1865,7 +1865,8 @@
boolean tryBindTransport(ServiceInfo info) {
try {
PackageInfo packInfo = mPackageManager.getPackageInfo(info.packageName, 0);
- if ((packInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+ if ((packInfo.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+ != 0) {
return bindTransport(info);
} else {
Slog.w(TAG, "Transport package " + info.packageName + " not privileged");
@@ -3196,7 +3197,7 @@
final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
final boolean sendApk = mIncludeApks
&& !isSharedStorage
- && ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
+ && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0)
&& ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
(app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 42a5195..17b4939 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -813,7 +813,8 @@
.getApplicationInfo(packageName, 0, UserHandle.getUserId(uid));
if (appInfo != null) {
pkgUid = appInfo.uid;
- isPrivileged = (appInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+ isPrivileged = (appInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
} else {
if ("media".equals(packageName)) {
pkgUid = Process.MEDIA_UID;
@@ -996,7 +997,8 @@
ApplicationInfo appInfo = ActivityThread.getPackageManager()
.getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
if (appInfo != null) {
- isPrivileged = (appInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+ isPrivileged = (appInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
} else {
// Could not load data, don't add to cache so it will be loaded later.
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 551a5dc..b72b29d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2636,9 +2636,15 @@
// 100 percent is full good, 0 is full bad.
public void reportInetCondition(int networkType, int percentage) {
- if (percentage > 50) return; // don't handle good network reports
NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
- if (nai != null) reportBadNetwork(nai.network);
+ if (nai == null) return;
+ boolean isGood = percentage > 50;
+ // Revalidate if the app report does not match our current validated state.
+ if (isGood != nai.lastValidated) {
+ // Make the message logged by reportBadNetwork below less confusing.
+ if (DBG && isGood) log("reportInetCondition: type=" + networkType + " ok, revalidate");
+ reportBadNetwork(nai.network);
+ }
}
public void reportBadNetwork(Network network) {
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 1405fc1..1e3b46b 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -892,11 +892,6 @@
// Temporary workaround for http://b/17945169.
Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
-
- // TODO: Stop setting these properties once we've removed all
- // references to them.
- SystemProperties.set("persist.sys.language", locale.getLanguage());
- SystemProperties.set("persist.sys.country", locale.getCountry());
}
/**
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index d1b4569..aeacd45 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -31,6 +31,7 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.os.BatteryManager;
import android.os.Binder;
import android.os.Handler;
@@ -63,7 +64,7 @@
private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
- int mNightMode = UiModeManager.MODE_NIGHT_NO;
+ private int mNightMode = UiModeManager.MODE_NIGHT_NO;
private boolean mCarModeEnabled = false;
private boolean mCharging = false;
@@ -157,6 +158,7 @@
public void onStart() {
final Context context = getContext();
mTwilightManager = getLocalService(TwilightManager.class);
+
final PowerManager powerManager =
(PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
@@ -168,20 +170,23 @@
mConfiguration.setToDefaults();
- mDefaultUiModeType = context.getResources().getInteger(
+ final Resources res = context.getResources();
+ mDefaultUiModeType = res.getInteger(
com.android.internal.R.integer.config_defaultUiModeType);
- mCarModeKeepsScreenOn = (context.getResources().getInteger(
+ mCarModeKeepsScreenOn = (res.getInteger(
com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1);
- mDeskModeKeepsScreenOn = (context.getResources().getInteger(
+ mDeskModeKeepsScreenOn = (res.getInteger(
com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1);
- mTelevision = context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_TELEVISION) ||
- context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_LEANBACK);
- mWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+ final PackageManager pm = context.getPackageManager();
+ mTelevision = pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+ || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ mWatch = pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+
+ final int defaultNightMode = res.getInteger(
+ com.android.internal.R.integer.config_defaultNightMode);
mNightMode = Settings.Secure.getInt(context.getContentResolver(),
- Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO);
+ Settings.Secure.UI_NIGHT_MODE, defaultNightMode);
mTwilightManager.registerListener(mTwilightListener, mHandler);
@@ -245,7 +250,7 @@
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- if (isDoingNightModeLocked() && mNightMode != mode) {
+ if (mNightMode != mode) {
Settings.Secure.putInt(getContext().getContentResolver(),
Settings.Secure.UI_NIGHT_MODE, mode);
mNightMode = mode;
@@ -309,10 +314,6 @@
}
}
- boolean isDoingNightModeLocked() {
- return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
- }
-
void setCarModeLocked(boolean enabled, int flags) {
if (mCarModeEnabled != enabled) {
mCarModeEnabled = enabled;
@@ -354,17 +355,13 @@
} else if (isDeskDockState(mDockState)) {
uiMode = Configuration.UI_MODE_TYPE_DESK;
}
- if (mCarModeEnabled) {
- if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
- updateComputedNightModeLocked();
- uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
- : Configuration.UI_MODE_NIGHT_NO;
- } else {
- uiMode |= mNightMode << 4;
- }
+
+ if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+ updateComputedNightModeLocked();
+ uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
+ : Configuration.UI_MODE_NIGHT_NO;
} else {
- // Disabling the car mode clears the night mode.
- uiMode = (uiMode & ~Configuration.UI_MODE_NIGHT_MASK) | Configuration.UI_MODE_NIGHT_NO;
+ uiMode |= mNightMode << 4;
}
if (LOG) {
@@ -618,7 +615,7 @@
void updateTwilight() {
synchronized (mLock) {
- if (isDoingNightModeLocked() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+ if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
updateComputedNightModeLocked();
updateLocked(0, 0);
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index e52b2bf..9339b35 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3083,7 +3083,8 @@
try {
PackageInfo packageInfo = userPackageManager.getPackageInfo(name, 0 /* flags */);
if (packageInfo != null
- && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+ && (packageInfo.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
return true;
}
} catch (PackageManager.NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1eec141..a437761 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7882,7 +7882,11 @@
Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
return;
}
- task.mResizeable = resizeable;
+ if (task.mResizeable != resizeable) {
+ task.mResizeable = resizeable;
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
+ mStackSupervisor.resumeTopActivitiesLocked();
+ }
}
}
@@ -16398,15 +16402,6 @@
if (isPersist) {
SystemProperties.set("persist.sys.locale", languageTag);
-
- // These values are *deprecated*, use persist.sys.locale instead.
- //
- // TODO: Stop setting these values once all code that references
- // them has been removed.
- SystemProperties.set("persist.sys.language", l.getLanguage());
- SystemProperties.set("persist.sys.country", l.getCountry());
- SystemProperties.set("persist.sys.localevar", l.getVariant());
-
mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG, l));
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 58104a8..1aa2a10 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -882,7 +882,8 @@
final long origId = Binder.clearCallingIdentity();
if (aInfo != null &&
- (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+ (aInfo.applicationInfo.privateFlags
+ &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
// This may be a heavy-weight process! Check to see if we already
// have another, different heavy-weight process running.
if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
@@ -1053,8 +1054,8 @@
aInfo = mService.getActivityInfoForUser(aInfo, userId);
if (aInfo != null &&
- (aInfo.applicationInfo.flags & ApplicationInfo.FLAG_CANT_SAVE_STATE)
- != 0) {
+ (aInfo.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
throw new IllegalArgumentException(
"FLAG_CANT_SAVE_STATE not supported here");
}
@@ -1185,7 +1186,7 @@
r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
- if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+ if ((app.info.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
// This may be a heavy-weight process! Note that the package
// manager will ensure that only activity can run in the main
// process of the .apk, which is the only thing that will be
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 6e61e41..4e075c3 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -37,7 +37,6 @@
import android.opengl.EGLSurface;
import android.opengl.GLES20;
import android.opengl.GLES11Ext;
-import android.util.FloatMath;
import android.util.Slog;
import android.view.DisplayInfo;
import android.view.Surface.OutOfResourcesException;
@@ -372,13 +371,13 @@
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// Draw the frame.
- float one_minus_level = 1 - level;
- float cos = FloatMath.cos((float)Math.PI * one_minus_level);
- float sign = cos < 0 ? -1 : 1;
- float opacity = -FloatMath.pow(one_minus_level, 2) + 1;
- float saturation = FloatMath.pow(level, 4);
- float scale = (-FloatMath.pow(one_minus_level, 2) + 1) * 0.1f + 0.9f;
- float gamma = (0.5f * sign * FloatMath.pow(cos, 2) + 0.5f) * 0.9f + 0.1f;
+ double one_minus_level = 1 - level;
+ double cos = Math.cos(Math.PI * one_minus_level);
+ double sign = cos < 0 ? -1 : 1;
+ float opacity = (float) -Math.pow(one_minus_level, 2) + 1;
+ float saturation = (float) Math.pow(level, 4);
+ float scale = (float) ((-Math.pow(one_minus_level, 2) + 1) * 0.1d + 0.9d);
+ float gamma = (float) ((0.5d * sign * Math.pow(cos, 2) + 0.5d) * 0.9d + 0.1d);
drawFaded(opacity, 1.f / gamma, saturation, scale);
if (checkGlErrors("drawFrame")) {
return false;
diff --git a/services/core/java/com/android/server/firewall/SenderFilter.java b/services/core/java/com/android/server/firewall/SenderFilter.java
index c0eee69..0074119 100644
--- a/services/core/java/com/android/server/firewall/SenderFilter.java
+++ b/services/core/java/com/android/server/firewall/SenderFilter.java
@@ -45,7 +45,8 @@
IPackageManager pm = AppGlobals.getPackageManager();
try {
- return (pm.getFlagsForUid(callerUid) & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+ return (pm.getPrivateFlagsForUid(callerUid) & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+ != 0;
} catch (RemoteException ex) {
Slog.e(IntentFirewall.TAG, "Remote exception while retrieving uid flags",
ex);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 4f6b8f2..1a0f81d 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -742,6 +742,10 @@
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
+ if (DEBUG) {
+ Log.d(TAG, "dispatchMediaKeyEvent, pid=" + pid + ", uid=" + uid + ", event="
+ + keyEvent);
+ }
try {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index e9b3f8b..bfdc400 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -98,6 +98,11 @@
@Override
public void onSwitchUser(int userId) {
mMediaRouter.rebindAsUser(userId);
+ synchronized (mLock) {
+ if (mProjectionGrant != null) {
+ mProjectionGrant.stop();
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 02cacd9..f49d77d 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -931,6 +931,7 @@
mDisableNotificationEffects = true;
}
mZenModeHelper.readZenModeFromSetting();
+ mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
mUserProfiles.updateCache(getContext());
listenForCallState();
@@ -1671,6 +1672,7 @@
if (filter == null || zenOnly) {
pw.println("\n Zen Mode:");
+ pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
mZenModeHelper.dump(pw, " ");
pw.println("\n Zen Log:");
diff --git a/services/core/java/com/android/server/pm/GrantedPermissions.java b/services/core/java/com/android/server/pm/GrantedPermissions.java
index 8f0f935..e87546c 100644
--- a/services/core/java/com/android/server/pm/GrantedPermissions.java
+++ b/services/core/java/com/android/server/pm/GrantedPermissions.java
@@ -21,13 +21,15 @@
class GrantedPermissions {
int pkgFlags;
+ int pkgPrivateFlags;
ArraySet<String> grantedPermissions = new ArraySet<String>();
int[] gids;
- GrantedPermissions(int pkgFlags) {
+ GrantedPermissions(int pkgFlags, int pkgPrivateFlags) {
setFlags(pkgFlags);
+ setPrivateFlags(pkgPrivateFlags);
}
@SuppressWarnings("unchecked")
@@ -43,8 +45,12 @@
void setFlags(int pkgFlags) {
this.pkgFlags = pkgFlags
& (ApplicationInfo.FLAG_SYSTEM
- | ApplicationInfo.FLAG_PRIVILEGED
- | ApplicationInfo.FLAG_FORWARD_LOCK
| ApplicationInfo.FLAG_EXTERNAL_STORAGE);
}
+
+ void setPrivateFlags(int pkgPrivateFlags) {
+ this.pkgPrivateFlags = pkgPrivateFlags
+ & (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
+ | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK);
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 12c4315..c3f1418 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1299,17 +1299,17 @@
mMetrics = new DisplayMetrics();
mSettings = new Settings(context);
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
- ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+ ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
- ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+ ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
- ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+ ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
- ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+ ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
- ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+ ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
- ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+ ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
// TODO: add a property to control this?
long dexOptLRUThresholdInMinutes;
@@ -2124,6 +2124,7 @@
pkg = new PackageParser.Package(packageName);
pkg.applicationInfo.packageName = packageName;
pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
+ pkg.applicationInfo.privateFlags = ps.pkgPrivateFlags;
pkg.applicationInfo.dataDir =
getDataPathForPackage(packageName, 0).getPath();
pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
@@ -2966,7 +2967,7 @@
}
// reader
synchronized (mPackages) {
- final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, false);
+ final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, 0, false);
if (suid == null) {
return -1;
}
@@ -2990,6 +2991,21 @@
}
@Override
+ public int getPrivateFlagsForUid(int uid) {
+ synchronized (mPackages) {
+ Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
+ if (obj instanceof SharedUserSetting) {
+ final SharedUserSetting sus = (SharedUserSetting) obj;
+ return sus.pkgPrivateFlags;
+ } else if (obj instanceof PackageSetting) {
+ final PackageSetting ps = (PackageSetting) obj;
+ return ps.pkgPrivateFlags;
+ }
+ }
+ return 0;
+ }
+
+ @Override
public boolean isUidPrivileged(int uid) {
uid = UserHandle.getAppId(uid);
// reader
@@ -4309,9 +4325,9 @@
// If new package is not located in "/system/priv-app" (e.g. due to an OTA),
// it needs to drop FLAG_PRIVILEGED.
if (locationIsPrivileged(scanFile)) {
- updatedPkg.pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
+ updatedPkg.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
} else {
- updatedPkg.pkgFlags &= ~ApplicationInfo.FLAG_PRIVILEGED;
+ updatedPkg.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
if (ps != null && !ps.codePath.equals(scanFile)) {
@@ -4375,7 +4391,7 @@
// An updated privileged app will not have the PARSE_IS_PRIVILEGED
// flag set initially
- if ((updatedPkg.pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+ if ((updatedPkg.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
}
}
@@ -5315,7 +5331,7 @@
}
if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
- pkg.applicationInfo.flags |= ApplicationInfo.FLAG_PRIVILEGED;
+ pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
if (mCustomResolverComponentName != null &&
@@ -5389,7 +5405,7 @@
// writer
synchronized (mPackages) {
if (pkg.mSharedUserId != null) {
- suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, true);
+ suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, true);
if (suid == null) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Creating application package " + pkg.packageName
@@ -5463,7 +5479,8 @@
destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
pkg.applicationInfo.primaryCpuAbi,
pkg.applicationInfo.secondaryCpuAbi,
- pkg.applicationInfo.flags, user, false);
+ pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
+ user, false);
if (pkgSetting == null) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Creating application package " + pkg.packageName + " failed");
@@ -10358,7 +10375,8 @@
boolean disabledSystem = false;
boolean updatedSettings = false;
parseFlags |= PackageParser.PARSE_IS_SYSTEM;
- if ((deletedPackage.applicationInfo.flags&ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+ if ((deletedPackage.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+ != 0) {
parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
}
String packageName = deletedPackage.packageName;
@@ -10716,15 +10734,15 @@
}
private static boolean isForwardLocked(PackageParser.Package pkg) {
- return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;
+ return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
}
private static boolean isForwardLocked(ApplicationInfo info) {
- return (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;
+ return (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
}
private boolean isForwardLocked(PackageSetting ps) {
- return (ps.pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;
+ return (ps.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
}
private static boolean isMultiArch(PackageSetting ps) {
@@ -10752,7 +10770,7 @@
}
private static boolean isPrivilegedApp(PackageParser.Package pkg) {
- return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+ return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
private static boolean isSystemApp(ApplicationInfo info) {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 696aa34..8ea0bee 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -32,10 +32,10 @@
PackageSetting(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
- int pVersionCode, int pkgFlags) {
+ int pVersionCode, int pkgFlags, int privateFlags) {
super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
- pVersionCode, pkgFlags);
+ pVersionCode, pkgFlags, privateFlags);
}
/**
@@ -62,6 +62,6 @@
}
public boolean isPrivileged() {
- return (pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+ return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 1dcadb4..4b8ca42 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -112,8 +112,8 @@
PackageSettingBase(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
- int pVersionCode, int pkgFlags) {
- super(pkgFlags);
+ int pVersionCode, int pkgFlags, int pkgPrivateFlags) {
+ super(pkgFlags, pkgPrivateFlags);
this.name = name;
this.realName = realName;
init(codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString,
diff --git a/services/core/java/com/android/server/pm/PendingPackage.java b/services/core/java/com/android/server/pm/PendingPackage.java
index 5d30e76..bb0dba1 100644
--- a/services/core/java/com/android/server/pm/PendingPackage.java
+++ b/services/core/java/com/android/server/pm/PendingPackage.java
@@ -24,10 +24,10 @@
PendingPackage(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString, int sharedId,
- int pVersionCode, int pkgFlags) {
+ int pVersionCode, int pkgFlags, int pkgPrivateFlags) {
super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
- pVersionCode, pkgFlags);
+ pVersionCode, pkgFlags, pkgPrivateFlags);
this.sharedId = sharedId;
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 524f638..d353494 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -281,11 +281,11 @@
PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbi, String secondaryCpuAbi,
- int pkgFlags, UserHandle user, boolean add) {
+ int pkgFlags, int pkgPrivateFlags, UserHandle user, boolean add) {
final String name = pkg.packageName;
PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,
resourcePath, legacyNativeLibraryPathString, primaryCpuAbi, secondaryCpuAbi,
- pkg.mVersionCode, pkgFlags, user, add, true /* allowInstall */);
+ pkg.mVersionCode, pkgFlags, pkgPrivateFlags, user, add, true /* allowInstall */);
return p;
}
@@ -311,13 +311,13 @@
}
SharedUserSetting getSharedUserLPw(String name,
- int pkgFlags, boolean create) {
+ int pkgFlags, int pkgPrivateFlags, boolean create) {
SharedUserSetting s = mSharedUsers.get(name);
if (s == null) {
if (!create) {
return null;
}
- s = new SharedUserSetting(name, pkgFlags);
+ s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
s.userId = newUserIdLPw(s);
Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);
// < 0 means we couldn't assign a userid; fall out and return
@@ -373,7 +373,7 @@
PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
p.legacyNativeLibraryPathString, p.primaryCpuAbiString,
p.secondaryCpuAbiString, p.secondaryCpuAbiString,
- p.appId, p.versionCode, p.pkgFlags);
+ p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags);
mDisabledSysPackages.remove(name);
return ret;
}
@@ -388,7 +388,7 @@
PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
- String cpuAbiOverrideString, int uid, int vc, int pkgFlags) {
+ String cpuAbiOverrideString, int uid, int vc, int pkgFlags, int pkgPrivateFlags) {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (p.appId == uid) {
@@ -400,7 +400,7 @@
}
p = new PackageSetting(name, realName, codePath, resourcePath,
legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
- cpuAbiOverrideString, vc, pkgFlags);
+ cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags);
p.appId = uid;
if (addUserIdLPw(uid, p, name)) {
mPackages.put(name, p);
@@ -409,7 +409,7 @@
return null;
}
- SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {
+ SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
SharedUserSetting s = mSharedUsers.get(name);
if (s != null) {
if (s.userId == uid) {
@@ -419,7 +419,7 @@
"Adding duplicate shared user, keeping first: " + name);
return null;
}
- s = new SharedUserSetting(name, pkgFlags);
+ s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
s.userId = uid;
if (addUserIdLPw(uid, s, name)) {
mSharedUsers.put(name, s);
@@ -469,7 +469,7 @@
private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
- int vc, int pkgFlags, UserHandle installUser, boolean add,
+ int vc, int pkgFlags, int pkgPrivateFlags, UserHandle installUser, boolean add,
boolean allowInstall) {
PackageSetting p = mPackages.get(name);
UserManagerService userManager = UserManagerService.getInstance();
@@ -511,9 +511,8 @@
// If what we are scanning is a system (and possibly privileged) package,
// then make it so, regardless of whether it was previously installed only
// in the data partition.
- final int sysPrivFlags = pkgFlags
- & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PRIVILEGED);
- p.pkgFlags |= sysPrivFlags;
+ p.pkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM;
+ p.pkgPrivateFlags |= pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
}
if (p == null) {
@@ -521,7 +520,7 @@
// We are consuming the data from an existing package.
p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
- null /* cpuAbiOverrideString */, vc, pkgFlags);
+ null /* cpuAbiOverrideString */, vc, pkgFlags, pkgPrivateFlags);
if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
+ name + " is adopting original package " + origPackage.name);
// Note that we will retain the new package's signature so
@@ -539,7 +538,7 @@
} else {
p = new PackageSetting(name, realName, codePath, resourcePath,
legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
- null /* cpuAbiOverrideString */, vc, pkgFlags);
+ null /* cpuAbiOverrideString */, vc, pkgFlags, pkgPrivateFlags);
p.setTimeStamp(codePath.lastModified());
p.sharedUser = sharedUser;
// If this is not a system app, it starts out stopped.
@@ -1818,7 +1817,8 @@
serializer.attribute(null, "cpuAbiOverride", pkg.cpuAbiOverrideString);
}
- serializer.attribute(null, "flags", Integer.toString(pkg.pkgFlags));
+ serializer.attribute(null, "publicFlags", Integer.toString(pkg.pkgFlags));
+ serializer.attribute(null, "privateFlags", Integer.toString(pkg.pkgPrivateFlags));
serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
@@ -2127,8 +2127,8 @@
PackageSetting p = getPackageLPw(pp.name, null, pp.realName,
(SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
pp.legacyNativeLibraryPathString, pp.primaryCpuAbiString,
- pp.secondaryCpuAbiString, pp.versionCode, pp.pkgFlags, null,
- true /* add */, false /* allowInstall */);
+ pp.secondaryCpuAbiString, pp.versionCode, pp.pkgFlags, pp.pkgPrivateFlags,
+ null, true /* add */, false /* allowInstall */);
if (p == null) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Unable to create application package for " + pp.name);
@@ -2596,14 +2596,15 @@
}
int pkgFlags = 0;
+ int pkgPrivateFlags = 0;
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
final File codePathFile = new File(codePathStr);
if (PackageManagerService.locationIsPrivileged(codePathFile)) {
- pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
PackageSetting ps = new PackageSetting(name, realName, codePathFile,
new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr,
- secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags);
+ secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags);
String timeStampStr = parser.getAttributeValue(null, "ft");
if (timeStampStr != null) {
try {
@@ -2662,6 +2663,11 @@
mDisabledSysPackages.put(name, ps);
}
+ private static int PRE_M_APP_INFO_FLAG_HIDDEN = 1<<27;
+ private static int PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE = 1<<28;
+ private static int PRE_M_APP_INFO_FLAG_FORWARD_LOCK = 1<<29;
+ private static int PRE_M_APP_INFO_FLAG_PRIVILEGED = 1<<30;
+
private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
String name = null;
String realName = null;
@@ -2678,6 +2684,7 @@
String installerPackageName = null;
String uidError = null;
int pkgFlags = 0;
+ int pkgPrivateFlags = 0;
long timeStamp = 0;
long firstInstallTime = 0;
long lastUpdateTime = 0;
@@ -2713,22 +2720,54 @@
}
installerPackageName = parser.getAttributeValue(null, "installer");
- systemStr = parser.getAttributeValue(null, "flags");
+ systemStr = parser.getAttributeValue(null, "publicFlags");
if (systemStr != null) {
try {
pkgFlags = Integer.parseInt(systemStr);
} catch (NumberFormatException e) {
}
- } else {
- // For backward compatibility
- systemStr = parser.getAttributeValue(null, "system");
+ systemStr = parser.getAttributeValue(null, "privateFlags");
if (systemStr != null) {
- pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM
- : 0;
+ try {
+ pkgPrivateFlags = Integer.parseInt(systemStr);
+ } catch (NumberFormatException e) {
+ }
+ }
+ } else {
+ // Pre-M -- both public and private flags were stored in one "flags" field.
+ systemStr = parser.getAttributeValue(null, "flags");
+ if (systemStr != null) {
+ try {
+ pkgFlags = Integer.parseInt(systemStr);
+ } catch (NumberFormatException e) {
+ }
+ if ((pkgFlags & PRE_M_APP_INFO_FLAG_HIDDEN) != 0) {
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+ }
+ if ((pkgFlags & PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE) != 0) {
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
+ }
+ if ((pkgFlags & PRE_M_APP_INFO_FLAG_FORWARD_LOCK) != 0) {
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
+ }
+ if ((pkgFlags & PRE_M_APP_INFO_FLAG_PRIVILEGED) != 0) {
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+ }
+ pkgFlags &= ~(PRE_M_APP_INFO_FLAG_HIDDEN
+ | PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE
+ | PRE_M_APP_INFO_FLAG_FORWARD_LOCK
+ | PRE_M_APP_INFO_FLAG_PRIVILEGED);
} else {
- // Old settings that don't specify system... just treat
- // them as system, good enough.
- pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ // For backward compatibility
+ systemStr = parser.getAttributeValue(null, "system");
+ if (systemStr != null) {
+ pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM
+ : 0;
+ } else {
+ // Old settings that don't specify system... just treat
+ // them as system, good enough.
+ pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ }
}
}
String timeStampStr = parser.getAttributeValue(null, "ft");
@@ -2781,7 +2820,8 @@
} else if (userId > 0) {
packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
- secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags);
+ secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,
+ pkgPrivateFlags);
if (PackageManagerService.DEBUG_SETTINGS)
Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
+ userId + " pkg=" + packageSetting);
@@ -2800,7 +2840,7 @@
packageSetting = new PendingPackage(name.intern(), realName, new File(
codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
- userId, versionCode, pkgFlags);
+ userId, versionCode, pkgFlags, pkgPrivateFlags);
packageSetting.setTimeStamp(timeStamp);
packageSetting.firstInstallTime = firstInstallTime;
packageSetting.lastUpdateTime = lastUpdateTime;
@@ -2967,6 +3007,7 @@
String name = null;
String idStr = null;
int pkgFlags = 0;
+ int pkgPrivateFlags = 0;
SharedUserSetting su = null;
try {
name = parser.getAttributeValue(null, ATTR_NAME);
@@ -2985,7 +3026,8 @@
+ " has bad userId " + idStr + " at "
+ parser.getPositionDescription());
} else {
- if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags)) == null) {
+ if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags, pkgPrivateFlags))
+ == null) {
PackageManagerService
.reportSettingsProblem(Log.ERROR, "Occurred while parsing settings at "
+ parser.getPositionDescription());
@@ -3302,9 +3344,12 @@
ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
- ApplicationInfo.FLAG_PRIVILEGED, "PRIVILEGED",
- ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
- ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
+ };
+
+ static final Object[] PRIVATE_FLAG_DUMP_SPEC = new Object[] {
+ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, "PRIVILEGED",
+ ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+ ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
};
void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag, PackageSetting ps,
@@ -3391,6 +3436,8 @@
pw.println(ps.pkg.applicationInfo.toString());
pw.print(prefix); pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
FLAG_DUMP_SPEC); pw.println();
+ pw.print(prefix); pw.print(" priavateFlags="); printFlags(pw,
+ ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println();
pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
if (ps.pkg.mOperationPending) {
pw.print(prefix); pw.println(" mOperationPending=true");
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 2b406f7..d95739c 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -28,14 +28,16 @@
// flags that are associated with this uid, regardless of any package flags
int uidFlags;
+ int uidPrivateFlags;
final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>();
final PackageSignatures signatures = new PackageSignatures();
- SharedUserSetting(String _name, int _pkgFlags) {
- super(_pkgFlags);
+ SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) {
+ super(_pkgFlags, _pkgPrivateFlags);
uidFlags = _pkgFlags;
+ uidPrivateFlags = _pkgPrivateFlags;
name = _name;
}
@@ -55,12 +57,20 @@
}
setFlags(aggregatedFlags);
}
+ if ((this.pkgPrivateFlags & packageSetting.pkgPrivateFlags) != 0) {
+ int aggregatedPrivateFlags = uidPrivateFlags;
+ for (PackageSetting ps : packages) {
+ aggregatedPrivateFlags |= ps.pkgPrivateFlags;
+ }
+ setPrivateFlags(aggregatedPrivateFlags);
+ }
}
}
void addPackage(PackageSetting packageSetting) {
if (packages.add(packageSetting)) {
setFlags(this.pkgFlags | packageSetting.pkgFlags);
+ setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
}
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f85b195..69a1ac9 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1592,7 +1592,8 @@
try {
for (ApplicationInfo appInfo : apps) {
if ((appInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0
- && (appInfo.flags & ApplicationInfo.FLAG_HIDDEN) != 0) {
+ && (appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HIDDEN)
+ != 0) {
mPm.setApplicationHiddenSettingAsUser(appInfo.packageName, false,
userHandle);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index ec8a77513..5bb193a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1195,8 +1195,7 @@
} catch (RemoteException ex) { }
mSettingsObserver = new SettingsObserver(mHandler);
mSettingsObserver.observe();
- mShortcutManager = new ShortcutManager(context, mHandler);
- mShortcutManager.observe();
+ mShortcutManager = new ShortcutManager(context);
mUiMode = context.getResources().getInteger(
com.android.internal.R.integer.config_defaultUiModeType);
mHomeIntent = new Intent(Intent.ACTION_MAIN, null);
@@ -4751,7 +4750,6 @@
msg.setAsynchronous(true);
msg.sendToTarget();
}
- break;
}
}
diff --git a/services/core/java/com/android/server/policy/ShortcutManager.java b/services/core/java/com/android/server/policy/ShortcutManager.java
index 6a0136a..76f56bc 100644
--- a/services/core/java/com/android/server/policy/ShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ShortcutManager.java
@@ -16,81 +16,47 @@
package com.android.server.policy;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.os.Handler;
-import android.provider.Settings;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.res.XmlResourceParser;
+import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.KeyCharacterMap;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
-import java.net.URISyntaxException;
+import java.io.IOException;
/**
* Manages quick launch shortcuts by:
* <li> Keeping the local copy in sync with the database (this is an observer)
* <li> Returning a shortcut-matching intent to clients
*/
-class ShortcutManager extends ContentObserver {
-
+class ShortcutManager {
private static final String TAG = "ShortcutManager";
-
- private static final int COLUMN_SHORTCUT = 0;
- private static final int COLUMN_INTENT = 1;
- private static final String[] sProjection = new String[] {
- Settings.Bookmarks.SHORTCUT, Settings.Bookmarks.INTENT
- };
- private Context mContext;
- private Cursor mCursor;
- /** Map of a shortcut to its intent. */
- private SparseArray<Intent> mShortcutIntents;
+ private static final String TAG_BOOKMARKS = "bookmarks";
+ private static final String TAG_BOOKMARK = "bookmark";
+
+ private static final String ATTRIBUTE_PACKAGE = "package";
+ private static final String ATTRIBUTE_CLASS = "class";
+ private static final String ATTRIBUTE_SHORTCUT = "shortcut";
+ private static final String ATTRIBUTE_CATEGORY = "category";
+
+ private final SparseArray<ShortcutInfo> mShortcuts = new SparseArray<>();
+
+ private final Context mContext;
- public ShortcutManager(Context context, Handler handler) {
- super(handler);
-
+ public ShortcutManager(Context context) {
mContext = context;
- mShortcutIntents = new SparseArray<Intent>();
+ loadShortcuts();
}
- /** Observes the provider of shortcut+intents */
- public void observe() {
- mCursor = mContext.getContentResolver().query(
- Settings.Bookmarks.CONTENT_URI, sProjection, null, null, null);
- mCursor.registerContentObserver(this);
- updateShortcuts();
- }
-
- @Override
- public void onChange(boolean selfChange) {
- updateShortcuts();
- }
-
- private void updateShortcuts() {
- Cursor c = mCursor;
- if (!c.requery()) {
- Log.e(TAG, "ShortcutObserver could not re-query shortcuts.");
- return;
- }
-
- mShortcutIntents.clear();
- while (c.moveToNext()) {
- int shortcut = c.getInt(COLUMN_SHORTCUT);
- if (shortcut == 0) continue;
- String intentURI = c.getString(COLUMN_INTENT);
- Intent intent = null;
- try {
- intent = Intent.getIntent(intentURI);
- } catch (URISyntaxException e) {
- Log.w(TAG, "Intent URI for shortcut invalid.", e);
- }
- if (intent == null) continue;
- mShortcutIntents.put(shortcut, intent);
- }
- }
-
/**
* Gets the shortcut intent for a given keycode+modifier. Make sure you
* strip whatever modifier is used for invoking shortcuts (for example,
@@ -107,23 +73,105 @@
* @return The intent that matches the shortcut, or null if not found.
*/
public Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
- Intent intent = null;
+ ShortcutInfo shortcut = null;
// First try the exact keycode (with modifiers).
- int shortcut = kcm.get(keyCode, metaState);
- if (shortcut != 0) {
- intent = mShortcutIntents.get(shortcut);
+ int shortcutChar = kcm.get(keyCode, metaState);
+ if (shortcutChar != 0) {
+ shortcut = mShortcuts.get(shortcutChar);
}
// Next try the primary character on that key.
- if (intent == null) {
- shortcut = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
- if (shortcut != 0) {
- intent = mShortcutIntents.get(shortcut);
+ if (shortcut == null) {
+ shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
+ if (shortcutChar != 0) {
+ shortcut = mShortcuts.get(shortcutChar);
}
}
- return intent;
+ return (shortcut != null) ? shortcut.intent : null;
}
+ private void loadShortcuts() {
+ PackageManager packageManager = mContext.getPackageManager();
+ try {
+ XmlResourceParser parser = mContext.getResources().getXml(
+ com.android.internal.R.xml.bookmarks);
+ XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
+
+ while (true) {
+ XmlUtils.nextElement(parser);
+
+ if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+ break;
+ }
+
+ if (!TAG_BOOKMARK.equals(parser.getName())) {
+ break;
+ }
+
+ String packageName = parser.getAttributeValue(null, ATTRIBUTE_PACKAGE);
+ String className = parser.getAttributeValue(null, ATTRIBUTE_CLASS);
+ String shortcutName = parser.getAttributeValue(null, ATTRIBUTE_SHORTCUT);
+ String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
+
+ if (TextUtils.isEmpty(shortcutName)) {
+ Log.w(TAG, "Unable to get shortcut for: " + packageName + "/" + className);
+ continue;
+ }
+
+ final int shortcutChar = shortcutName.charAt(0);
+
+ final Intent intent;
+ final String title;
+ if (packageName != null && className != null) {
+ ActivityInfo info = null;
+ ComponentName componentName = new ComponentName(packageName, className);
+ try {
+ info = packageManager.getActivityInfo(componentName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ String[] packages = packageManager.canonicalToCurrentPackageNames(
+ new String[] { packageName });
+ componentName = new ComponentName(packages[0], className);
+ try {
+ info = packageManager.getActivityInfo(componentName, 0);
+ } catch (PackageManager.NameNotFoundException e1) {
+ Log.w(TAG, "Unable to add bookmark: " + packageName
+ + "/" + className, e);
+ continue;
+ }
+ }
+
+ intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ intent.setComponent(componentName);
+ title = info.loadLabel(packageManager).toString();
+ } else if (categoryName != null) {
+ intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, categoryName);
+ title = "";
+ } else {
+ Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutName
+ + ": missing package/class or category attributes");
+ continue;
+ }
+
+ ShortcutInfo shortcut = new ShortcutInfo(title, intent);
+ mShortcuts.put(shortcutChar, shortcut);
+ }
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "Got exception parsing bookmarks.", e);
+ } catch (IOException e) {
+ Log.w(TAG, "Got exception parsing bookmarks.", e);
+ }
+ }
+
+ private static final class ShortcutInfo {
+ public final String title;
+ public final Intent intent;
+
+ public ShortcutInfo(String title, Intent intent) {
+ this.title = title;
+ this.intent = intent;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index f8b40d1..b5d4caf 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -397,8 +397,6 @@
private final class MagnifiedViewport {
- private static final int DEFAUTLT_BORDER_WIDTH_DIP = 5;
-
private final SparseArray<WindowState> mTempWindowStates =
new SparseArray<WindowState>();
@@ -411,6 +409,8 @@
private final Region mMagnifiedBounds = new Region();
private final Region mOldMagnifiedBounds = new Region();
+ private final Path mCircularPath;
+
private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
private final WindowManager mWindowManager;
@@ -425,12 +425,22 @@
public MagnifiedViewport() {
mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
- mBorderWidth = TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, DEFAUTLT_BORDER_WIDTH_DIP,
- mContext.getResources().getDisplayMetrics());
+ mBorderWidth = mContext.getResources().getDimension(
+ com.android.internal.R.dimen.accessibility_magnification_indicator_width);
mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
mDrawBorderInset = (int) mBorderWidth / 2;
mWindow = new ViewportWindow(mContext);
+
+ if (mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_windowIsRound)) {
+ mCircularPath = new Path();
+ mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
+ final int centerXY = mTempPoint.x / 2;
+ mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
+ } else {
+ mCircularPath = null;
+ }
+
recomputeBoundsLocked();
}
@@ -459,6 +469,10 @@
Region availableBounds = mTempRegion1;
availableBounds.set(0, 0, screenWidth, screenHeight);
+ if (mCircularPath != null) {
+ availableBounds.setPath(mCircularPath, availableBounds);
+ }
+
Region nonMagnifiedBounds = mTempRegion4;
nonMagnifiedBounds.set(0, 0, 0, 0);
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 0c5d06a..abf8412 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -146,35 +146,6 @@
mDisplayContentsAnimators.delete(displayId);
}
- void hideWallpapersLocked(final WindowState w) {
- final WindowState wallpaperTarget = mService.mWallpaperTarget;
- final WindowState lowerWallpaperTarget = mService.mLowerWallpaperTarget;
- final ArrayList<WindowToken> wallpaperTokens = mService.mWallpaperTokens;
-
- if ((wallpaperTarget == w && lowerWallpaperTarget == null) || wallpaperTarget == null) {
- final int numTokens = wallpaperTokens.size();
- for (int i = numTokens - 1; i >= 0; i--) {
- final WindowToken token = wallpaperTokens.get(i);
- final int numWindows = token.windows.size();
- for (int j = numWindows - 1; j >= 0; j--) {
- final WindowState wallpaper = token.windows.get(j);
- final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
- if (!winAnimator.mLastHidden) {
- winAnimator.hide();
- mService.dispatchWallpaperVisibility(wallpaper, false);
- setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
- WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
- }
- }
- if (WindowManagerService.DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG,
- "Hiding wallpaper " + token + " from " + w
- + " target=" + wallpaperTarget + " lower=" + lowerWallpaperTarget
- + "\n" + Debug.getCallers(5, " "));
- token.hidden = true;
- }
- }
- }
-
private void updateAppWindowsLocked(int displayId) {
ArrayList<TaskStack> stacks = mService.getDisplayContentLocked(displayId).getStacks();
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 71fddfb..02a4f4d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -582,7 +582,7 @@
}
}
- final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
+ private final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
// If non-null, this is the currently visible window that is associated
// with the wallpaper.
@@ -1694,7 +1694,7 @@
return true;
}
- final boolean isWallpaperVisible(WindowState wallpaperTarget) {
+ private boolean isWallpaperVisible(WindowState wallpaperTarget) {
if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
+ (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
+ " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null)
@@ -1708,6 +1708,34 @@
|| mLowerWallpaperTarget != null;
}
+ void hideWallpapersLocked(final WindowState winGoingAway) {
+ if (mWallpaperTarget != null &&
+ (mWallpaperTarget != winGoingAway || mLowerWallpaperTarget != null)) {
+ return;
+ }
+
+ for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
+ final WindowToken token = mWallpaperTokens.get(i);
+ for (int j = token.windows.size() - 1; j >= 0; j--) {
+ final WindowState wallpaper = token.windows.get(j);
+ final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
+ if (!winAnimator.mLastHidden) {
+ winAnimator.hide();
+ dispatchWallpaperVisibility(wallpaper, false);
+ final DisplayContent displayContent = wallpaper.getDisplayContent();
+ if (displayContent != null) {
+ displayContent.pendingLayoutChanges |=
+ WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+ }
+ }
+ }
+ if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token
+ + " from " + winGoingAway + " target=" + mWallpaperTarget + " lower="
+ + mLowerWallpaperTarget + "\n" + Debug.getCallers(5, " "));
+ token.hidden = true;
+ }
+ }
+
static final int ADJUST_WALLPAPER_LAYERS_CHANGED = 1<<1;
static final int ADJUST_WALLPAPER_VISIBILITY_CHANGED = 1<<2;
@@ -1890,7 +1918,7 @@
// AND any starting window associated with it, AND below the
// maximum layer the policy allows for wallpapers.
while (foundI > 0) {
- WindowState wb = windows.get(foundI-1);
+ WindowState wb = windows.get(foundI - 1);
if (wb.mBaseLayer < maxLayer &&
wb.mAttachedWindow != foundW &&
(foundW.mAttachedWindow == null ||
@@ -1916,7 +1944,7 @@
} else {
// Okay i is the position immediately above the wallpaper. Look at
// what is below it for later.
- foundW = foundI > 0 ? windows.get(foundI-1) : null;
+ foundW = foundI > 0 ? windows.get(foundI - 1) : null;
}
if (visible) {
@@ -1939,43 +1967,37 @@
// Start stepping backwards from here, ensuring that our wallpaper windows
// are correctly placed.
int changed = 0;
- int curTokenIndex = mWallpaperTokens.size();
- while (curTokenIndex > 0) {
- curTokenIndex--;
- WindowToken token = mWallpaperTokens.get(curTokenIndex);
+ for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+ WindowToken token = mWallpaperTokens.get(curTokenNdx);
if (token.hidden == visible) {
if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
"Wallpaper token " + token + " hidden=" + !visible);
changed |= ADJUST_WALLPAPER_VISIBILITY_CHANGED;
token.hidden = !visible;
- // Need to do a layout to ensure the wallpaper now has the
- // correct size.
+ // Need to do a layout to ensure the wallpaper now has the correct size.
getDefaultDisplayContentLocked().layoutNeeded = true;
}
- int curWallpaperIndex = token.windows.size();
- while (curWallpaperIndex > 0) {
- curWallpaperIndex--;
- WindowState wallpaper = token.windows.get(curWallpaperIndex);
+ final WindowList tokenWindows = token.windows;
+ for (int wallpaperNdx = tokenWindows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+ WindowState wallpaper = tokenWindows.get(wallpaperNdx);
if (visible) {
updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
}
- // First, make sure the client has the current visibility
- // state.
+ // First, make sure the client has the current visibility state.
dispatchWallpaperVisibility(wallpaper, visible);
- wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
+ wallpaper.mWinAnimator.mAnimLayer =
+ wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
+ wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
- // First, if this window is at the current index, then all
- // is well.
+ // First, if this window is at the current index, then all is well.
if (wallpaper == foundW) {
foundI--;
- foundW = foundI > 0
- ? windows.get(foundI-1) : null;
+ foundW = foundI > 0 ? windows.get(foundI - 1) : null;
continue;
}
@@ -2015,48 +2037,20 @@
}
}
- /*
- final TaskStack targetStack =
- mWallpaperTarget == null ? null : mWallpaperTarget.getStack();
- if ((changed & ADJUST_WALLPAPER_LAYERS_CHANGED) != 0 &&
- targetStack != null && !targetStack.isHomeStack()) {
- // If the wallpaper target is not on the home stack then make sure that all windows
- // from other non-home stacks are above the wallpaper.
- for (i = foundI - 1; i >= 0; --i) {
- WindowState win = windows.get(i);
- if (!win.isVisibleLw()) {
- continue;
- }
- final TaskStack winStack = win.getStack();
- if (winStack != null && !winStack.isHomeStack() && winStack != targetStack) {
- windows.remove(i);
- windows.add(foundI + 1, win);
- }
- }
- }
- */
-
- if (targetChanged && DEBUG_WALLPAPER_LIGHT) {
- Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget
- + " lower=" + mLowerWallpaperTarget + " upper="
- + mUpperWallpaperTarget);
- }
+ if (targetChanged && DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target="
+ + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper="
+ + mUpperWallpaperTarget);
return changed;
}
void setWallpaperAnimLayerAdjustmentLocked(int adj) {
- if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG,
- "Setting wallpaper layer adj to " + adj);
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Setting wallpaper layer adj to " + adj);
mWallpaperAnimLayerAdjustment = adj;
- int curTokenIndex = mWallpaperTokens.size();
- while (curTokenIndex > 0) {
- curTokenIndex--;
- WindowToken token = mWallpaperTokens.get(curTokenIndex);
- int curWallpaperIndex = token.windows.size();
- while (curWallpaperIndex > 0) {
- curWallpaperIndex--;
- WindowState wallpaper = token.windows.get(curWallpaperIndex);
+ for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+ WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
+ for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+ WindowState wallpaper = windows.get(wallpaperNdx);
wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + adj;
if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "setWallpaper win "
+ wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
@@ -2190,14 +2184,10 @@
}
}
- int curTokenIndex = mWallpaperTokens.size();
- while (curTokenIndex > 0) {
- curTokenIndex--;
- WindowToken token = mWallpaperTokens.get(curTokenIndex);
- int curWallpaperIndex = token.windows.size();
- while (curWallpaperIndex > 0) {
- curWallpaperIndex--;
- WindowState wallpaper = token.windows.get(curWallpaperIndex);
+ for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+ WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
+ for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+ WindowState wallpaper = windows.get(wallpaperNdx);
if (updateWallpaperOffsetLocked(wallpaper, dw, dh, sync)) {
WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
winAnimator.computeShownFrameLocked();
@@ -2229,7 +2219,7 @@
}
}
- void updateWallpaperVisibilityLocked() {
+ private void updateWallpaperVisibilityLocked() {
final boolean visible = isWallpaperVisible(mWallpaperTarget);
final DisplayContent displayContent = mWallpaperTarget.getDisplayContent();
if (displayContent == null) {
@@ -2239,21 +2229,18 @@
final int dw = displayInfo.logicalWidth;
final int dh = displayInfo.logicalHeight;
- int curTokenIndex = mWallpaperTokens.size();
- while (curTokenIndex > 0) {
- curTokenIndex--;
- WindowToken token = mWallpaperTokens.get(curTokenIndex);
+ for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+ WindowToken token = mWallpaperTokens.get(curTokenNdx);
if (token.hidden == visible) {
token.hidden = !visible;
// Need to do a layout to ensure the wallpaper now has the
// correct size.
- getDefaultDisplayContentLocked().layoutNeeded = true;
+ displayContent.layoutNeeded = true;
}
- int curWallpaperIndex = token.windows.size();
- while (curWallpaperIndex > 0) {
- curWallpaperIndex--;
- WindowState wallpaper = token.windows.get(curWallpaperIndex);
+ final WindowList windows = token.windows;
+ for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+ WindowState wallpaper = windows.get(wallpaperNdx);
if (visible) {
updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
}
@@ -2911,14 +2898,10 @@
if (window == mWallpaperTarget || window == mLowerWallpaperTarget
|| window == mUpperWallpaperTarget) {
boolean doWait = sync;
- int curTokenIndex = mWallpaperTokens.size();
- while (curTokenIndex > 0) {
- curTokenIndex--;
- WindowToken token = mWallpaperTokens.get(curTokenIndex);
- int curWallpaperIndex = token.windows.size();
- while (curWallpaperIndex > 0) {
- curWallpaperIndex--;
- WindowState wallpaper = token.windows.get(curWallpaperIndex);
+ for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+ final WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
+ for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+ WindowState wallpaper = windows.get(wallpaperNdx);
try {
wallpaper.mClient.dispatchWallpaperCommand(action,
x, y, z, extras, sync);
@@ -3556,13 +3539,13 @@
false /*updateInputWindows*/);
}
- if (delayed) {
- if (displayContent != null) {
- displayContent.mExitingTokens.add(wtoken);
- }
+ if (delayed && displayContent != null) {
+ displayContent.mExitingTokens.add(wtoken);
} else if (wtoken.windowType == TYPE_WALLPAPER) {
mWallpaperTokens.remove(wtoken);
}
+ } else if (wtoken.windowType == TYPE_WALLPAPER) {
+ mWallpaperTokens.remove(wtoken);
}
mInputMonitor.updateInputWindowsLw(true /*force*/);
@@ -9583,9 +9566,6 @@
// it is animating.
displayContent.pendingLayoutChanges = 0;
- if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number "
- + mLayoutRepeatCount, displayContent.pendingLayoutChanges);
-
if (isDefaultDisplay) {
mPolicy.beginPostLayoutPolicyLw(dw, dh);
for (i = windows.size() - 1; i >= 0; i--) {
@@ -9669,7 +9649,7 @@
if (w.mHasSurface && !w.isHiddenFromUserLocked()) {
// Take care of the window being ready to display.
final boolean committed =
- winAnimator.commitFinishDrawingLocked(currentTime);
+ winAnimator.commitFinishDrawingLocked();
if (isDefaultDisplay && committed) {
if (w.mAttrs.type == TYPE_DREAM) {
// HACK: When a dream is shown, it may at that
@@ -10799,7 +10779,7 @@
void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
- if (mTokenMap.size() > 0) {
+ if (!mTokenMap.isEmpty()) {
pw.println(" All tokens:");
Iterator<WindowToken> it = mTokenMap.values().iterator();
while (it.hasNext()) {
@@ -10813,7 +10793,7 @@
}
}
}
- if (mWallpaperTokens.size() > 0) {
+ if (!mWallpaperTokens.isEmpty()) {
pw.println();
pw.println(" Wallpaper tokens:");
for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
@@ -10828,7 +10808,7 @@
}
}
}
- if (mFinishedStarting.size() > 0) {
+ if (!mFinishedStarting.isEmpty()) {
pw.println();
pw.println(" Finishing start of application tokens:");
for (int i=mFinishedStarting.size()-1; i>=0; i--) {
@@ -10843,7 +10823,7 @@
}
}
}
- if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
+ if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty()) {
pw.println();
if (mOpeningApps.size() > 0) {
pw.print(" mOpeningApps="); pw.println(mOpeningApps);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 8202880..a78bab45 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -53,21 +53,16 @@
import android.view.WindowManager;
import android.view.WindowManagerPolicy;
import android.view.WindowManager.LayoutParams;
-import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
-import com.android.internal.R;
import com.android.server.wm.WindowManagerService.H;
import java.io.PrintWriter;
import java.util.ArrayList;
-class WinAnimatorList extends ArrayList<WindowStateAnimator> {
-}
-
/**
* Keep track of animations and surface operations for a single WindowState.
**/
@@ -185,7 +180,7 @@
int mAttrType;
- public WindowStateAnimator(final WindowState win) {
+ WindowStateAnimator(final WindowState win) {
final WindowManagerService service = win.mService;
mService = service;
@@ -482,7 +477,7 @@
mService.mPendingRemove.add(mWin);
mWin.mRemoveOnExit = false;
}
- mAnimator.hideWallpapersLocked(mWin);
+ mService.hideWallpapersLocked(mWin);
}
void hide() {
@@ -523,7 +518,7 @@
}
// This must be called while inside a transaction.
- boolean commitFinishDrawingLocked(long currentTime) {
+ boolean commitFinishDrawingLocked() {
if (DEBUG_STARTING_WINDOW &&
mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="
@@ -538,9 +533,9 @@
mDrawState = READY_TO_SHOW;
final AppWindowToken atoken = mWin.mAppToken;
if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
- performShowLocked();
+ return performShowLocked();
}
- return true;
+ return false;
}
static class SurfaceTrace extends SurfaceControl {
@@ -980,7 +975,7 @@
}
mSurfaceControl.destroy();
}
- mAnimator.hideWallpapersLocked(mWin);
+ mService.hideWallpapersLocked(mWin);
} catch (RuntimeException e) {
Slog.w(TAG, "Exception thrown when destroying Window " + this
+ " surface " + mSurfaceControl + " session " + mSession
@@ -1006,7 +1001,7 @@
WindowManagerService.logSurface(mWin, "DESTROY PENDING", e);
}
mPendingDestroySurface.destroy();
- mAnimator.hideWallpapersLocked(mWin);
+ mService.hideWallpapersLocked(mWin);
}
} catch (RuntimeException e) {
Slog.w(TAG, "Exception thrown when destroying Window "
@@ -1454,7 +1449,7 @@
hide();
} else if (w.mAttachedHidden || !w.isOnScreen()) {
hide();
- mAnimator.hideWallpapersLocked(w);
+ mService.hideWallpapersLocked(w);
// If we are waiting for this window to handle an
// orientation change, well, it is hidden, so
@@ -1626,13 +1621,8 @@
}
if (DEBUG_VISIBILITY || (DEBUG_STARTING_WINDOW &&
mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING)) {
- RuntimeException e = null;
- if (!WindowManagerService.HIDE_STACK_CRAWLS) {
- e = new RuntimeException();
- e.fillInStackTrace();
- }
Slog.v(TAG, "performShow on " + this
- + ": mDrawState=" + mDrawState + " readyForDisplay="
+ + ": mDrawState=" + drawStateToString() + " readyForDisplay="
+ mWin.isReadyForDisplayIgnoringKeyguard()
+ " starting=" + (mWin.mAttrs.type == TYPE_APPLICATION_STARTING)
+ " during animation: policyVis=" + mWin.mPolicyVisibility
@@ -1643,7 +1633,8 @@
+ (mWin.mAppToken != null ? mWin.mAppToken.hidden : false)
+ " animating=" + mAnimating
+ " tok animating="
- + (mAppAnimator != null ? mAppAnimator.animating : false), e);
+ + (mAppAnimator != null ? mAppAnimator.animating : false) + " Callers="
+ + Debug.getCallers(3));
}
if (mDrawState == READY_TO_SHOW && mWin.isReadyForDisplayIgnoringKeyguard()) {
if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 05c37d1..fbb6f7c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5071,6 +5071,10 @@
throws RemoteException {
ApplicationInfo appInfo = pm.getApplicationInfo(packageName, GET_UNINSTALLED_PACKAGES,
userId);
+ if (appInfo == null) {
+ throw new IllegalArgumentException("The application " + packageName +
+ " is not present on this device");
+ }
return (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index 8d44905..396ed38 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -112,7 +112,7 @@
MidiReceiver receiver = new MidiReceiver() {
@Override
- public void onPost(byte[] data, int offset, int count, long timestamp)
+ public void post(byte[] data, int offset, int count, long timestamp)
throws IOException {
// FIXME - timestamps are ignored, future posting not supported yet.
mOutputStreams[portNumberF].write(data, offset, count);
@@ -137,7 +137,7 @@
pfd.revents = 0;
int count = mInputStreams[index].read(buffer);
- mOutputPortReceivers[index].onPost(buffer, 0, count,
+ mOutputPortReceivers[index].post(buffer, 0, count,
System.nanoTime());
} else if ((pfd.revents & (OsConstants.POLLERR
| OsConstants.POLLHUP)) != 0) {
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 393d2ec..1330c28 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -48,8 +48,9 @@
class Field():
- def __init__(self, clazz, raw, blame):
+ def __init__(self, clazz, line, raw, blame):
self.clazz = clazz
+ self.line = line
self.raw = raw.strip(" {;")
self.blame = blame
@@ -73,8 +74,9 @@
class Method():
- def __init__(self, clazz, raw, blame):
+ def __init__(self, clazz, line, raw, blame):
self.clazz = clazz
+ self.line = line
self.raw = raw.strip(" {;")
self.blame = blame
@@ -110,8 +112,9 @@
class Class():
- def __init__(self, pkg, raw, blame):
+ def __init__(self, pkg, line, raw, blame):
self.pkg = pkg
+ self.line = line
self.raw = raw.strip(" {;")
self.blame = blame
self.ctors = []
@@ -140,7 +143,8 @@
class Package():
- def __init__(self, raw, blame):
+ def __init__(self, line, raw, blame):
+ self.line = line
self.raw = raw.strip(" {;")
self.blame = blame
@@ -151,64 +155,92 @@
return self.raw
-def parse_api(fn):
+def parse_api(f):
+ line = 0
api = {}
pkg = None
clazz = None
blame = None
re_blame = re.compile("^([a-z0-9]{7,}) \(<([^>]+)>.+?\) (.+?)$")
+ for raw in f.readlines():
+ line += 1
+ raw = raw.rstrip()
+ match = re_blame.match(raw)
+ if match is not None:
+ blame = match.groups()[0:2]
+ raw = match.groups()[2]
+ else:
+ blame = None
- with open(fn) as f:
- for raw in f.readlines():
- raw = raw.rstrip()
- match = re_blame.match(raw)
- if match is not None:
- blame = match.groups()[0:2]
- raw = match.groups()[2]
- else:
- blame = None
-
- if raw.startswith("package"):
- pkg = Package(raw, blame)
- elif raw.startswith(" ") and raw.endswith("{"):
- clazz = Class(pkg, raw, blame)
- api[clazz.fullname] = clazz
- elif raw.startswith(" ctor"):
- clazz.ctors.append(Method(clazz, raw, blame))
- elif raw.startswith(" method"):
- clazz.methods.append(Method(clazz, raw, blame))
- elif raw.startswith(" field"):
- clazz.fields.append(Field(clazz, raw, blame))
+ if raw.startswith("package"):
+ pkg = Package(line, raw, blame)
+ elif raw.startswith(" ") and raw.endswith("{"):
+ clazz = Class(pkg, line, raw, blame)
+ api[clazz.fullname] = clazz
+ elif raw.startswith(" ctor"):
+ clazz.ctors.append(Method(clazz, line, raw, blame))
+ elif raw.startswith(" method"):
+ clazz.methods.append(Method(clazz, line, raw, blame))
+ elif raw.startswith(" field"):
+ clazz.fields.append(Field(clazz, line, raw, blame))
return api
+def parse_api_file(fn):
+ with open(fn) as f:
+ return parse_api(f)
+
+
+class Failure():
+ def __init__(self, sig, clazz, detail, error, msg):
+ self.sig = sig
+ self.clazz = clazz
+ self.detail = detail
+ self.error = error
+ self.msg = msg
+
+ if error:
+ dump = "%sError:%s %s" % (format(fg=RED, bg=BLACK, bold=True), format(reset=True), msg)
+ else:
+ dump = "%sWarning:%s %s" % (format(fg=YELLOW, bg=BLACK, bold=True), format(reset=True), msg)
+
+ self.line = clazz.line
+ blame = clazz.blame
+ if detail is not None:
+ dump += "\n in " + repr(detail)
+ self.line = detail.line
+ blame = detail.blame
+ dump += "\n in " + repr(clazz)
+ dump += "\n in " + repr(clazz.pkg)
+ dump += "\n at line " + repr(self.line)
+ if blame is not None:
+ dump += "\n last modified by %s in %s" % (blame[1], blame[0])
+
+ self.dump = dump
+
+ def __repr__(self):
+ return self.dump
+
+
failures = {}
-def _fail(clazz, detail, msg):
+def _fail(clazz, detail, error, msg):
"""Records an API failure to be processed later."""
global failures
sig = "%s-%s-%s" % (clazz.fullname, repr(detail), msg)
sig = sig.replace(" deprecated ", " ")
- res = msg
- blame = clazz.blame
- if detail is not None:
- res += "\n in " + repr(detail)
- blame = detail.blame
- res += "\n in " + repr(clazz)
- res += "\n in " + repr(clazz.pkg)
- if blame is not None:
- res += "\n last modified by %s in %s" % (blame[1], blame[0])
- failures[sig] = res
+ failures[sig] = Failure(sig, clazz, detail, error, msg)
+
def warn(clazz, detail, msg):
- _fail(clazz, detail, "%sWarning:%s %s" % (format(fg=YELLOW, bg=BLACK, bold=True), format(reset=True), msg))
+ _fail(clazz, detail, False, msg)
def error(clazz, detail, msg):
- _fail(clazz, detail, "%sError:%s %s" % (format(fg=RED, bg=BLACK, bold=True), format(reset=True), msg))
+ _fail(clazz, detail, True, msg)
def verify_constants(clazz):
@@ -770,28 +802,29 @@
return failures
-cur = parse_api(sys.argv[1])
-cur_fail = verify_style(cur)
+if __name__ == "__main__":
+ cur = parse_api_file(sys.argv[1])
+ cur_fail = verify_style(cur)
-if len(sys.argv) > 2:
- prev = parse_api(sys.argv[2])
- prev_fail = verify_style(prev)
+ if len(sys.argv) > 2:
+ prev = parse_api_file(sys.argv[2])
+ prev_fail = verify_style(prev)
- # ignore errors from previous API level
- for p in prev_fail:
- if p in cur_fail:
- del cur_fail[p]
+ # ignore errors from previous API level
+ for p in prev_fail:
+ if p in cur_fail:
+ del cur_fail[p]
- # look for compatibility issues
- compat_fail = verify_compat(cur, prev)
+ # look for compatibility issues
+ compat_fail = verify_compat(cur, prev)
- print "%s API compatibility issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
- for f in sorted(compat_fail):
- print compat_fail[f]
+ print "%s API compatibility issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
+ for f in sorted(compat_fail):
+ print compat_fail[f]
+ print
+
+
+ print "%s API style issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
+ for f in sorted(cur_fail):
+ print cur_fail[f]
print
-
-
-print "%s API style issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
-for f in sorted(cur_fail):
- print cur_fail[f]
- print