Merge "Fix getHitRect() to return correct rect for transformed child"
diff --git a/Android.mk b/Android.mk
index 25c050e..c8576a0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -700,32 +700,6 @@
include $(BUILD_DROIDDOC)
-# explicitly specify that online-sdk depends on framework-res and any generated docs
-$(full_target): framework-res-package-target
-
-# ==== docs for the s.a.c site (on the google app engine server) =======================
-# include $(CLEAR_VARS)
-
-# LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
-# LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
-# LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
-# LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
-# LOCAL_DROIDDOC_HTML_DIR:=../../docs/source.android.com/src
-# LOCAL_ADDITIONAL_HTML_DIR:=
-# LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
-# LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
-# LOCAL_MODULE := online-sac
-#
-# LOCAL_DROIDDOC_OPTIONS:= \
-# $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
-# -toroot / \
-# -hdf android.whichdoc online \
-# -hdf sac true
-#
-# LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
-#
-# include $(BUILD_DROIDDOC)
-
# ==== docs for the web (on the devsite app engine server) =======================
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
@@ -754,35 +728,6 @@
include $(BUILD_DROIDDOC)
-# explicitly specify that ds depends on framework-res and any generated docs
-$(full_target): framework-res-package-target
-
-#==== reference docs for GCM =======================
-
-include $(CLEAR_VARS)
-#
-gcm_docs_src_files += \
- $(call all-java-files-under, ../../vendor/unbundled_google/libs/gcm/gcm-client/src) \
- $(call all-java-files-under, ../../vendor/unbundled_google/libs/gcm/gcm-server/src) \
- $(call all-html-files-under, ../../vendor/unbundled_google/libs/gcm/gcm-client/src) \
- $(call all-html-files-under, ../../vendor/unbundled_google/libs/gcm/gcm-server/src) \
-
-LOCAL_SRC_FILES := $(gcm_docs_src_files)
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE:= online-gcm-ref
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_IS_HOST_MODULE := false
-
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR := build/tools/droiddoc/templates-sdk
-
-LOCAL_DROIDDOC_OPTIONS := \
- -toroot / \
- -gcmref \
- -hdf android.whichdoc online \
- -hdf template.showLanguageMenu true
-
-include $(BUILD_DROIDDOC)
-
# ==== docs that have all of the stuff that's @hidden =======================
include $(CLEAR_VARS)
diff --git a/api/current.txt b/api/current.txt
index c8f999f..ee4732d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4153,11 +4153,14 @@
}
public final class UiAutomation {
- method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, com.android.internal.util.Predicate<android.view.accessibility.AccessibilityEvent>, long) throws java.util.concurrent.TimeoutException;
+ method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
+ method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
method public boolean injectInputEvent(android.view.InputEvent, boolean);
+ method public final boolean performGlobalAction(int);
method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener);
method public boolean setRotation(int);
+ method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
method public android.graphics.Bitmap takeScreenshot();
method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException;
field public static final int ROTATION_FREEZE_0 = 0; // 0x0
@@ -4168,6 +4171,10 @@
field public static final int ROTATION_UNFREEZE = -2; // 0xfffffffe
}
+ public static abstract interface UiAutomation.AccessibilityEventFilter {
+ method public abstract boolean accept(android.view.accessibility.AccessibilityEvent);
+ }
+
public static abstract interface UiAutomation.OnAccessibilityEventListener {
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
}
@@ -19485,6 +19492,7 @@
public class FieldPacker {
ctor public FieldPacker(int);
+ ctor public FieldPacker(byte[]);
method public void addBoolean(boolean);
method public void addF32(float);
method public void addF32(android.renderscript.Float2);
@@ -22265,6 +22273,21 @@
method public int getTopPadding();
}
+ public abstract interface TextDirectionHeuristic {
+ method public abstract boolean isRtl(char[], int, int);
+ method public abstract boolean isRtl(java.lang.CharSequence, int, int);
+ }
+
+ public class TextDirectionHeuristics {
+ ctor public TextDirectionHeuristics();
+ field public static final android.text.TextDirectionHeuristic ANYRTL_LTR;
+ field public static final android.text.TextDirectionHeuristic FIRSTSTRONG_LTR;
+ field public static final android.text.TextDirectionHeuristic FIRSTSTRONG_RTL;
+ field public static final android.text.TextDirectionHeuristic LOCALE;
+ field public static final android.text.TextDirectionHeuristic LTR;
+ field public static final android.text.TextDirectionHeuristic RTL;
+ }
+
public class TextPaint extends android.graphics.Paint {
ctor public TextPaint();
ctor public TextPaint(int);
@@ -22356,6 +22379,48 @@
}
+package android.text.bidi {
+
+ public final class BidiFormatter {
+ method public java.lang.String dirAttr(java.lang.String);
+ method public java.lang.String dirAttr(java.lang.String, android.text.TextDirectionHeuristic);
+ method public java.lang.String dirAttr(boolean);
+ method public java.lang.String dirAttrValue(java.lang.String);
+ method public java.lang.String dirAttrValue(java.lang.String, android.text.TextDirectionHeuristic);
+ method public java.lang.String dirAttrValue(boolean);
+ method public java.lang.String endEdge();
+ method public static android.text.bidi.BidiFormatter getInstance(boolean);
+ method public static android.text.bidi.BidiFormatter getInstance(java.util.Locale);
+ method public boolean getStereoReset();
+ method public boolean isRtl(java.lang.String);
+ method public boolean isRtlContext();
+ method public java.lang.String mark();
+ method public java.lang.String markAfter(java.lang.String);
+ method public java.lang.String markAfter(java.lang.String, android.text.TextDirectionHeuristic);
+ method public java.lang.String markBefore(java.lang.String);
+ method public java.lang.String markBefore(java.lang.String, android.text.TextDirectionHeuristic);
+ method public java.lang.String spanWrap(java.lang.String, android.text.TextDirectionHeuristic, boolean);
+ method public java.lang.String spanWrap(java.lang.String, android.text.TextDirectionHeuristic);
+ method public java.lang.String spanWrap(java.lang.String, boolean);
+ method public java.lang.String spanWrap(java.lang.String);
+ method public java.lang.String startEdge();
+ method public java.lang.String unicodeWrap(java.lang.String, android.text.TextDirectionHeuristic, boolean);
+ method public java.lang.String unicodeWrap(java.lang.String, android.text.TextDirectionHeuristic);
+ method public java.lang.String unicodeWrap(java.lang.String, boolean);
+ method public java.lang.String unicodeWrap(java.lang.String);
+ }
+
+ public static final class BidiFormatter.Builder {
+ ctor public BidiFormatter.Builder();
+ ctor public BidiFormatter.Builder(boolean);
+ ctor public BidiFormatter.Builder(java.util.Locale);
+ method public android.text.bidi.BidiFormatter build();
+ method public android.text.bidi.BidiFormatter.Builder setTextDirectionHeuristic(android.text.TextDirectionHeuristic);
+ method public android.text.bidi.BidiFormatter.Builder stereoReset(boolean);
+ }
+
+}
+
package android.text.format {
public class DateFormat {
@@ -23278,6 +23343,7 @@
field public static final int DENSITY_TV = 213; // 0xd5
field public static final int DENSITY_XHIGH = 320; // 0x140
field public static final int DENSITY_XXHIGH = 480; // 0x1e0
+ field public static final int DENSITY_XXXHIGH = 640; // 0x280
field public float density;
field public int densityDpi;
field public int heightPixels;
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8dddbc1..811b92a 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -457,7 +457,7 @@
*
* @return The accessibility service info.
*
- * @see AccessibilityNodeInfo
+ * @see AccessibilityServiceInfo
*/
public final AccessibilityServiceInfo getServiceInfo() {
IAccessibilityServiceConnection connection =
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 594be68..944a533 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1915,7 +1915,30 @@
return PackageManager.PERMISSION_DENIED;
}
- /** @hide */
+ /**
+ * @hide
+ * Helper for dealing with incoming user arguments to system service calls.
+ * Takes care of checking permissions and converting USER_CURRENT to the
+ * actual current user.
+ *
+ * @param callingPid The pid of the incoming call, as per Binder.getCallingPid().
+ * @param callingUid The uid of the incoming call, as per Binder.getCallingUid().
+ * @param userId The user id argument supplied by the caller -- this is the user
+ * they want to run as.
+ * @param allowAll If true, we will allow USER_ALL. This means you must be prepared
+ * to get a USER_ALL returned and deal with it correctly. If false,
+ * an exception will be thrown if USER_ALL is supplied.
+ * @param requireFull If true, the caller must hold
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} to be able to run as a
+ * different user than their current process; otherwise they must hold
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS}.
+ * @param name Optional textual name of the incoming call; only for generating error messages.
+ * @param callerPackage Optional package name of caller; only for error messages.
+ *
+ * @return Returns the user ID that the call should run as. Will always be a concrete
+ * user number, unless <var>allowAll</var> is true in which case it could also be
+ * USER_ALL.
+ */
public static int handleIncomingUser(int callingPid, int callingUid, int userId,
boolean allowAll, boolean requireFull, String name, String callerPackage) {
if (UserHandle.getUserId(callingUid) == userId) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 34708ab..de69867 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,6 +16,7 @@
package android.app;
+import android.Manifest;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IAppOpsCallback;
@@ -29,7 +30,25 @@
import android.os.Process;
import android.os.RemoteException;
-/** @hide */
+/**
+ * API for interacting with "application operation" tracking. Allows you to:
+ *
+ * - Note when operations are happening, and find out if they are allowed for the current caller.
+ * - Disallow specific apps from doing specific operations.
+ * - Collect all of the current information about operations that have been executed or are not
+ * being allowed.
+ * - Monitor for changes in whether an operation is allowed.
+ *
+ * Each operation is identified by a single integer; these integers are a fixed set of
+ * operations, enumerated by the OP_* constants.
+ *
+ * When checking operations, the result is a "mode" integer indicating the current setting
+ * for the operation under that caller: MODE_ALLOWED, MODE_IGNORED (don't execute the operation but
+ * fake its behavior enough so that the caller doesn't crash), MODE_ERRORED (through a
+ * SecurityException back to the caller; the normal operation calls will do this for you).
+ *
+ * @hide
+ */
public class AppOpsManager {
final Context mContext;
final IAppOpsService mService;
@@ -71,8 +90,11 @@
public static final int OP_WRITE_SETTINGS = 23;
public static final int OP_SYSTEM_ALERT_WINDOW = 24;
public static final int OP_ACCESS_NOTIFICATIONS = 25;
+ public static final int OP_CAMERA = 26;
+ public static final int OP_RECORD_AUDIO = 27;
+ public static final int OP_PLAY_AUDIO = 28;
/** @hide */
- public static final int _NUM_OP = 26;
+ public static final int _NUM_OP = 29;
/**
* This maps each operation to the operation that serves as the
@@ -109,6 +131,9 @@
OP_WRITE_SETTINGS,
OP_SYSTEM_ALERT_WINDOW,
OP_ACCESS_NOTIFICATIONS,
+ OP_CAMERA,
+ OP_RECORD_AUDIO,
+ OP_PLAY_AUDIO,
};
/**
@@ -142,6 +167,9 @@
"WRITE_SETTINGS",
"SYSTEM_ALERT_WINDOW",
"ACCESS_NOTIFICATIONS",
+ "CAMERA",
+ "RECORD_AUDIO",
+ "PLAY_AUDIO",
};
/**
@@ -175,21 +203,36 @@
android.Manifest.permission.WRITE_SETTINGS,
android.Manifest.permission.SYSTEM_ALERT_WINDOW,
android.Manifest.permission.ACCESS_NOTIFICATIONS,
+ android.Manifest.permission.CAMERA,
+ android.Manifest.permission.RECORD_AUDIO,
+ null, // no permission for playing audio
};
+ /**
+ * Retrieve the op switch that controls the given operation.
+ */
public static int opToSwitch(int op) {
return sOpToSwitch[op];
}
+ /**
+ * Retrieve a non-localized name for the operation, for debugging output.
+ */
public static String opToName(int op) {
if (op == OP_NONE) return "NONE";
return op < sOpNames.length ? sOpNames[op] : ("Unknown(" + op + ")");
}
+ /**
+ * Retrieve the permission associated with an operation, or null if there is not one.
+ */
public static String opToPermission(int op) {
return sOpPerms[op];
}
+ /**
+ * Class holding all of the operation information associated with an app.
+ */
public static class PackageOps implements Parcelable {
private final String mPackageName;
private final int mUid;
@@ -249,6 +292,9 @@
};
}
+ /**
+ * Class holding the information about one unique operation of an application.
+ */
public static class OpEntry implements Parcelable {
private final int mOp;
private final int mMode;
@@ -321,6 +367,9 @@
};
}
+ /**
+ * Callback for notification of changes to operation state.
+ */
public interface Callback {
public void opChanged(int op, String packageName);
}
@@ -330,6 +379,11 @@
mService = service;
}
+ /**
+ * Retrieve current operation state for all applications.
+ *
+ * @param ops The set of operations you are interested in, or null if you want all of them.
+ */
public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
try {
return mService.getPackagesForOps(ops);
@@ -338,6 +392,13 @@
return null;
}
+ /**
+ * Retrieve current operation state for one application.
+ *
+ * @param uid The uid of the application of interest.
+ * @param packageName The name of the application of interest.
+ * @param ops The set of operations you are interested in, or null if you want all of them.
+ */
public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
try {
return mService.getOpsForPackage(uid, packageName, ops);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index bb10f62..1f4c81d 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -38,5 +38,6 @@
boolean areNotificationsEnabledForPackage(String pkg, int uid);
StatusBarNotification[] getActiveNotifications(String callingPkg);
+ StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count);
}
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index e611f6d..7d02342 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -18,7 +18,9 @@
import android.accessibilityservice.AccessibilityService.Callbacks;
import android.accessibilityservice.AccessibilityService.IAccessibilityServiceClientWrapper;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceClient;
+import android.accessibilityservice.IAccessibilityServiceConnection;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
@@ -35,8 +37,6 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.IAccessibilityInteractionConnection;
-import com.android.internal.util.Predicate;
-
import java.util.ArrayList;
import java.util.concurrent.TimeoutException;
@@ -45,7 +45,10 @@
* introspection of the screen content. It relies on the platform accessibility
* APIs to introspect the screen and to perform some actions on the remote view
* tree. It also allows injecting of arbitrary raw input events simulating user
- * interaction with keyboards and touch devices.
+ * interaction with keyboards and touch devices. One can think of a UiAutomation
+ * as a special type of {@link android.accessibilityservice.AccessibilityService}
+ * which does not provide hooks for the service life cycle and exposes other
+ * APIs that are useful for UI test automation.
* <p>
* The APIs exposed by this class are low-level to maximize flexibility when
* developing UI test automation tools and libraries. Generally, a UiAutomation
@@ -130,6 +133,21 @@
}
/**
+ * Listener for filtering accessibility events.
+ */
+ public static interface AccessibilityEventFilter {
+
+ /**
+ * Callback for determining whether an event is accepted or
+ * it is filtered out.
+ *
+ * @param event The event to process.
+ * @return True if the event is accepted, false to filter it out.
+ */
+ public boolean accept(AccessibilityEvent event);
+ }
+
+ /**
* Creates a new instance that will handle callbacks from the accessibility
* layer on the thread of the provided looper and perform requests for privileged
* operations on the provided connection.
@@ -243,6 +261,90 @@
}
/**
+ * Performs a global action. Such an action can be performed at any moment
+ * regardless of the current application or user location in that application.
+ * For example going back, going home, opening recents, etc.
+ *
+ * @param action The action to perform.
+ * @return Whether the action was successfully performed.
+ *
+ * @see AccessibilityService#GLOBAL_ACTION_BACK
+ * @see AccessibilityService#GLOBAL_ACTION_HOME
+ * @see AccessibilityService#GLOBAL_ACTION_NOTIFICATIONS
+ * @see AccessibilityService#GLOBAL_ACTION_RECENTS
+ */
+ public final boolean performGlobalAction(int action) {
+ final IAccessibilityServiceConnection connection;
+ synchronized (mLock) {
+ throwIfNotConnectedLocked();
+ connection = AccessibilityInteractionClient.getInstance()
+ .getConnection(mConnectionId);
+ }
+ // Calling out without a lock held.
+ if (connection != null) {
+ try {
+ return connection.performGlobalAction(action);
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Gets the an {@link AccessibilityServiceInfo} describing this UiAutomation.
+ * This method is useful if one wants to change some of the dynamically
+ * configurable properties at runtime.
+ *
+ * @return The accessibility service info.
+ *
+ * @see AccessibilityServiceInfo
+ */
+ public final AccessibilityServiceInfo getServiceInfo() {
+ final IAccessibilityServiceConnection connection;
+ synchronized (mLock) {
+ throwIfNotConnectedLocked();
+ connection = AccessibilityInteractionClient.getInstance()
+ .getConnection(mConnectionId);
+ }
+ // Calling out without a lock held.
+ if (connection != null) {
+ try {
+ return connection.getServiceInfo();
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Sets the {@link AccessibilityServiceInfo} that describes how this
+ * UiAutomation will be handled by the platform accessibility layer.
+ *
+ * @param info The info.
+ *
+ * @see AccessibilityServiceInfo
+ */
+ public final void setServiceInfo(AccessibilityServiceInfo info) {
+ final IAccessibilityServiceConnection connection;
+ synchronized (mLock) {
+ throwIfNotConnectedLocked();
+ AccessibilityInteractionClient.getInstance().clearCache();
+ connection = AccessibilityInteractionClient.getInstance()
+ .getConnection(mConnectionId);
+ }
+ // Calling out without a lock held.
+ if (connection != null) {
+ try {
+ connection.setServiceInfo(info);
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
+ }
+ }
+ }
+
+ /**
* Gets the root {@link AccessibilityNodeInfo} in the active window.
*
* @return The root info.
@@ -339,7 +441,7 @@
* @throws TimeoutException If the expected event is not received within the timeout.
*/
public AccessibilityEvent executeAndWaitForEvent(Runnable command,
- Predicate<AccessibilityEvent> filter, long timeoutMillis) throws TimeoutException {
+ AccessibilityEventFilter filter, long timeoutMillis) throws TimeoutException {
synchronized (mLock) {
throwIfNotConnectedLocked();
@@ -363,7 +465,7 @@
if (event.getEventTime() <= executionStartTimeMillis) {
continue;
}
- if (filter.apply(event)) {
+ if (filter.accept(event)) {
return event;
}
event.recycle();
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 09ff7be..028317f 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -703,7 +703,13 @@
* show for the initial UI.
*/
public Header onGetInitialHeader() {
- return mHeaders.get(0);
+ for (int i=0; i<mHeaders.size(); i++) {
+ Header h = mHeaders.get(i);
+ if (h.fragment != null) {
+ return h;
+ }
+ }
+ throw new IllegalStateException("Must have at least one header with a fragment");
}
/**
@@ -1167,6 +1173,9 @@
getFragmentManager().popBackStack(BACK_STACK_PREFS,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
} else {
+ if (header.fragment == null) {
+ throw new IllegalStateException("can't switch to header that has no fragment");
+ }
int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);
switchToHeaderInner(header.fragment, header.fragmentArguments, direction);
setSelectedHeader(header);
diff --git a/core/java/android/text/TextDirectionHeuristic.java b/core/java/android/text/TextDirectionHeuristic.java
index 513e11c..8a4ba42 100644
--- a/core/java/android/text/TextDirectionHeuristic.java
+++ b/core/java/android/text/TextDirectionHeuristic.java
@@ -17,10 +17,30 @@
package android.text;
/**
- * Interface for objects that guess at the paragraph direction by examining text.
- *
- * @hide
+ * Interface for objects that use a heuristic for guessing at the paragraph direction by examining text.
*/
public interface TextDirectionHeuristic {
- boolean isRtl(char[] text, int start, int count);
+ /**
+ * Guess if a chars array is in the RTL direction or not.
+ *
+ * @param array the char array.
+ * @param start start index, inclusive.
+ * @param count the length to check, must not be negative and not greater than
+ * {@code array.length - start}.
+ * @return true if all chars in the range are to be considered in a RTL direction,
+ * false otherwise.
+ */
+ boolean isRtl(char[] array, int start, int count);
+
+ /**
+ * Guess if a {@code CharSequence} is in the RTL direction or not.
+ *
+ * @param cs the CharSequence.
+ * @param start start index, inclusive.
+ * @param count the length to check, must not be negative and not greater than
+ * {@code CharSequence.length() - start}.
+ * @return true if all chars in the range are to be considered in a RTL direction,
+ * false otherwise.
+ */
+ boolean isRtl(CharSequence cs, int start, int count);
}
diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java
index df8c4c6..7d7e3a9 100644
--- a/core/java/android/text/TextDirectionHeuristics.java
+++ b/core/java/android/text/TextDirectionHeuristics.java
@@ -19,43 +19,45 @@
import android.view.View;
+import java.nio.CharBuffer;
+
/**
* Some objects that implement TextDirectionHeuristic.
*
- * @hide
*/
public class TextDirectionHeuristics {
- /** Always decides that the direction is left to right. */
+ /**
+ * Always decides that the direction is left to right.
+ */
public static final TextDirectionHeuristic LTR =
new TextDirectionHeuristicInternal(null /* no algorithm */, false);
- /** Always decides that the direction is right to left. */
+ /**
+ * Always decides that the direction is right to left.
+ */
public static final TextDirectionHeuristic RTL =
new TextDirectionHeuristicInternal(null /* no algorithm */, true);
/**
- * Determines the direction based on the first strong directional character,
- * including bidi format chars, falling back to left to right if it
- * finds none. This is the default behavior of the Unicode Bidirectional
- * Algorithm.
+ * Determines the direction based on the first strong directional character, including bidi
+ * format chars, falling back to left to right if it finds none. This is the default behavior
+ * of the Unicode Bidirectional Algorithm.
*/
public static final TextDirectionHeuristic FIRSTSTRONG_LTR =
new TextDirectionHeuristicInternal(FirstStrong.INSTANCE, false);
/**
- * Determines the direction based on the first strong directional character,
- * including bidi format chars, falling back to right to left if it
- * finds none. This is similar to the default behavior of the Unicode
- * Bidirectional Algorithm, just with different fallback behavior.
+ * Determines the direction based on the first strong directional character, including bidi
+ * format chars, falling back to right to left if it finds none. This is similar to the default
+ * behavior of the Unicode Bidirectional Algorithm, just with different fallback behavior.
*/
public static final TextDirectionHeuristic FIRSTSTRONG_RTL =
new TextDirectionHeuristicInternal(FirstStrong.INSTANCE, true);
/**
- * If the text contains any strong right to left non-format character, determines
- * that the direction is right to left, falling back to left to right if it
- * finds none.
+ * If the text contains any strong right to left non-format character, determines that the
+ * direction is right to left, falling back to left to right if it finds none.
*/
public static final TextDirectionHeuristic ANYRTL_LTR =
new TextDirectionHeuristicInternal(AnyStrong.INSTANCE_RTL, false);
@@ -65,8 +67,39 @@
*/
public static final TextDirectionHeuristic LOCALE = TextDirectionHeuristicLocale.INSTANCE;
- private static enum TriState {
- TRUE, FALSE, UNKNOWN;
+ /**
+ * State constants for taking care about true / false / unknown
+ */
+ private static final int STATE_TRUE = 0;
+ private static final int STATE_FALSE = 1;
+ private static final int STATE_UNKNOWN = 2;
+
+ private static int isRtlText(int directionality) {
+ switch (directionality) {
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+ return STATE_FALSE;
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+ return STATE_TRUE;
+ default:
+ return STATE_UNKNOWN;
+ }
+ }
+
+ private static int isRtlTextOrFormat(int directionality) {
+ switch (directionality) {
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
+ return STATE_FALSE;
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
+ return STATE_TRUE;
+ default:
+ return STATE_UNKNOWN;
+ }
}
/**
@@ -87,21 +120,26 @@
abstract protected boolean defaultIsRtl();
@Override
- public boolean isRtl(char[] chars, int start, int count) {
- if (chars == null || start < 0 || count < 0 || chars.length - count < start) {
+ public boolean isRtl(char[] array, int start, int count) {
+ return isRtl(CharBuffer.wrap(array), start, count);
+ }
+
+ @Override
+ public boolean isRtl(CharSequence cs, int start, int count) {
+ if (cs == null || start < 0 || count < 0 || cs.length() - count < start) {
throw new IllegalArgumentException();
}
if (mAlgorithm == null) {
return defaultIsRtl();
}
- return doCheck(chars, start, count);
+ return doCheck(cs, start, count);
}
- private boolean doCheck(char[] chars, int start, int count) {
- switch(mAlgorithm.checkRtl(chars, start, count)) {
- case TRUE:
+ private boolean doCheck(CharSequence cs, int start, int count) {
+ switch(mAlgorithm.checkRtl(cs, start, count)) {
+ case STATE_TRUE:
return true;
- case FALSE:
+ case STATE_FALSE:
return false;
default:
return defaultIsRtl();
@@ -124,58 +162,26 @@
}
}
- private static TriState isRtlText(int directionality) {
- switch (directionality) {
- case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
- return TriState.FALSE;
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
- return TriState.TRUE;
- default:
- return TriState.UNKNOWN;
- }
- }
-
- private static TriState isRtlTextOrFormat(int directionality) {
- switch (directionality) {
- case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
- case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
- case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
- return TriState.FALSE;
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
- return TriState.TRUE;
- default:
- return TriState.UNKNOWN;
- }
- }
-
/**
* Interface for an algorithm to guess the direction of a paragraph of text.
- *
*/
private static interface TextDirectionAlgorithm {
/**
* Returns whether the range of text is RTL according to the algorithm.
- *
*/
- TriState checkRtl(char[] text, int start, int count);
+ int checkRtl(CharSequence cs, int start, int count);
}
/**
- * Algorithm that uses the first strong directional character to determine
- * the paragraph direction. This is the standard Unicode Bidirectional
- * algorithm.
- *
+ * Algorithm that uses the first strong directional character to determine the paragraph
+ * direction. This is the standard Unicode Bidirectional algorithm.
*/
private static class FirstStrong implements TextDirectionAlgorithm {
@Override
- public TriState checkRtl(char[] text, int start, int count) {
- TriState result = TriState.UNKNOWN;
- for (int i = start, e = start + count; i < e && result == TriState.UNKNOWN; ++i) {
- result = isRtlTextOrFormat(Character.getDirectionality(text[i]));
+ public int checkRtl(CharSequence cs, int start, int count) {
+ int result = STATE_UNKNOWN;
+ for (int i = start, e = start + count; i < e && result == STATE_UNKNOWN; ++i) {
+ result = isRtlTextOrFormat(Character.getDirectionality(cs.charAt(i)));
}
return result;
}
@@ -190,25 +196,24 @@
* Algorithm that uses the presence of any strong directional non-format
* character (e.g. excludes LRE, LRO, RLE, RLO) to determine the
* direction of text.
- *
*/
private static class AnyStrong implements TextDirectionAlgorithm {
private final boolean mLookForRtl;
@Override
- public TriState checkRtl(char[] text, int start, int count) {
+ public int checkRtl(CharSequence cs, int start, int count) {
boolean haveUnlookedFor = false;
for (int i = start, e = start + count; i < e; ++i) {
- switch (isRtlText(Character.getDirectionality(text[i]))) {
- case TRUE:
+ switch (isRtlText(Character.getDirectionality(cs.charAt(i)))) {
+ case STATE_TRUE:
if (mLookForRtl) {
- return TriState.TRUE;
+ return STATE_TRUE;
}
haveUnlookedFor = true;
break;
- case FALSE:
+ case STATE_FALSE:
if (!mLookForRtl) {
- return TriState.FALSE;
+ return STATE_FALSE;
}
haveUnlookedFor = true;
break;
@@ -217,9 +222,9 @@
}
}
if (haveUnlookedFor) {
- return mLookForRtl ? TriState.FALSE : TriState.TRUE;
+ return mLookForRtl ? STATE_FALSE : STATE_TRUE;
}
- return TriState.UNKNOWN;
+ return STATE_UNKNOWN;
}
private AnyStrong(boolean lookForRtl) {
diff --git a/core/java/android/text/bidi/BidiFormatter.java b/core/java/android/text/bidi/BidiFormatter.java
new file mode 100644
index 0000000..370cbf7
--- /dev/null
+++ b/core/java/android/text/bidi/BidiFormatter.java
@@ -0,0 +1,1123 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.bidi;
+
+import android.text.TextDirectionHeuristic;
+import android.text.TextDirectionHeuristics;
+import android.text.TextUtils;
+import android.view.View;
+
+import static android.text.TextDirectionHeuristics.FIRSTSTRONG_LTR;
+
+import java.util.Locale;
+
+
+/**
+ * Utility class for formatting text for display in a potentially opposite-directionality context
+ * without garbling. The directionality of the context is set at formatter creation and the
+ * directionality of the text can be either estimated or passed in when known. Provides the
+ * following functionality:
+ * <p>
+ * 1. Bidi Wrapping
+ * When text in one language is mixed into a document in another, opposite-directionality language,
+ * e.g. when an English business name is embedded in a Hebrew web page, both the inserted string
+ * and the text surrounding it may be displayed incorrectly unless the inserted string is explicitly
+ * separated from the surrounding text in a "wrapper" that:
+ * <p>
+ * - Declares its directionality so that the string is displayed correctly. This can be done in HTML
+ * markup (e.g. a 'span dir="rtl"' element) by {@link #spanWrap} and similar methods, or - only in
+ * contexts where markup can't be used - in Unicode bidi formatting codes by {@link #unicodeWrap}
+ * and similar methods.
+ * <p>
+ * - Isolates the string's directionality, so it does not unduly affect the surrounding content.
+ * Currently, this can only be done using invisible Unicode characters of the same direction as
+ * the context (LRM or RLM) in addition to the directionality declaration above, thus "resetting"
+ * the directionality to that of the context. The "reset" may need to be done at both ends of the
+ * string. Without "reset" after the string, the string will "stick" to a number or logically
+ * separate opposite-direction text that happens to follow it in-line (even if separated by
+ * neutral content like spaces and punctuation). Without "reset" before the string, the same can
+ * happen there, but only with more opposite-direction text, not a number. One approach is to
+ * "reset" the direction only after each string, on the theory that if the preceding opposite-
+ * direction text is itself bidi-wrapped, the "reset" after it will prevent the sticking. (Doing
+ * the "reset" only before each string definitely does not work because we do not want to require
+ * bidi-wrapping numbers, and a bidi-wrapped opposite-direction string could be followed by a
+ * number.) Still, the safest policy is to do the "reset" on both ends of each string, since RTL
+ * message translations often contain untranslated Latin-script brand names and technical terms,
+ * and one of these can be followed by a bidi-wrapped inserted value. On the other hand, when one
+ * has such a message, it is best to do the "reset" manually in the message translation itself,
+ * since the message's opposite-direction text could be followed by an inserted number, which we
+ * would not bidi-wrap anyway. Thus, "reset" only after the string is the current default. In an
+ * alternative to "reset", recent additions to the HTML, CSS, and Unicode standards allow the
+ * isolation to be part of the directionality declaration. This form of isolation is better than
+ * "reset" because it takes less space, does not require knowing the context directionality, has a
+ * gentler effect than "reset", and protects both ends of the string. However, we do not yet allow
+ * using it because required platforms do not yet support it.
+ * <p>
+ * Providing these wrapping services is the basic purpose of the bidi formatter.
+ * <p>
+ * 2. Directionality estimation
+ * How does one know whether a string about to be inserted into surrounding text has the same
+ * directionality? Well, in many cases, one knows that this must be the case when writing the code
+ * doing the insertion, e.g. when a localized message is inserted into a localized page. In such
+ * cases there is no need to involve the bidi formatter at all. In some other cases, it need not be
+ * the same as the context, but is either constant (e.g. urls are always LTR) or otherwise known.
+ * In the remaining cases, e.g. when the string is user-entered or comes from a database, the
+ * language of the string (and thus its directionality) is not known a priori, and must be
+ * estimated at run-time. The bidi formatter can do this automatically using the default
+ * first-strong estimation algorithm. It can also be configured to use a custom directionality
+ * estimation object.
+ * <p>
+ * 3. Escaping
+ * When wrapping plain text - i.e. text that is not already HTML or HTML-escaped - in HTML markup,
+ * the text must first be HTML-escaped to prevent XSS attacks and other nasty business. This of
+ * course is always true, but the escaping can not be done after the string has already been wrapped
+ * in markup, so the bidi formatter also serves as a last chance and includes escaping services.
+ * <p>
+ * Thus, in a single call, the formatter will escape the input string as specified, determine its
+ * directionality, and wrap it as necessary. It is then up to the caller to insert the return value
+ * in the output.
+ */
+public final class BidiFormatter {
+
+ /**
+ * The default text direction heuristic.
+ */
+ private static TextDirectionHeuristic DEFAULT_TEXT_DIRECTION_HEURISTIC = FIRSTSTRONG_LTR;
+
+ /**
+ * Unicode "Left-To-Right Embedding" (LRE) character.
+ */
+ private static final char LRE = '\u202A';
+
+ /**
+ * Unicode "Right-To-Left Embedding" (RLE) character.
+ */
+ private static final char RLE = '\u202B';
+
+ /**
+ * Unicode "Pop Directional Formatting" (PDF) character.
+ */
+ private static final char PDF = '\u202C';
+
+ /**
+ * Unicode "Left-To-Right Mark" (LRM) character.
+ */
+ private static final char LRM = '\u200E';
+
+ /*
+ * Unicode "Right-To-Left Mark" (RLM) character.
+ */
+ private static final char RLM = '\u200F';
+
+ /*
+ * String representation of LRM
+ */
+ private static final String LRM_STRING = Character.toString(LRM);
+
+ /*
+ * String representation of RLM
+ */
+ private static final String RLM_STRING = Character.toString(RLM);
+
+ /**
+ * "ltr" string constant.
+ */
+ private static final String LTR_STRING = "ltr";
+
+ /**
+ * "rtl" string constant.
+ */
+ private static final String RTL_STRING = "rtl";
+
+ /**
+ * "dir=\"ltr\"" string constant.
+ */
+ private static final String DIR_LTR_STRING = "dir=\"ltr\"";
+
+ /**
+ * "dir=\"rtl\"" string constant.
+ */
+ private static final String DIR_RTL_STRING = "dir=\"rtl\"";
+
+ /**
+ * "right" string constant.
+ */
+ private static final String RIGHT = "right";
+
+ /**
+ * "left" string constant.
+ */
+ private static final String LEFT = "left";
+
+ /**
+ * Empty string constant.
+ */
+ private static final String EMPTY_STRING = "";
+
+ /**
+ * A class for building a BidiFormatter with non-default options.
+ */
+ public static final class Builder {
+ private boolean isRtlContext;
+ private int flags;
+ private TextDirectionHeuristic textDirectionHeuristic;
+
+ /**
+ * Constructor.
+ *
+ */
+ public Builder() {
+ initialize(isRtlLocale(Locale.getDefault()));
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param rtlContext Whether the context directionality is RTL.
+ */
+ public Builder(boolean rtlContext) {
+ initialize(rtlContext);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param locale The context locale.
+ */
+ public Builder(Locale locale) {
+ initialize(isRtlLocale(locale));
+ }
+
+ /**
+ * Initializes the builder with the given context directionality and default options.
+ *
+ * @param isRtlContext Whether the context is RTL or not.
+ */
+ private void initialize(boolean isRtlContext) {
+ this.isRtlContext = isRtlContext;
+ textDirectionHeuristic = DEFAULT_TEXT_DIRECTION_HEURISTIC;
+ this.flags = DEFAULT_FLAGS;
+ }
+
+ /**
+ * Specifies whether the BidiFormatter to be built should also "reset" directionality before
+ * a string being bidi-wrapped, not just after it. The default is false.
+ */
+ public Builder stereoReset(boolean stereoReset) {
+ if (stereoReset) {
+ flags |= FLAG_STEREO_RESET;
+ } else {
+ flags &= ~FLAG_STEREO_RESET;
+ }
+ return this;
+ }
+
+ /**
+ * Specifies the default directionality estimation algorithm to be used by the BidiFormatter.
+ * By default, uses the first-strong heuristic.
+ *
+ * @param heuristic the {@code TextDirectionHeuristic} to use.
+ * @return the builder itself.
+ */
+ public Builder setTextDirectionHeuristic(TextDirectionHeuristic heuristic) {
+ this.textDirectionHeuristic = heuristic;
+ return this;
+ }
+
+ private static BidiFormatter getDefaultInstanceFromContext(boolean isRtlContext) {
+ return isRtlContext ? DEFAULT_RTL_INSTANCE : DEFAULT_LTR_INSTANCE;
+ }
+
+ /**
+ * @return A BidiFormatter with the specified options.
+ */
+ public BidiFormatter build() {
+ if (flags == DEFAULT_FLAGS &&
+ textDirectionHeuristic == DEFAULT_TEXT_DIRECTION_HEURISTIC) {
+ return getDefaultInstanceFromContext(isRtlContext);
+ }
+ return new BidiFormatter(isRtlContext, flags, textDirectionHeuristic);
+ }
+ }
+
+ //
+ private static final int FLAG_STEREO_RESET = 2;
+ private static final int DEFAULT_FLAGS = FLAG_STEREO_RESET;
+
+ private static final BidiFormatter DEFAULT_LTR_INSTANCE = new BidiFormatter(
+ false /* LTR context */,
+ DEFAULT_FLAGS,
+ DEFAULT_TEXT_DIRECTION_HEURISTIC);
+
+ private static final BidiFormatter DEFAULT_RTL_INSTANCE = new BidiFormatter(
+ true /* RTL context */,
+ DEFAULT_FLAGS,
+ DEFAULT_TEXT_DIRECTION_HEURISTIC);
+
+ private final boolean isRtlContext;
+ private final int flags;
+ private final TextDirectionHeuristic defaultTextDirectionHeuristic;
+
+ /**
+ * Factory for creating an instance of BidiFormatter given the context directionality.
+ *
+ * @param rtlContext Whether the context directionality is RTL.
+ */
+ public static BidiFormatter getInstance(boolean rtlContext) {
+ return new Builder(rtlContext).build();
+ }
+
+ /**
+ * Factory for creating an instance of BidiFormatter given the context locale.
+ *
+ * @param locale The context locale.
+ */
+ public static BidiFormatter getInstance(Locale locale) {
+ return new Builder(locale).build();
+ }
+
+ /**
+ * @param isRtlContext Whether the context directionality is RTL or not.
+ * @param flags The option flags.
+ * @param heuristic The default text direction heuristic.
+ */
+ private BidiFormatter(boolean isRtlContext, int flags, TextDirectionHeuristic heuristic) {
+ this.isRtlContext = isRtlContext;
+ this.flags = flags;
+ this.defaultTextDirectionHeuristic = heuristic;
+ }
+
+ /**
+ * @return Whether the context directionality is RTL
+ */
+ public boolean isRtlContext() {
+ return isRtlContext;
+ }
+
+ /**
+ * @return Whether directionality "reset" should also be done before a string being
+ * bidi-wrapped, not just after it.
+ */
+ public boolean getStereoReset() {
+ return (flags & FLAG_STEREO_RESET) != 0;
+ }
+
+ /**
+ * Returns "rtl" if {@code str}'s estimated directionality is RTL, and "ltr" if it is LTR.
+ *
+ * @param str String whose directionality is to be estimated.
+ * @return "rtl" if {@code str}'s estimated directionality is RTL, and "ltr" otherwise.
+ */
+ public String dirAttrValue(String str) {
+ return dirAttrValue(isRtl(str));
+ }
+
+ /**
+ * Operates like {@link #dirAttrValue(String)}, but uses a given heuristic to estimate the
+ * {@code str}'s directionality.
+ *
+ * @param str String whose directionality is to be estimated.
+ * @param heuristic The text direction heuristic that will be used to estimate the {@code str}'s
+ * directionality.
+ * @return "rtl" if {@code str}'s estimated directionality is RTL, and "ltr" otherwise.
+ */
+ public String dirAttrValue(String str, TextDirectionHeuristic heuristic) {
+ return dirAttrValue(heuristic.isRtl(str, 0, str.length()));
+ }
+
+ /**
+ * Returns "rtl" if the given directionality is RTL, and "ltr" if it is LTR.
+ *
+ * @param isRtl Whether the directionality is RTL or not.
+ * @return "rtl" if the given directionality is RTL, and "ltr" otherwise.
+ */
+ public String dirAttrValue(boolean isRtl) {
+ return isRtl ? RTL_STRING : LTR_STRING;
+ }
+
+ /**
+ * Returns "dir=\"ltr\"" or "dir=\"rtl\"", depending on {@code str}'s estimated directionality,
+ * if it is not the same as the context directionality. Otherwise, returns the empty string.
+ *
+ * @param str String whose directionality is to be estimated.
+ * @return "dir=\"rtl\"" for RTL text in non-RTL context; "dir=\"ltr\"" for LTR text in non-LTR
+ * context; else, the empty string.
+ */
+ public String dirAttr(String str) {
+ return dirAttr(isRtl(str));
+ }
+
+ /**
+ * Operates like {@link #dirAttr(String)}, but uses a given heuristic to estimate the
+ * {@code str}'s directionality.
+ *
+ * @param str String whose directionality is to be estimated.
+ * @param heuristic The text direction heuristic that will be used to estimate the {@code str}'s
+ * directionality.
+ * @return "dir=\"rtl\"" for RTL text in non-RTL context; "dir=\"ltr\"" for LTR text in non-LTR
+ * context; else, the empty string.
+ */
+ public String dirAttr(String str, TextDirectionHeuristic heuristic) {
+ return dirAttr(heuristic.isRtl(str, 0, str.length()));
+ }
+
+ /**
+ * Returns "dir=\"ltr\"" or "dir=\"rtl\"", depending on the given directionality, if it is not
+ * the same as the context directionality. Otherwise, returns the empty string.
+ *
+ * @param isRtl Whether the directionality is RTL or not
+ * @return "dir=\"rtl\"" for RTL text in non-RTL context; "dir=\"ltr\"" for LTR text in non-LTR
+ * context; else, the empty string.
+ */
+ public String dirAttr(boolean isRtl) {
+ return (isRtl != isRtlContext) ? (isRtl ? DIR_RTL_STRING : DIR_LTR_STRING) : EMPTY_STRING;
+ }
+
+ /**
+ * Returns a Unicode bidi mark matching the context directionality (LRM or RLM) if either the
+ * overall or the exit directionality of a given string is opposite to the context directionality.
+ * Putting this after the string (including its directionality declaration wrapping) prevents it
+ * from "sticking" to other opposite-directionality text or a number appearing after it inline
+ * with only neutral content in between. Otherwise returns the empty string. While the exit
+ * directionality is determined by scanning the end of the string, the overall directionality is
+ * given explicitly in {@code dir}.
+ *
+ * @param str String after which the mark may need to appear.
+ * @return LRM for RTL text in LTR context; RLM for LTR text in RTL context;
+ * else, the empty string.
+ */
+ public String markAfter(String str) {
+ return markAfter(str, defaultTextDirectionHeuristic);
+ }
+
+ /**
+ * Operates like {@link #markAfter(String)}, but uses a given heuristic to estimate the
+ * {@code str}'s directionality.
+ *
+ * @param str String after which the mark may need to appear.
+ * @param heuristic The text direction heuristic that will be used to estimate the {@code str}'s
+ * directionality.
+ * @return LRM for RTL text in LTR context; RLM for LTR text in RTL context;
+ * else, the empty string.
+ */
+ public String markAfter(String str, TextDirectionHeuristic heuristic) {
+ final boolean isRtl = heuristic.isRtl(str, 0, str.length());
+ // getExitDir() is called only if needed (short-circuit).
+ if (!isRtlContext && (isRtl || getExitDir(str) == DIR_RTL)) {
+ return LRM_STRING;
+ }
+ if (isRtlContext && (!isRtl || getExitDir(str) == DIR_LTR)) {
+ return RLM_STRING;
+ }
+ return EMPTY_STRING;
+ }
+
+ /**
+ * Returns a Unicode bidi mark matching the context directionality (LRM or RLM) if either the
+ * overall or the entry directionality of a given string is opposite to the context
+ * directionality. Putting this before the string (including its directionality declaration
+ * wrapping) prevents it from "sticking" to other opposite-directionality text appearing before it
+ * inline with only neutral content in between. Otherwise returns the empty string. While the
+ * entry directionality is determined by scanning the beginning of the string, the overall
+ * directionality is given explicitly in {@code dir}.
+ *
+ * @param str String before which the mark may need to appear.
+ * @return LRM for RTL text in LTR context; RLM for LTR text in RTL context;
+ * else, the empty string.
+ */
+ public String markBefore(String str) {
+ return markBefore(str, defaultTextDirectionHeuristic);
+ }
+
+ /**
+ * Operates like {@link #markBefore(String)}, but uses a given heuristic to estimate the
+ * {@code str}'s directionality.
+ *
+ * @param str String before which the mark may need to appear.
+ * @param heuristic The text direction heuristic that will be used to estimate the {@code str}'s
+ * directionality.
+ * @return LRM for RTL text in LTR context; RLM for LTR text in RTL context;
+ * else, the empty string.
+ */
+ public String markBefore(String str, TextDirectionHeuristic heuristic) {
+ final boolean isRtl = heuristic.isRtl(str, 0, str.length());
+ // getEntryDir() is called only if needed (short-circuit).
+ if (!isRtlContext && (isRtl || getEntryDir(str) == DIR_RTL)) {
+ return LRM_STRING;
+ }
+ if (isRtlContext && (!isRtl || getEntryDir(str) == DIR_LTR)) {
+ return RLM_STRING;
+ }
+ return EMPTY_STRING;
+ }
+
+ /**
+ * Returns the Unicode bidi mark matching the context directionality (LRM for LTR context
+ * directionality, RLM for RTL context directionality).
+ */
+ public String mark() {
+ return isRtlContext ? RLM_STRING : LRM_STRING;
+ }
+
+ /**
+ * Returns "right" for RTL context directionality. Otherwise for LTR context directionality
+ * returns "left".
+ */
+ public String startEdge() {
+ return isRtlContext ? RIGHT : LEFT;
+ }
+
+ /**
+ * Returns "left" for RTL context directionality. Otherwise for LTR context directionality
+ * returns "right".
+ */
+ public String endEdge() {
+ return isRtlContext ? LEFT : RIGHT;
+ }
+
+ /**
+ * Estimates the directionality of a string using the default text direction heuristic.
+ *
+ * @param str String whose directionality is to be estimated.
+ * @return true if {@code str}'s estimated overall directionality is RTL. Otherwise returns
+ * false.
+ */
+ public boolean isRtl(String str) {
+ return defaultTextDirectionHeuristic.isRtl(str, 0, str.length());
+ }
+
+ /**
+ * Formats a given string of unknown directionality for use in HTML output of the context
+ * directionality, so an opposite-directionality string is neither garbled nor garbles its
+ * surroundings.
+ * <p>
+ * The algorithm: estimates the directionality of the given string using the given heuristic.
+ * If the directionality is known, pass TextDirectionHeuristics.LTR or RTL for heuristic.
+ * In case its directionality doesn't match the context directionality, wraps it with a 'span'
+ * element and adds a "dir" attribute (either 'dir=\"rtl\"' or 'dir=\"ltr\"').
+ * <p>
+ * If {@code isolate}, directionally isolates the string so that it does not garble its
+ * surroundings. Currently, this is done by "resetting" the directionality after the string by
+ * appending a trailing Unicode bidi mark matching the context directionality (LRM or RLM) when
+ * either the overall directionality or the exit directionality of the string is opposite to that
+ * of the context. If the formatter was built using {@link Builder#stereoReset(boolean)} and
+ * passing "true" as an argument, also prepends a Unicode bidi mark matching the context
+ * directionality when either the overall directionality or the entry directionality of the
+ * string is opposite to that of the context.
+ * <p>
+ *
+ * @param str The input string.
+ * @param heuristic The algorithm to be used to estimate the string's overall direction.
+ * @param isolate Whether to directionally isolate the string to prevent it from garbling the
+ * content around it.
+ * @return Input string after applying the above processing.
+ */
+ public String spanWrap(String str, TextDirectionHeuristic heuristic, boolean isolate) {
+ final boolean isRtl = heuristic.isRtl(str, 0, str.length());
+ String origStr = str;
+ str = TextUtils.htmlEncode(str);
+
+ StringBuilder result = new StringBuilder();
+ if (getStereoReset() && isolate) {
+ result.append(markBefore(origStr,
+ isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR));
+ }
+ if (isRtl != isRtlContext) {
+ result.append("<span ").append(dirAttr(isRtl)).append('>').append(str).append("</span>");
+ } else {
+ result.append(str);
+ }
+ if (isolate) {
+ result.append(markAfter(origStr,
+ isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR));
+ }
+ return result.toString();
+ }
+
+ /**
+ * Operates like {@link #spanWrap(String, TextDirectionHeuristic, boolean)}, but assumes
+ * {@code isolate} is true.
+ *
+ * @param str The input string.
+ * @param heuristic The algorithm to be used to estimate the string's overall direction.
+ * @return Input string after applying the above processing.
+ */
+ public String spanWrap(String str, TextDirectionHeuristic heuristic) {
+ return spanWrap(str, heuristic, true /* isolate */);
+ }
+
+ /**
+ * Operates like {@link #spanWrap(String, TextDirectionHeuristic, boolean)}, but uses the
+ * formatter's default direction estimation algorithm.
+ *
+ * @param str The input string.
+ * @param isolate Whether to directionally isolate the string to prevent it from garbling the
+ * content around it
+ * @return Input string after applying the above processing.
+ */
+ public String spanWrap(String str, boolean isolate) {
+ return spanWrap(str, defaultTextDirectionHeuristic, isolate);
+ }
+
+ /**
+ * Operates like {@link #spanWrap(String, TextDirectionHeuristic, boolean)}, but uses the
+ * formatter's default direction estimation algorithm and assumes {@code isolate} is true.
+ *
+ * @param str The input string.
+ * @return Input string after applying the above processing.
+ */
+ public String spanWrap(String str) {
+ return spanWrap(str, defaultTextDirectionHeuristic, true /* isolate */);
+ }
+
+ /**
+ * Formats a string of given directionality for use in plain-text output of the context
+ * directionality, so an opposite-directionality string is neither garbled nor garbles its
+ * surroundings. As opposed to {@link #spanWrap}, this makes use of Unicode bidi
+ * formatting characters. In HTML, its *only* valid use is inside of elements that do not allow
+ * markup, e.g. the 'option' and 'title' elements.
+ * <p>
+ * The algorithm: In case the given directionality doesn't match the context directionality, wraps
+ * the string with Unicode bidi formatting characters: RLE+{@code str}+PDF for RTL text, or
+ * LRE+{@code str}+PDF for LTR text.
+ * <p>
+ * If {@code isolate}, directionally isolates the string so that it does not garble its
+ * surroundings. Currently, this is done by "resetting" the directionality after the string by
+ * appending a trailing Unicode bidi mark matching the context directionality (LRM or RLM) when
+ * either the overall directionality or the exit directionality of the string is opposite to that
+ * of the context. If the formatter was built using {@link Builder#stereoReset(boolean)} and
+ * passing "true" as an argument, also prepends a Unicode bidi mark matching the context
+ * directionality when either the overall directionality or the entry directionality of the
+ * string is opposite to that of the context. Note that as opposed to the overall
+ * directionality, the entry and exit directionalities are determined from the string itself.
+ * <p>
+ * Does *not* do HTML-escaping.
+ *
+ * @param str The input string.
+ * @param heuristic The algorithm to be used to estimate the string's overall direction.
+ * @param isolate Whether to directionally isolate the string to prevent it from garbling the
+ * content around it
+ * @return Input string after applying the above processing.
+ */
+ public String unicodeWrap(String str, TextDirectionHeuristic heuristic, boolean isolate) {
+ final boolean isRtl = heuristic.isRtl(str, 0, str.length());
+ StringBuilder result = new StringBuilder();
+ if (getStereoReset() && isolate) {
+ result.append(markBefore(str,
+ isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR));
+ }
+ if (isRtl != isRtlContext) {
+ result.append(isRtl ? RLE : LRE);
+ result.append(str);
+ result.append(PDF);
+ } else {
+ result.append(str);
+ }
+ if (isolate) {
+ result.append(markAfter(str,
+ isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR));
+ }
+ return result.toString();
+ }
+
+ /**
+ * Operates like {@link #unicodeWrap(String, TextDirectionHeuristic, boolean)}, but assumes
+ * {@code isolate} is true.
+ *
+ * @param str The input string.
+ * @param heuristic The algorithm to be used to estimate the string's overall direction.
+ * @return Input string after applying the above processing.
+ */
+ public String unicodeWrap(String str, TextDirectionHeuristic heuristic) {
+ return unicodeWrap(str, heuristic, true /* isolate */);
+ }
+
+ /**
+ * Operates like {@link #unicodeWrap(String, TextDirectionHeuristic, boolean)}, but uses the
+ * formatter's default direction estimation algorithm.
+ *
+ * @param str The input string.
+ * @param isolate Whether to directionally isolate the string to prevent it from garbling the
+ * content around it
+ * @return Input string after applying the above processing.
+ */
+ public String unicodeWrap(String str, boolean isolate) {
+ return unicodeWrap(str, defaultTextDirectionHeuristic, isolate);
+ }
+
+ /**
+ * Operates like {@link #unicodeWrap(String, TextDirectionHeuristic, boolean)}, but uses the
+ * formatter's default direction estimation algorithm and assumes {@code isolate} is true.
+ *
+ * @param str The input string.
+ * @return Input string after applying the above processing.
+ */
+ public String unicodeWrap(String str) {
+ return unicodeWrap(str, defaultTextDirectionHeuristic, true /* isolate */);
+ }
+
+ /**
+ * Helper method to return true if the Locale directionality is RTL.
+ *
+ * @param locale The Locale whose directionality will be checked to be RTL or LTR
+ * @return true if the {@code locale} directionality is RTL. False otherwise.
+ */
+ private static boolean isRtlLocale(Locale locale) {
+ return (TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL);
+ }
+
+ /**
+ * Enum for directionality type.
+ */
+ private static final int DIR_LTR = -1;
+ private static final int DIR_UNKNOWN = 0;
+ private static final int DIR_RTL = +1;
+
+ /**
+ * Returns the directionality of the last character with strong directionality in the string, or
+ * DIR_UNKNOWN if none was encountered. For efficiency, actually scans backwards from the end of
+ * the string. Treats a non-BN character between an LRE/RLE/LRO/RLO and its matching PDF as a
+ * strong character, LTR after LRE/LRO, and RTL after RLE/RLO. The results are undefined for a
+ * string containing unbalanced LRE/RLE/LRO/RLO/PDF characters. The intended use is to check
+ * whether a logically separate item that starts with a number or a character of the string's
+ * exit directionality and follows this string inline (not counting any neutral characters in
+ * between) would "stick" to it in an opposite-directionality context, thus being displayed in
+ * an incorrect position. An LRM or RLM character (the one of the context's directionality)
+ * between the two will prevent such sticking.
+ *
+ * @param str the string to check.
+ */
+ private static int getExitDir(String str) {
+ return new DirectionalityEstimator(str, false /* isHtml */).getExitDir();
+ }
+
+ /**
+ * Returns the directionality of the first character with strong directionality in the string,
+ * or DIR_UNKNOWN if none was encountered. Treats a non-BN character between an
+ * LRE/RLE/LRO/RLO and its matching PDF as a strong character, LTR after LRE/LRO, and RTL after
+ * RLE/RLO. The results are undefined for a string containing unbalanced LRE/RLE/LRO/RLO/PDF
+ * characters. The intended use is to check whether a logically separate item that ends with a
+ * character of the string's entry directionality and precedes the string inline (not counting
+ * any neutral characters in between) would "stick" to it in an opposite-directionality context,
+ * thus being displayed in an incorrect position. An LRM or RLM character (the one of the
+ * context's directionality) between the two will prevent such sticking.
+ *
+ * @param str the string to check.
+ */
+ private static int getEntryDir(String str) {
+ return new DirectionalityEstimator(str, false /* isHtml */).getEntryDir();
+ }
+
+ /**
+ * An object that estimates the directionality of a given string by various methods.
+ *
+ */
+ private static class DirectionalityEstimator {
+
+ // Internal static variables and constants.
+
+ /**
+ * Size of the bidi character class cache. The results of the Character.getDirectionality()
+ * calls on the lowest DIR_TYPE_CACHE_SIZE codepoints are kept in an array for speed.
+ * The 0x700 value is designed to leave all the European and Near Eastern languages in the
+ * cache. It can be reduced to 0x180, restricting the cache to the Western European
+ * languages.
+ */
+ private static final int DIR_TYPE_CACHE_SIZE = 0x700;
+
+ /**
+ * The bidi character class cache.
+ */
+ private static final byte DIR_TYPE_CACHE[];
+
+ static {
+ DIR_TYPE_CACHE = new byte[DIR_TYPE_CACHE_SIZE];
+ for (int i = 0; i < DIR_TYPE_CACHE_SIZE; i++) {
+ DIR_TYPE_CACHE[i] = Character.getDirectionality(i);
+ }
+ }
+
+ // Internal instance variables.
+
+ /**
+ * The text to be scanned.
+ */
+ private final String text;
+
+ /**
+ * Whether the text to be scanned is to be treated as HTML, i.e. skipping over tags and
+ * entities when looking for the next / preceding dir type.
+ */
+ private final boolean isHtml;
+
+ /**
+ * The length of the text in chars.
+ */
+ private final int length;
+
+ /**
+ * The current position in the text.
+ */
+ private int charIndex;
+
+ /**
+ * The char encountered by the last dirTypeForward or dirTypeBackward call. If it
+ * encountered a supplementary codepoint, this contains a char that is not a valid
+ * codepoint. This is ok, because this member is only used to detect some well-known ASCII
+ * syntax, e.g. "http://" and the beginning of an HTML tag or entity.
+ */
+ private char lastChar;
+
+ /**
+ * Constructor.
+ *
+ * @param text The string to scan.
+ * @param isHtml Whether the text to be scanned is to be treated as HTML, i.e. skipping over
+ * tags and entities.
+ */
+ DirectionalityEstimator(String text, boolean isHtml) {
+ this.text = text;
+ this.isHtml = isHtml;
+ length = text.length();
+ }
+
+ /**
+ * Returns the directionality of the first character with strong directionality in the
+ * string, or DIR_UNKNOWN if none was encountered. Treats a non-BN character between an
+ * LRE/RLE/LRO/RLO and its matching PDF as a strong character, LTR after LRE/LRO, and RTL
+ * after RLE/RLO. The results are undefined for a string containing unbalanced
+ * LRE/RLE/LRO/RLO/PDF characters.
+ */
+ int getEntryDir() {
+ // The reason for this method name, as opposed to getFirstStrongDir(), is that
+ // "first strong" is a commonly used description of Unicode's estimation algorithm,
+ // but the two must treat formatting characters quite differently. Thus, we are staying
+ // away from both "first" and "last" in these method names to avoid confusion.
+ charIndex = 0;
+ int embeddingLevel = 0;
+ int embeddingLevelDir = DIR_UNKNOWN;
+ int firstNonEmptyEmbeddingLevel = 0;
+ while (charIndex < length && firstNonEmptyEmbeddingLevel == 0) {
+ switch (dirTypeForward()) {
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
+ ++embeddingLevel;
+ embeddingLevelDir = DIR_LTR;
+ break;
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
+ ++embeddingLevel;
+ embeddingLevelDir = DIR_RTL;
+ break;
+ case Character.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT:
+ --embeddingLevel;
+ // To restore embeddingLevelDir to its previous value, we would need a
+ // stack, which we want to avoid. Thus, at this point we do not know the
+ // current embedding's directionality.
+ embeddingLevelDir = DIR_UNKNOWN;
+ break;
+ case Character.DIRECTIONALITY_BOUNDARY_NEUTRAL:
+ break;
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+ if (embeddingLevel == 0) {
+ return DIR_LTR;
+ }
+ firstNonEmptyEmbeddingLevel = embeddingLevel;
+ break;
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+ if (embeddingLevel == 0) {
+ return DIR_RTL;
+ }
+ firstNonEmptyEmbeddingLevel = embeddingLevel;
+ break;
+ default:
+ firstNonEmptyEmbeddingLevel = embeddingLevel;
+ break;
+ }
+ }
+
+ // We have either found a non-empty embedding or scanned the entire string finding
+ // neither a non-empty embedding nor a strong character outside of an embedding.
+ if (firstNonEmptyEmbeddingLevel == 0) {
+ // We have not found a non-empty embedding. Thus, the string contains neither a
+ // non-empty embedding nor a strong character outside of an embedding.
+ return DIR_UNKNOWN;
+ }
+
+ // We have found a non-empty embedding.
+ if (embeddingLevelDir != DIR_UNKNOWN) {
+ // We know the directionality of the non-empty embedding.
+ return embeddingLevelDir;
+ }
+
+ // We do not remember the directionality of the non-empty embedding we found. So, we go
+ // backwards to find the start of the non-empty embedding and get its directionality.
+ while (charIndex > 0) {
+ switch (dirTypeBackward()) {
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
+ if (firstNonEmptyEmbeddingLevel == embeddingLevel) {
+ return DIR_LTR;
+ }
+ --embeddingLevel;
+ break;
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
+ if (firstNonEmptyEmbeddingLevel == embeddingLevel) {
+ return DIR_RTL;
+ }
+ --embeddingLevel;
+ break;
+ case Character.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT:
+ ++embeddingLevel;
+ break;
+ }
+ }
+ // We should never get here.
+ return DIR_UNKNOWN;
+ }
+
+ /**
+ * Returns the directionality of the last character with strong directionality in the
+ * string, or DIR_UNKNOWN if none was encountered. For efficiency, actually scans backwards
+ * from the end of the string. Treats a non-BN character between an LRE/RLE/LRO/RLO and its
+ * matching PDF as a strong character, LTR after LRE/LRO, and RTL after RLE/RLO. The results
+ * are undefined for a string containing unbalanced LRE/RLE/LRO/RLO/PDF characters.
+ */
+ int getExitDir() {
+ // The reason for this method name, as opposed to getLastStrongDir(), is that "last
+ // strong" sounds like the exact opposite of "first strong", which is a commonly used
+ // description of Unicode's estimation algorithm (getUnicodeDir() above), but the two
+ // must treat formatting characters quite differently. Thus, we are staying away from
+ // both "first" and "last" in these method names to avoid confusion.
+ charIndex = length;
+ int embeddingLevel = 0;
+ int lastNonEmptyEmbeddingLevel = 0;
+ while (charIndex > 0) {
+ switch (dirTypeBackward()) {
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+ if (embeddingLevel == 0) {
+ return DIR_LTR;
+ }
+ if (lastNonEmptyEmbeddingLevel == 0) {
+ lastNonEmptyEmbeddingLevel = embeddingLevel;
+ }
+ break;
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
+ if (lastNonEmptyEmbeddingLevel == embeddingLevel) {
+ return DIR_LTR;
+ }
+ --embeddingLevel;
+ break;
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+ if (embeddingLevel == 0) {
+ return DIR_RTL;
+ }
+ if (lastNonEmptyEmbeddingLevel == 0) {
+ lastNonEmptyEmbeddingLevel = embeddingLevel;
+ }
+ break;
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
+ if (lastNonEmptyEmbeddingLevel == embeddingLevel) {
+ return DIR_RTL;
+ }
+ --embeddingLevel;
+ break;
+ case Character.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT:
+ ++embeddingLevel;
+ break;
+ case Character.DIRECTIONALITY_BOUNDARY_NEUTRAL:
+ break;
+ default:
+ if (lastNonEmptyEmbeddingLevel == 0) {
+ lastNonEmptyEmbeddingLevel = embeddingLevel;
+ }
+ break;
+ }
+ }
+ return DIR_UNKNOWN;
+ }
+
+ // Internal methods
+
+ /**
+ * Gets the bidi character class, i.e. Character.getDirectionality(), of a given char, using
+ * a cache for speed. Not designed for supplementary codepoints, whose results we do not
+ * cache.
+ */
+ private static byte getCachedDirectionality(char c) {
+ return c < DIR_TYPE_CACHE_SIZE ? DIR_TYPE_CACHE[c] : Character.getDirectionality(c);
+ }
+
+ /**
+ * Returns the Character.DIRECTIONALITY_... value of the next codepoint and advances
+ * charIndex. If isHtml, and the codepoint is '<' or '&', advances through the tag/entity,
+ * and returns Character.DIRECTIONALITY_WHITESPACE. For an entity, it would be best to
+ * figure out the actual character, and return its dirtype, but treating it as whitespace is
+ * good enough for our purposes.
+ *
+ * @throws java.lang.IndexOutOfBoundsException if called when charIndex >= length or < 0.
+ */
+ byte dirTypeForward() {
+ lastChar = text.charAt(charIndex);
+ if (Character.isHighSurrogate(lastChar)) {
+ int codePoint = Character.codePointAt(text, charIndex);
+ charIndex += Character.charCount(codePoint);
+ return Character.getDirectionality(codePoint);
+ }
+ charIndex++;
+ byte dirType = getCachedDirectionality(lastChar);
+ if (isHtml) {
+ // Process tags and entities.
+ if (lastChar == '<') {
+ dirType = skipTagForward();
+ } else if (lastChar == '&') {
+ dirType = skipEntityForward();
+ }
+ }
+ return dirType;
+ }
+
+ /**
+ * Returns the Character.DIRECTIONALITY_... value of the preceding codepoint and advances
+ * charIndex backwards. If isHtml, and the codepoint is the end of a complete HTML tag or
+ * entity, advances over the whole tag/entity and returns
+ * Character.DIRECTIONALITY_WHITESPACE. For an entity, it would be best to figure out the
+ * actual character, and return its dirtype, but treating it as whitespace is good enough
+ * for our purposes.
+ *
+ * @throws java.lang.IndexOutOfBoundsException if called when charIndex > length or <= 0.
+ */
+ byte dirTypeBackward() {
+ lastChar = text.charAt(charIndex - 1);
+ if (Character.isLowSurrogate(lastChar)) {
+ int codePoint = Character.codePointBefore(text, charIndex);
+ charIndex -= Character.charCount(codePoint);
+ return Character.getDirectionality(codePoint);
+ }
+ charIndex--;
+ byte dirType = getCachedDirectionality(lastChar);
+ if (isHtml) {
+ // Process tags and entities.
+ if (lastChar == '>') {
+ dirType = skipTagBackward();
+ } else if (lastChar == ';') {
+ dirType = skipEntityBackward();
+ }
+ }
+ return dirType;
+ }
+
+ /**
+ * Advances charIndex forward through an HTML tag (after the opening < has already been
+ * read) and returns Character.DIRECTIONALITY_WHITESPACE. If there is no matching >,
+ * does not change charIndex and returns Character.DIRECTIONALITY_OTHER_NEUTRALS (for the
+ * < that hadn't been part of a tag after all).
+ */
+ private byte skipTagForward() {
+ int initialCharIndex = charIndex;
+ while (charIndex < length) {
+ lastChar = text.charAt(charIndex++);
+ if (lastChar == '>') {
+ // The end of the tag.
+ return Character.DIRECTIONALITY_WHITESPACE;
+ }
+ if (lastChar == '"' || lastChar == '\'') {
+ // Skip over a quoted attribute value inside the tag.
+ char quote = lastChar;
+ while (charIndex < length && (lastChar = text.charAt(charIndex++)) != quote) {}
+ }
+ }
+ // The original '<' wasn't the start of a tag after all.
+ charIndex = initialCharIndex;
+ lastChar = '<';
+ return Character.DIRECTIONALITY_OTHER_NEUTRALS;
+ }
+
+ /**
+ * Advances charIndex backward through an HTML tag (after the closing > has already been
+ * read) and returns Character.DIRECTIONALITY_WHITESPACE. If there is no matching <, does
+ * not change charIndex and returns Character.DIRECTIONALITY_OTHER_NEUTRALS (for the >
+ * that hadn't been part of a tag after all). Nevertheless, the running time for calling
+ * skipTagBackward() in a loop remains linear in the size of the text, even for a text like
+ * ">>>>", because skipTagBackward() also stops looking for a matching <
+ * when it encounters another >.
+ */
+ private byte skipTagBackward() {
+ int initialCharIndex = charIndex;
+ while (charIndex > 0) {
+ lastChar = text.charAt(--charIndex);
+ if (lastChar == '<') {
+ // The start of the tag.
+ return Character.DIRECTIONALITY_WHITESPACE;
+ }
+ if (lastChar == '>') {
+ break;
+ }
+ if (lastChar == '"' || lastChar == '\'') {
+ // Skip over a quoted attribute value inside the tag.
+ char quote = lastChar;
+ while (charIndex > 0 && (lastChar = text.charAt(--charIndex)) != quote) {}
+ }
+ }
+ // The original '>' wasn't the end of a tag after all.
+ charIndex = initialCharIndex;
+ lastChar = '>';
+ return Character.DIRECTIONALITY_OTHER_NEUTRALS;
+ }
+
+ /**
+ * Advances charIndex forward through an HTML character entity tag (after the opening
+ * & has already been read) and returns Character.DIRECTIONALITY_WHITESPACE. It would be
+ * best to figure out the actual character and return its dirtype, but this is good enough.
+ */
+ private byte skipEntityForward() {
+ while (charIndex < length && (lastChar = text.charAt(charIndex++)) != ';') {}
+ return Character.DIRECTIONALITY_WHITESPACE;
+ }
+
+ /**
+ * Advances charIndex backward through an HTML character entity tag (after the closing ;
+ * has already been read) and returns Character.DIRECTIONALITY_WHITESPACE. It would be best
+ * to figure out the actual character and return its dirtype, but this is good enough.
+ * If there is no matching &, does not change charIndex and returns
+ * Character.DIRECTIONALITY_OTHER_NEUTRALS (for the ';' that did not start an entity after
+ * all). Nevertheless, the running time for calling skipEntityBackward() in a loop remains
+ * linear in the size of the text, even for a text like ";;;;;;;", because skipTagBackward()
+ * also stops looking for a matching & when it encounters another ;.
+ */
+ private byte skipEntityBackward() {
+ int initialCharIndex = charIndex;
+ while (charIndex > 0) {
+ lastChar = text.charAt(--charIndex);
+ if (lastChar == '&') {
+ return Character.DIRECTIONALITY_WHITESPACE;
+ }
+ if (lastChar == ';') {
+ break;
+ }
+ }
+ charIndex = initialCharIndex;
+ lastChar = ';';
+ return Character.DIRECTIONALITY_OTHER_NEUTRALS;
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index e856501..dae47b8 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -74,6 +74,15 @@
public static final int DENSITY_XXHIGH = 480;
/**
+ * Standard quantized DPI for extra-extra-extra-high-density screens. Applications
+ * should not generally worry about this density; relying on XHIGH graphics
+ * being scaled up to it should be sufficient for almost all cases. A typical
+ * use of this density would be 4K television screens -- 3840x2160, which
+ * is 2x a traditional HD 1920x1080 screen which runs at DENSITY_XHIGH.
+ */
+ public static final int DENSITY_XXXHIGH = 640;
+
+ /**
* The reference density used throughout the system.
*/
public static final int DENSITY_DEFAULT = DENSITY_MEDIUM;
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 85ed8db..12cce8b 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -1235,6 +1235,7 @@
Assoc<Spec, Bounds> assoc = Assoc.of(Spec.class, Bounds.class);
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
+ if (c.getVisibility() == View.GONE) continue;
LayoutParams lp = getLayoutParams(c);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
Bounds bounds = getAlignment(spec.alignment, horizontal).getBounds();
@@ -1250,6 +1251,7 @@
}
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
+ if (c.getVisibility() == View.GONE) continue;
LayoutParams lp = getLayoutParams(c);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
groupBounds.getValue(i).include(GridLayout.this, c, spec, this);
diff --git a/core/java/com/android/internal/app/IAppOpsCallback.aidl b/core/java/com/android/internal/app/IAppOpsCallback.aidl
index 4e75a61..afbc609 100644
--- a/core/java/com/android/internal/app/IAppOpsCallback.aidl
+++ b/core/java/com/android/internal/app/IAppOpsCallback.aidl
@@ -16,6 +16,8 @@
package com.android.internal.app;
+// This interface is also used by native code, so must
+// be kept in sync with frameworks/native/include/binder/IAppOpsCallback.h
oneway interface IAppOpsCallback {
void opChanged(int op, String packageName);
}
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 83967f6..a9da863 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -20,13 +20,17 @@
import com.android.internal.app.IAppOpsCallback;
interface IAppOpsService {
- List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
- List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
- void setMode(int code, int uid, String packageName, int mode);
+ // These first methods are also called by native code, so must
+ // be kept in sync with frameworks/native/include/binder/IAppOpsService.h
int checkOperation(int code, int uid, String packageName);
int noteOperation(int code, int uid, String packageName);
int startOperation(int code, int uid, String packageName);
void finishOperation(int code, int uid, String packageName);
void startWatchingMode(int op, String packageName, IAppOpsCallback callback);
void stopWatchingMode(IAppOpsCallback callback);
+
+ // Remaining methods are only used in Java.
+ List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
+ List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
+ void setMode(int code, int uid, String packageName, int mode);
}
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 6641f2c..28fd05f 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -820,7 +820,7 @@
* and we won't log special messages SM_INIT_CMD or SM_QUIT_CMD which
* always set msg.obj to the handler.
*/
- boolean recordLogMsg = mSm.recordLogRec(mMsg) && (msg.obj == mSmHandlerObj);
+ boolean recordLogMsg = mSm.recordLogRec(mMsg) && (msg.obj != mSmHandlerObj);
if (mLogRecords.logOnlyTransitions()) {
/** Record only if there is a transition */
diff --git a/core/res/Android.mk b/core/res/Android.mk
index 22f4fdc..cfc791d 100644
--- a/core/res/Android.mk
+++ b/core/res/Android.mk
@@ -42,7 +42,3 @@
# Make sure the system .rs files get compiled before building the package-export.apk.
# $(resource_export_package): $(framework_RenderScript_STAMP_FILE)
-
-# define a global intermediate target that other module may depend on.
-.PHONY: framework-res-package-target
-framework-res-package-target: $(LOCAL_BUILT_MODULE)
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 960232a..c1cb9d59 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дазваляе прыкладаннм кіраваць сеткавымі палітыкамі і вызначаць правілы пэўных прыкладанняў."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"змяніць улік выкарыстання сеткі"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дазваляе прыкладанням змяняць метад уліку выкарыстання сеткі прыкладаннямі. Не для выкарыстання звычайнымі прыкладаннямі."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"доступ да паведамленняў"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дазваляе прыкладанню атрымлiваць, правяраць i выдаляць апавяшчэннi, у тым лiку апублiкаваныя iншымi прыкладаннямi."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Устанавіць правілы паролю"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Кіраванне даўжынёй і колькасцю знакаў у паролі разблакоўкі экрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Сачыць за спробамі разблакоўкі экрана"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 7f351da..158134e 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Разрешава на приложението да управлява правилата на мрежата и да определя такива за конкретно приложение."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"промяна на отчетността на употребата на мрежа"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Разрешава на приложението да променя това как употребата на мрежа се отчита спрямо приложенията. Не е предназначено за нормални приложения."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"достъп до известията"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Разрешава на приложението да извлича, преглежда и изчиства известия, включително публикуваните от други приложения."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Задаване на правила за паролата"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролирайте дължината и разрешените знаци за паролите за отключване на екрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Наблюдаване на опитите за отключване на екрана"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index de1f9aa..e3ee35d 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permet que l\'aplicació gestioni les polítiques de la xarxa i que defineixi les regles específiques d\'aplicació."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificació del càlcul d\'ús de la xarxa"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permet que l\'aplicació modifiqui la manera com es calcula l\'ús de la xarxa per part de les aplicacions. No indicat per a les aplicacions normals."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"accedeix a les notificacions"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet que l\'aplicació recuperi, examini i esborri les notificacions, incloses les que han publicat altres aplicacions."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Defineix les normes de contrasenya"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controla la longitud i els caràcters permesos a les contrasenyes de desbloqueig de pantalla."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Control d\'intents de desbloqueig de pantalla"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 0b1715e..35798a4 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Umožňuje aplikaci spravovat zásady sítě a definovat pravidla pro konkrétní aplikace."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"upravit kontrolu používání sítě"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Umožňuje aplikaci upravit způsob výpočtu využití sítě aplikacemi. Toto oprávnění není určeno pro běžné aplikace."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"přístup k oznámením"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikacím načítat, zobrazovat a mazat oznámení včetně těch přidaných jinými aplikacemi."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavit pravidla pro heslo"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Řídit délku hesel pro odemčení obrazovky a povolené znaky."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Sledovat pokusy o odemčení obrazovky"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 860a9be..477f313 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillader, at appen kan administrere netværkspolitikker og definere appspecifikke regler."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"skift afregning af netværksbrug"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillader, at appen kan ændre den måde, som netværksforbrug udregnes på i forhold til apps. Anvendes ikke af normale apps."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"adgang til underretninger"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde underretninger, herunder dem, der er sendt af andre apps."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Indstil regler for adgangskode"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller længden samt tilladte tegn i adgangskoder til oplåsning af skærmen."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 3a8c6ab..770cc61 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ermöglicht der App, Netzwerkrichtlinien zu verwalten und anwendungsspezifische Regeln festzulegen"</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Zuordnung für Netzwerknutzung ändern"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ermöglicht der App, die Art und Weise zu ändern, wie der Netzwerkverbrauch im Hinblick auf Apps berechnet wird. Nicht für normale Apps vorgesehen."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"Auf Benachrichtigungen zugreifen"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ermöglicht der App das Abrufen, Überprüfen und Löschen von Benachrichtigungen, einschließlich Benachrichtigungen, die von anderen Apps gepostet wurden"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Zulässige Länge und Zeichen für Passwörter zum Entsperren des Bildschirms festlegen"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 9f7399b..40fc411 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Επιτρέπει στην εφαρμογή τη διαχείριση των πολιτικών δικτύου και τον ορισμό κανόνων για ορισμένες εφαρμογές."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"τροποποίηση υπολογισμού χρήσης δικτύου"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Επιτρέπει στην εφαρμογή την τροποποίηση του τρόπου υπολογισμού της χρήσης δικτύου έναντι των εφαρμογών. Δεν προορίζεται για χρήση από συνήθεις εφαρμογές."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"πρόσβαση στις ειδοποιήσεις"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Έλεγχος του μεγέθους και των χαρακτήρων που επιτρέπονται στους κωδικούς πρόσβασης ξεκλειδώματος οθόνης."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index ec2a60e..4af1886 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Allows the app to manage network policies and define app-specific rules."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modify network usage accounting"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Allows the app to modify how network usage is accounted against apps. Not for use by normal apps."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"access notifications"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Allows the app to retrieve, examine, and clear notifications, including those posted by other apps."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index c6be92d..8517662 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que la aplicación administre las políticas de red y defina reglas específicas de la aplicación."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Modificar la administración del uso de redes"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y elimine notificaciones, incluidas aquellas publicadas por otras aplicaciones."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer reglas de contraseña"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas para desbloquear la pantalla"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 6c0761c..2b657c8 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que la aplicación administre políticas de red y defina reglas específicas de la aplicación."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar cálculo de uso de red"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y borre notificaciones, incluidas las que han publicado otras aplicaciones."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas de bloqueo de pantalla"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Control de intentos de bloqueo de pantalla"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 26482bd..3303f00 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Võimaldab rakendusel hallata võrgueeskirju ja määratleda rakendusespetsiifilisi reegleid."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"võrgukasutuse arvestamise muutmine"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Võimaldab rakendusel muuta võrgukasutuse loendamist rakenduste suhtes. Mitte kasutada tavarakenduste puhul."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"juurdepääsu märguanded"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Võimaldab rakendusel tuua, kontrollida ja kustutada märguandeid, sh neid, mille on postitanud teised rakendused."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrollige ekraaniluku avamise paroolide pikkust ja tähemärke."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 5e8ac2b..b4a15c5 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"به برنامه اجازه میدهد تا خط مشیهای شبکه را مدیریت کند و قوانین خاص برنامه را تعیین کند."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"اصلاح محاسبه استفاده از شبکه"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"به برنامه اجازه میدهد تا نحوه محاسبه کاربرد شبکه در برنامه را تغییر دهد. برای استفاده برنامههای عادی نیست."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"اعلانهای دسترسی"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه میدهد به بازیابی، بررسی و پاک کردن اعلانها از جمله موارد پست شده توسط سایر برنامهها بپردازد."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"طول و نویسههای مجاز در گذرواژههای بازکردن قفل صفحه را کنترل کنید."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاشهای قفل گشایی صفحه"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 43cd8ab..45f4a05 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Sallii sovelluksen hallinnoida verkkokäytäntöjä ja määritellä sovelluskohtaisia sääntöjä."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verkon käytön seurannan muokkaaminen"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Antaa sovelluksen muokata, miten sovellusten verkonkäyttöä lasketaan. Ei tavallisten sovellusten käyttöön."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"käytä ilmoituksia"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Antaa sovelluksen noutaa, tutkia ja tyhjentää ilmoituksia (myös muiden sovelluksien lähettämiä)."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Aseta salasanasäännöt"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Hallinnoi ruudun lukituksenpoistosalasanoissa sallittuja merkkejä ja salasanan pituutta."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Tarkkaile ruudun lukituksen poistoyrityksiä"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index b5d2d2b..c94946e 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permet à l\'application de gérer les stratégies du réseau et de définir celles qui sont spécifiques à l\'application."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modifier le système de comptabilisation de l\'utilisation du réseau"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permet à l\'application de modifier l\'utilisation du réseau par les autres applications. Les applications standards ne doivent pas utiliser cette fonctionnalité."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"accéder aux notifications"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 8175fa4..3521f4b 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"एप्लिकेशन को नेटवर्क नीतियां प्रबंधित करने और एप्लिकेशन-विशिष्ट नियमों को परिभाषित करने देता है."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"नेटवर्क उपयोग हिसाब बदलें"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"एप्लिकेशन को यह संशोधित करने देता है कि एप्लिकेशन की तुलना में नेटवर्क उपयोग का मूल्यांकन कैसे किया जाता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"सूचनाओं तक पहुंचें"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"एप्लिकेशन को सूचनाओं को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य एप्लिकेशन के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"स्क्रीन-अनलॉक पासवर्ड में अनुमति प्राप्त लंबाई और वर्णों को नियंत्रित करें."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"स्क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 4773c941..ce7e954 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Aplikaciji omogućuje upravljanje mrežnim pravilima i određivanje pravila za aplikacije."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"izmjena evidencije mrežne upotrebe"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Omogućuje aplikaciji izmjenu načina upotrebe mreže u odnosu na aplikacije. Nije namijenjeno uobičajenim aplikacijama."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"pristup obavijestima"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Omogućuje aplikaciji dohvaćanje, pregledavanje i brisanje obavijesti, uključujući obavijesti drugih aplikacija."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Upravljajte duljinom zaporki za otključavanje zaslona i dopuštenim znakovima u tim zaporkama."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index a6ea0f6..a472123 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Lehetővé teszi az alkalmazás számára, hogy kezelje a hálózati irányelveket és meghatározza az alkalmazásspecifikus szabályokat."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"hálózathasználat elszámolásának módosítása"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lehetővé teszi az alkalmazás számára annak módosítását, hogy a hálózathasználatot hogyan számolják el az alkalmazások esetében. Normál alkalmazások nem használhatják."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"hozzáférési értesítések"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lehetővé teszi, hogy az alkalmazás értesítéseket kérdezzen le, vizsgáljon és tisztítson meg, beleértve az egyéb alkalmazások által közzétett értesítéseket is."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"A képernyőzár-feloldási jelszavakban engedélyezett karakterek és hosszúság vezérlése."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 72199a1..d0b4d61 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Mengizinkan apl mengelola kebijakan jaringan dan menentukan peraturan khusus apl."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"mengubah penghitungan penggunaan jaringan"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Mengizinkan apl memodifikasi cara penggunaan jaringan diperhitungkan terhadap apl. Tidak untuk digunakan oleh apl normal."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"mengakses pemberitahuan"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Mengizinkan aplikasi mengambil, memeriksa, dan menghapus pemberitahuan, termasuk pemberitahuan yang diposkan oleh aplikasi lain."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Setel aturan sandi"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrol panjang dan karakter yang diizinkan dalam sandi pembuka layar."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Upaya pembukaan kunci layar monitor"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 1c95e73..87d21fe 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Consente all\'applicazione di gestire le norme di rete e definire le regole specifiche delle applicazioni."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modifica calcolo dell\'utilizzo della rete"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Consente all\'applicazione di modificare il calcolo dell\'utilizzo della rete tra le applicazioni. Da non usare per normali applicazioni."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesso a notifiche"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Consente all\'app di recuperare, esaminare e cancellare notifiche, comprese quelle pubblicate da altre app."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Imposta regole password"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlla la lunghezza e i caratteri ammessi nelle password di sblocco dello schermo."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitora tentativi di sblocco dello schermo"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 333aaa9..1dfdf97 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"앱이 네트워크 정책을 관리하고 앱별 규칙을 정의할 수 있도록 허용합니다."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"네트워크 사용량 계산 수정"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"애플리케이션이 애플리케이션의 네트워크 사용량을 계산하는 방식을 수정할 수 있도록 허용합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"액세스 알림"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"앱이 다른 앱에서 게시한 알림을 비롯하여 알림을 검색하고 살펴보며 삭제할 수 있도록 허용합니다."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"비밀번호 규칙 설정"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"화면 잠금해제 비밀번호에 허용되는 길이 및 문자 수를 제어합니다."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"화면 잠금해제 시도 모니터링"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index a3460d16..3b6e440 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Leidžiama programai valdyti tinklo politiką ir apibrėžti konkrečios programos taisykles."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"keisti tinklo naudojimo apskaitą"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Leidžiama programai keisti, kaip tinklas naudojamas, palyginti su programomis. Neskirta naudoti įprastoms programoms."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"pasiekti pranešimus"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Programai leidžiama gauti, patikrinti ir išvalyti pranešimus, įskaitant pranešimus, kuriuos paskelbė kitos programos."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nustatyti slaptažodžio taisykles"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Valdyti leidžiamą ekrano atrakinimo slaptažodžių ilgį ir leidžiamus naudoti simbolius."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Stebėti bandymus atrakinti ekraną"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index e92fa7d..646b7fa 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ļauj lietotnei pārvaldīt tīkla politikas un noteikt lietotnes kārtulas."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Tīkla lietojuma uzskaites mainīšana"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ļauj lietotnei mainīt to, kā tīkla lietojums tiek uzskaitīts saistībā ar lietotnēm. Atļauja neattiecas uz parastām lietotnēm."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"piekļuve paziņojumiem"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ļauj lietotnei izgūt, pārbaudīt un dzēst paziņojumus, tostarp lietotņu publicētos paziņojumus."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Paroles kārtulu iestatīšana"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolē ekrāna atbloķēšanas parolē atļautās rakstzīmes un garumu."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 0f30f40..784a424 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Membenarkan apl mengurus dasar rangkaian dan menentukan peraturan khusus apl."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ubah suai perakaunan penggunaan rangkaian"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Membenarkan apl untuk mengubah suai bagaimana penggunaan rangkaian diambil kira terhadap apl. Bukan untuk digunakan oleh apl biasa."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"pemberitahuan akses"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Membenarkan apl untuk mendapatkan semula, memeriksa dan memadam bersih pemberitahuan, termasuk yang disiarkan oleh apl lain."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan buka kunci skrin."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 1cb41c4..485a11f8 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Lar appen administrere retningslinjene for nettverket og definere appspesifikke regler."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Modifisering av regnskapsføring av nettverksbruk"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lar appen endre hvordan nettverksbruk regnes ut for apper. Ikke beregnet på vanlige apper."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"varseltilgang"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lar appen hente, gjennomgå og fjerne varsler, inkludert de som sendes fra andre apper."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller tillatt lengde og tillatte tegn i passord for opplåsing av skjerm."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 757a813..95da93b 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Hiermee kan de app het netwerkbeleid beheren en app-specifieke regels definiëren."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verrekening van netwerkgebruik aanpassen"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Hiermee kan een app aanpassen hoe het netwerkgebruik wordt toegekend aan apps. Dit wordt niet gebruikt door normale apps."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"toegang tot meldingen"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Hiermee kan de app meldingen ophalen, onderzoeken en wissen, waaronder meldingen die zijn verzonden door andere apps."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"De lengte en tekens beheren die zijn toegestaan in wachtwoorden voor schermontgrendeling."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index a5405de..f15c106 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Pozwala aplikacji na zarządzanie zasadami dotyczącymi sieci i definiowanie reguł aplikacji."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modyfikowanie sposobu naliczania użycia sieci"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Pozwala aplikacji na zmienianie sposobu rozliczania wykorzystania sieci przez aplikacje. Nieprzeznaczone dla zwykłych aplikacji."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"dostęp do powiadomień"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umożliwia aplikacji pobieranie, sprawdzanie i usuwanie powiadomień, także tych, które pochodzą z innych aplikacji."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Określ reguły hasła"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolowanie długości haseł odblokowania ekranu i dozwolonych w nich znaków"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitoruj próby odblokowania ekranu"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 28b6f9d..186eb3e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que a aplicação faça a gestão de políticas de rede e defina regras específicas de aplicações."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar contabilização da utilização da rede"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que a aplicação modifique o modo como a utilização da rede é contabilizada em relação a aplicações. Nunca é necessário para aplicações normais."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"aceder às notificações"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que a aplicação obtenha, examine e limpe notificações, incluindo as que foram publicadas por outras aplicações."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras de palavra-passe"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o comprimento e os caracteres permitidos nas palavras-passe de desbloqueio do ecrã."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizar tentativas de desbloqueio do ecrã"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index bcec57e..a2c6675 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que o aplicativo gerencie políticas de rede e definia regras específicas para o aplicativo."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar contagem de uso da rede"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que o aplicativo modifique como o uso da rede é contabilizado em relação aos aplicativos. Não deve ser usado em aplicativos normais."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"acessar notificações"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que o aplicativo recupere, examine e limpe notificações, inclusive as postadas por outros aplicativos."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras para senha"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controle o tamanho e os caracteres permitidos nas senhas de desbloqueio de tela."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitorar tentativas de desbloqueio da tela"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 52fee9b..e6d142b 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite aplicaţiei să gestioneze politicile de reţea şi să definească regulile specifice aplicaţiilor."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificaţi modul de calcul al utilizării reţelei"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite aplicaţiei să modifice modul în care este calculată utilizarea reţelei pentru aplicaţii. Nu se utilizează de aplicaţiile obişnuite."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesare notificări"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 741d78f..fa623e0 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Приложение сможет управлять сетевыми политиками и определять правила для отдельных приложений."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"изменение учета использования сети"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Приложение сможет изменять порядок расчета использования сетевых ресурсов различными программами. Это разрешение не используется обычными приложениями."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"доступ к уведомлениям"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Приложение сможет получать, проверять и удалять уведомления, включая те, что опубликованы другими приложениями."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Правила выбора паролей"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролировать длину и символы при вводе паролей для снятия блокировки экрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Отслеживать попытки снятия блокировки экрана"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index e0126da..5f49e68 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Umožňuje aplikácii spravovať pravidlá siete a definovať pravidlá pre konkrétnu aplikáciu."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"zmeniť kontrolu používania siete"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Umožňuje aplikácii upraviť používanie siete jednotlivými aplikáciami. Bežné aplikácie toto nastavenie nepoužívajú."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"prístup k upozorneniam"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikácii načítať, zobrazovať a mazať upozornenia vrátane tých, ktoré boli uverejnené inými aplikáciami."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nastaviť pravidlá pre heslo"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Ovládanie dĺžky hesiel na odomknutie obrazovky a v nich používané znaky."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Sledovať pokusy o odomknutie obrazovky"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 73d308c..aa240de 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Programu omogoča upravljanje pravilnikov o omrežju in določanje pravil za program."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"spremeni obračunavanje uporabe omrežja"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Programu omogoča, da spremeni uporabo omrežja na podlagi programov. Ni za uporabo z navadnimi programi."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"dostop do obvestil"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Dovoli aplikaciji, da prenese, razišče in izbriše obvestila, tudi tista, ki so jih objavile druge aplikacije."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavitev pravil za geslo"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih za odklepanje zaslona."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"nadzor nad poskusi odklepanja zaslona"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 127d5eb..7a3ff07 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дозвољава апликацији да управља смерницама за мрежу и одређује посебна правила за апликацију."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"измените обрачунавање коришћења мреже"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозвољава апликацији да измени начин на који апликације користе мрежу. Не користе је уобичајене апликације."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"приступ обавештењима"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролишите дужину и знакове дозвољене у лозинкама за откључавање екрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Надгледање покушаја откључавања екрана"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index aab6047..eca52e6 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillåter att appen hanterar nätverkspolicyer och definierar appspecifika regler."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ändra nätverksredovisningen"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillåter att appen ändrar hur nätverksanvändning redovisas för appar. Används inte av vanliga appar."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"få åtkomst till meddelanden"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillåter att appen hämtar, granskar och raderar meddelanden, även sådana som skickats av andra appar."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Ange lösenordsregler"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Bestäm hur många och vilka tecken som är tillåtna i skärmlåsets lösenord."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Övervaka försök att låsa upp skärmen"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 109566f..d0b1510 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Inaruhusu programu kudhibiti sera za mtandao na kufafanua sheria maalum za programu."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"badilisha uthibitishaji wa matumizi ya mtandao"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Huruhusu programu kurekebisha jinsi matumizi ya mtandao yana hesabika dhidi ya programu. Sio ya matumizi na programu za kawaida."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"fikia arifa"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Huruhusu programu kurejesha, kuchunguza, na kuondoa arifa, ikiwa ni pamoja na zile zilizochapishwa na programu nyingine."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Weka kanuni za nenosiri"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Dhibiti urefu na vibambo vinavyoruhusiwa katika manenosiri ya kufungua skrini."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Chunguza majaribio ya kutofun gua skrini"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index e7d4b4f..e7df782 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"อนุญาตให้แอปพลิเคชันจัดการนโยบายเครือข่ายและกำหนดกฎเฉพาะแอปพลิเคชัน"</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"แก้ไขการบันทึกบัญชีการใช้งานเครือข่าย"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"อนุญาตให้แอปพลิเคชันแก้ไขวิธีการบันทึกบัญชีการใช้งานเครือข่ายของแอปพลิเคชัน ไม่ใช้สำหรับแอปพลิเคชันทั่วไป"</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"เข้าถึงการแจ้งเตือน"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกคืน ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"ควบคุมความยาวและอักขระที่อนุญาตให้ใช้ในรหัสผ่านการปลดล็อกหน้าจอ"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 0021828..6268786 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Pinapayagan ang app na pamahalaan ang mga patakaran ng network at ilarawan ang mga patakarang tukoy sa app."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"baguhin ang pagkukuwenta sa paggamit ng network"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Pinapayagan ang app na baguhin kung paano isinasaalang-alang ang paggamit ng network laban sa apps. Hindi para sa paggamit ng normal na apps."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"i-access ang mga notification"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Pinapayagan ang app na kumuha, sumuri, at mag-clear ng mga notification, kabilang ang mga na-post ng iba pang apps."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Magtakda ng mga panuntunan sa password"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolin ang haba at mga character na pinapayagan sa mga password sa pag-unlock ng screen."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index e2c505b..21fe6d4 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Uygulamaya, ağ politikalarını yönetme ve uygulamaya özgü kuralları tanımlama izni verir."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ağ kullanım hesaplamasını değiştir"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Uygulamaya, ağın uygulamalara göre nasıl kullanılacağını değiştirme izni verir. Normal uygulamalar tarafından kullanılmak için değildir."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"bildirimlere eriş"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Uygulamanın bildirimler almasına, bildirimleri incelemesine ve temizlemesine izin verir. Buna diğer uygulamalar tarafından yayınlanan bildirimler de dahildir."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Şifre kuralları ayarla"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Ekran kilidini açma şifrelerinde izin verilen uzunluğu ve karakterleri denetleme."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidini açma denemelerini izle"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 0563f8c..7f80706 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дозволяє програмі керувати політикою мережі та визначити спеціальні правила для програм."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"змінювати облік використання мережі"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозволяє програмі змінювати метод підрахунку того, як програми використовують мережу. Не для використання звичайними програмами."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"отримувати доступ до сповіщень"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролювати довжину паролів для розблокування екрана та дозволені в них символи."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Відстежув. спроби розблок. екрана"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index e4da91a..1406064 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"允许应用管理网络政策和定义专门针对应用的规则。"</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"修改网络使用情况记录方式"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"允许该应用修改对于各应用的网络使用情况的统计方式。普通应用不应使用此权限。"</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"查看通知"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解锁密码所允许的长度和字符。"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"监视屏幕解锁尝试次数"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 757ed6c..30893c6 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -617,10 +617,8 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ivumela insiza ukuthi yengamele iigomo iphinde ichaze imithetho ehambisana ngqo nensiza."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"lungisa ukubala kokusebenza kohleloxhumano"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ivumela insiza ukuthi iguqule ukuthii ukusetshenziswa kwenethiwekhi kumiswa kanjani ezinsizeni. Ayisetshenziswa izinsiza ezijwayelekile."</string>
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"finyelela kuzaziso"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ivumela uhlelo lokusebenza ukuthi lithole, lihlole, liphinde lisuse izaziso, ezifaka lezo ezithunyelwe ezinye izinhlelo zokusebenza."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Misa imithetho yephasiwedi"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi okuvula isikrini"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Gaka imizamo yokuvula isikrini"</string>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index 649e39d..0461c0b 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -213,8 +213,8 @@
config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
// Initialize other fields.
config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
- config.enterpriseConfig.setCaCertificate("");
- config.enterpriseConfig.setClientCertificate("");
+ config.enterpriseConfig.setCaCertificateAlias("");
+ config.enterpriseConfig.setClientCertificateAlias("");
config.enterpriseConfig.setIdentity("");
config.enterpriseConfig.setAnonymousIdentity("");
break;
@@ -288,12 +288,12 @@
}
if (cacert) {
String cacertValue = new String(ch, start, length);
- config.enterpriseConfig.setCaCertificate(cacertValue);
+ config.enterpriseConfig.setCaCertificateAlias(cacertValue);
cacert = false;
}
if (usercert) {
String usercertValue = new String(ch, start, length);
- config.enterpriseConfig.setClientCertificate(usercertValue);
+ config.enterpriseConfig.setClientCertificateAlias(usercertValue);
usercert = false;
}
if (ip) {
diff --git a/docs/html/reference/gcm-lists.js b/docs/html/reference/gcm-lists.js
new file mode 100644
index 0000000..44c6023
--- /dev/null
+++ b/docs/html/reference/gcm-lists.js
@@ -0,0 +1,16 @@
+var GCM_DATA = [
+ { id:0, label:"com.google.android.gcm", link:"reference/com/google/android/gcm/package-summary.html", type:"package" },
+ { id:1, label:"com.google.android.gcm.GCMBaseIntentService", link:"reference/com/google/android/gcm/GCMBaseIntentService.html", type:"class" },
+ { id:2, label:"com.google.android.gcm.GCMBroadcastReceiver", link:"reference/com/google/android/gcm/GCMBroadcastReceiver.html", type:"class" },
+ { id:3, label:"com.google.android.gcm.GCMConstants", link:"reference/com/google/android/gcm/GCMConstants.html", type:"class" },
+ { id:4, label:"com.google.android.gcm.GCMRegistrar", link:"reference/com/google/android/gcm/GCMRegistrar.html", type:"class" },
+ { id:5, label:"com.google.android.gcm.server", link:"reference/com/google/android/gcm/server/package-summary.html", type:"package" },
+ { id:6, label:"com.google.android.gcm.server.Constants", link:"reference/com/google/android/gcm/server/Constants.html", type:"class" },
+ { id:7, label:"com.google.android.gcm.server.InvalidRequestException", link:"reference/com/google/android/gcm/server/InvalidRequestException.html", type:"class" },
+ { id:8, label:"com.google.android.gcm.server.Message", link:"reference/com/google/android/gcm/server/Message.html", type:"class" },
+ { id:9, label:"com.google.android.gcm.server.Message.Builder", link:"reference/com/google/android/gcm/server/Message.Builder.html", type:"class" },
+ { id:10, label:"com.google.android.gcm.server.MulticastResult", link:"reference/com/google/android/gcm/server/MulticastResult.html", type:"class" },
+ { id:11, label:"com.google.android.gcm.server.Result", link:"reference/com/google/android/gcm/server/Result.html", type:"class" },
+ { id:12, label:"com.google.android.gcm.server.Sender", link:"reference/com/google/android/gcm/server/Sender.html", type:"class" }
+
+ ];
diff --git a/docs/html/reference/gms-lists.js b/docs/html/reference/gms-lists.js
new file mode 100644
index 0000000..a5999f7
--- /dev/null
+++ b/docs/html/reference/gms-lists.js
@@ -0,0 +1,93 @@
+var GMS_DATA = [
+ { id:0, label:"com.google.android.gms", link:"reference/com/google/android/gms/package-summary.html", type:"package" },
+ { id:1, label:"com.google.android.gms.R", link:"reference/com/google/android/gms/R.html", type:"class" },
+ { id:2, label:"com.google.android.gms.R.attr", link:"reference/com/google/android/gms/R.attr.html", type:"class" },
+ { id:3, label:"com.google.android.gms.R.id", link:"reference/com/google/android/gms/R.id.html", type:"class" },
+ { id:4, label:"com.google.android.gms.R.string", link:"reference/com/google/android/gms/R.string.html", type:"class" },
+ { id:5, label:"com.google.android.gms.R.styleable", link:"reference/com/google/android/gms/R.styleable.html", type:"class" },
+ { id:6, label:"com.google.android.gms.analytics", link:"reference/com/google/android/gms/analytics/package-summary.html", type:"package" },
+ { id:7, label:"com.google.android.gms.analytics.CampaignTrackingReceiver", link:"reference/com/google/android/gms/analytics/CampaignTrackingReceiver.html", type:"class" },
+ { id:8, label:"com.google.android.gms.analytics.CampaignTrackingService", link:"reference/com/google/android/gms/analytics/CampaignTrackingService.html", type:"class" },
+ { id:9, label:"com.google.android.gms.analytics.EasyTracker", link:"reference/com/google/android/gms/analytics/EasyTracker.html", type:"class" },
+ { id:10, label:"com.google.android.gms.analytics.ExceptionParser", link:"reference/com/google/android/gms/analytics/ExceptionParser.html", type:"class" },
+ { id:11, label:"com.google.android.gms.analytics.GoogleAnalytics", link:"reference/com/google/android/gms/analytics/GoogleAnalytics.html", type:"class" },
+ { id:12, label:"com.google.android.gms.analytics.GoogleAnalytics.AppOptOutCallback", link:"reference/com/google/android/gms/analytics/GoogleAnalytics.AppOptOutCallback.html", type:"class" },
+ { id:13, label:"com.google.android.gms.analytics.ModelFields", link:"reference/com/google/android/gms/analytics/ModelFields.html", type:"class" },
+ { id:14, label:"com.google.android.gms.analytics.StandardExceptionParser", link:"reference/com/google/android/gms/analytics/StandardExceptionParser.html", type:"class" },
+ { id:15, label:"com.google.android.gms.analytics.Tracker", link:"reference/com/google/android/gms/analytics/Tracker.html", type:"class" },
+ { id:16, label:"com.google.android.gms.analytics.Transaction", link:"reference/com/google/android/gms/analytics/Transaction.html", type:"class" },
+ { id:17, label:"com.google.android.gms.analytics.Transaction.Builder", link:"reference/com/google/android/gms/analytics/Transaction.Builder.html", type:"class" },
+ { id:18, label:"com.google.android.gms.analytics.Transaction.Item", link:"reference/com/google/android/gms/analytics/Transaction.Item.html", type:"class" },
+ { id:19, label:"com.google.android.gms.analytics.Transaction.Item.Builder", link:"reference/com/google/android/gms/analytics/Transaction.Item.Builder.html", type:"class" },
+ { id:20, label:"com.google.android.gms.auth", link:"reference/com/google/android/gms/auth/package-summary.html", type:"package" },
+ { id:21, label:"com.google.android.gms.auth.GoogleAuthException", link:"reference/com/google/android/gms/auth/GoogleAuthException.html", type:"class" },
+ { id:22, label:"com.google.android.gms.auth.GoogleAuthUtil", link:"reference/com/google/android/gms/auth/GoogleAuthUtil.html", type:"class" },
+ { id:23, label:"com.google.android.gms.auth.GooglePlayServicesAvailabilityException", link:"reference/com/google/android/gms/auth/GooglePlayServicesAvailabilityException.html", type:"class" },
+ { id:24, label:"com.google.android.gms.auth.UserRecoverableAuthException", link:"reference/com/google/android/gms/auth/UserRecoverableAuthException.html", type:"class" },
+ { id:25, label:"com.google.android.gms.auth.UserRecoverableNotifiedException", link:"reference/com/google/android/gms/auth/UserRecoverableNotifiedException.html", type:"class" },
+ { id:26, label:"com.google.android.gms.common", link:"reference/com/google/android/gms/common/package-summary.html", type:"package" },
+ { id:27, label:"com.google.android.gms.common.AccountPicker", link:"reference/com/google/android/gms/common/AccountPicker.html", type:"class" },
+ { id:28, label:"com.google.android.gms.common.ConnectionResult", link:"reference/com/google/android/gms/common/ConnectionResult.html", type:"class" },
+ { id:29, label:"com.google.android.gms.common.GooglePlayServicesClient", link:"reference/com/google/android/gms/common/GooglePlayServicesClient.html", type:"class" },
+ { id:30, label:"com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks", link:"reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html", type:"class" },
+ { id:31, label:"com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener", link:"reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html", type:"class" },
+ { id:32, label:"com.google.android.gms.common.GooglePlayServicesNotAvailableException", link:"reference/com/google/android/gms/common/GooglePlayServicesNotAvailableException.html", type:"class" },
+ { id:33, label:"com.google.android.gms.common.GooglePlayServicesUtil", link:"reference/com/google/android/gms/common/GooglePlayServicesUtil.html", type:"class" },
+ { id:34, label:"com.google.android.gms.common.Scopes", link:"reference/com/google/android/gms/common/Scopes.html", type:"class" },
+ { id:35, label:"com.google.android.gms.maps", link:"reference/com/google/android/gms/maps/package-summary.html", type:"package" },
+ { id:36, label:"com.google.android.gms.maps.CameraUpdate", link:"reference/com/google/android/gms/maps/CameraUpdate.html", type:"class" },
+ { id:37, label:"com.google.android.gms.maps.CameraUpdateFactory", link:"reference/com/google/android/gms/maps/CameraUpdateFactory.html", type:"class" },
+ { id:38, label:"com.google.android.gms.maps.GoogleMap", link:"reference/com/google/android/gms/maps/GoogleMap.html", type:"class" },
+ { id:39, label:"com.google.android.gms.maps.GoogleMap.CancelableCallback", link:"reference/com/google/android/gms/maps/GoogleMap.CancelableCallback.html", type:"class" },
+ { id:40, label:"com.google.android.gms.maps.GoogleMap.InfoWindowAdapter", link:"reference/com/google/android/gms/maps/GoogleMap.InfoWindowAdapter.html", type:"class" },
+ { id:41, label:"com.google.android.gms.maps.GoogleMap.OnCameraChangeListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnCameraChangeListener.html", type:"class" },
+ { id:42, label:"com.google.android.gms.maps.GoogleMap.OnInfoWindowClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnInfoWindowClickListener.html", type:"class" },
+ { id:43, label:"com.google.android.gms.maps.GoogleMap.OnMapClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMapClickListener.html", type:"class" },
+ { id:44, label:"com.google.android.gms.maps.GoogleMap.OnMapLongClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMapLongClickListener.html", type:"class" },
+ { id:45, label:"com.google.android.gms.maps.GoogleMap.OnMarkerClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMarkerClickListener.html", type:"class" },
+ { id:46, label:"com.google.android.gms.maps.GoogleMap.OnMarkerDragListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMarkerDragListener.html", type:"class" },
+ { id:47, label:"com.google.android.gms.maps.GoogleMapOptions", link:"reference/com/google/android/gms/maps/GoogleMapOptions.html", type:"class" },
+ { id:48, label:"com.google.android.gms.maps.LocationSource", link:"reference/com/google/android/gms/maps/LocationSource.html", type:"class" },
+ { id:49, label:"com.google.android.gms.maps.LocationSource.OnLocationChangedListener", link:"reference/com/google/android/gms/maps/LocationSource.OnLocationChangedListener.html", type:"class" },
+ { id:50, label:"com.google.android.gms.maps.MapFragment", link:"reference/com/google/android/gms/maps/MapFragment.html", type:"class" },
+ { id:51, label:"com.google.android.gms.maps.MapView", link:"reference/com/google/android/gms/maps/MapView.html", type:"class" },
+ { id:52, label:"com.google.android.gms.maps.MapsInitializer", link:"reference/com/google/android/gms/maps/MapsInitializer.html", type:"class" },
+ { id:53, label:"com.google.android.gms.maps.Projection", link:"reference/com/google/android/gms/maps/Projection.html", type:"class" },
+ { id:54, label:"com.google.android.gms.maps.SupportMapFragment", link:"reference/com/google/android/gms/maps/SupportMapFragment.html", type:"class" },
+ { id:55, label:"com.google.android.gms.maps.UiSettings", link:"reference/com/google/android/gms/maps/UiSettings.html", type:"class" },
+ { id:56, label:"com.google.android.gms.maps.model", link:"reference/com/google/android/gms/maps/model/package-summary.html", type:"package" },
+ { id:57, label:"com.google.android.gms.maps.model.BitmapDescriptor", link:"reference/com/google/android/gms/maps/model/BitmapDescriptor.html", type:"class" },
+ { id:58, label:"com.google.android.gms.maps.model.BitmapDescriptorFactory", link:"reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html", type:"class" },
+ { id:59, label:"com.google.android.gms.maps.model.CameraPosition", link:"reference/com/google/android/gms/maps/model/CameraPosition.html", type:"class" },
+ { id:60, label:"com.google.android.gms.maps.model.CameraPosition.Builder", link:"reference/com/google/android/gms/maps/model/CameraPosition.Builder.html", type:"class" },
+ { id:61, label:"com.google.android.gms.maps.model.GroundOverlay", link:"reference/com/google/android/gms/maps/model/GroundOverlay.html", type:"class" },
+ { id:62, label:"com.google.android.gms.maps.model.GroundOverlayOptions", link:"reference/com/google/android/gms/maps/model/GroundOverlayOptions.html", type:"class" },
+ { id:63, label:"com.google.android.gms.maps.model.LatLng", link:"reference/com/google/android/gms/maps/model/LatLng.html", type:"class" },
+ { id:64, label:"com.google.android.gms.maps.model.LatLngBounds", link:"reference/com/google/android/gms/maps/model/LatLngBounds.html", type:"class" },
+ { id:65, label:"com.google.android.gms.maps.model.LatLngBounds.Builder", link:"reference/com/google/android/gms/maps/model/LatLngBounds.Builder.html", type:"class" },
+ { id:66, label:"com.google.android.gms.maps.model.Marker", link:"reference/com/google/android/gms/maps/model/Marker.html", type:"class" },
+ { id:67, label:"com.google.android.gms.maps.model.MarkerOptions", link:"reference/com/google/android/gms/maps/model/MarkerOptions.html", type:"class" },
+ { id:68, label:"com.google.android.gms.maps.model.Polygon", link:"reference/com/google/android/gms/maps/model/Polygon.html", type:"class" },
+ { id:69, label:"com.google.android.gms.maps.model.PolygonOptions", link:"reference/com/google/android/gms/maps/model/PolygonOptions.html", type:"class" },
+ { id:70, label:"com.google.android.gms.maps.model.Polyline", link:"reference/com/google/android/gms/maps/model/Polyline.html", type:"class" },
+ { id:71, label:"com.google.android.gms.maps.model.PolylineOptions", link:"reference/com/google/android/gms/maps/model/PolylineOptions.html", type:"class" },
+ { id:72, label:"com.google.android.gms.maps.model.RuntimeRemoteException", link:"reference/com/google/android/gms/maps/model/RuntimeRemoteException.html", type:"class" },
+ { id:73, label:"com.google.android.gms.maps.model.Tile", link:"reference/com/google/android/gms/maps/model/Tile.html", type:"class" },
+ { id:74, label:"com.google.android.gms.maps.model.TileOverlay", link:"reference/com/google/android/gms/maps/model/TileOverlay.html", type:"class" },
+ { id:75, label:"com.google.android.gms.maps.model.TileOverlayOptions", link:"reference/com/google/android/gms/maps/model/TileOverlayOptions.html", type:"class" },
+ { id:76, label:"com.google.android.gms.maps.model.TileProvider", link:"reference/com/google/android/gms/maps/model/TileProvider.html", type:"class" },
+ { id:77, label:"com.google.android.gms.maps.model.UrlTileProvider", link:"reference/com/google/android/gms/maps/model/UrlTileProvider.html", type:"class" },
+ { id:78, label:"com.google.android.gms.maps.model.VisibleRegion", link:"reference/com/google/android/gms/maps/model/VisibleRegion.html", type:"class" },
+ { id:79, label:"com.google.android.gms.panorama", link:"reference/com/google/android/gms/panorama/package-summary.html", type:"package" },
+ { id:80, label:"com.google.android.gms.panorama.PanoramaClient", link:"reference/com/google/android/gms/panorama/PanoramaClient.html", type:"class" },
+ { id:81, label:"com.google.android.gms.panorama.PanoramaClient.OnPanoramaInfoLoadedListener", link:"reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html", type:"class" },
+ { id:82, label:"com.google.android.gms.plus", link:"reference/com/google/android/gms/plus/package-summary.html", type:"package" },
+ { id:83, label:"com.google.android.gms.plus.GooglePlusUtil", link:"reference/com/google/android/gms/plus/GooglePlusUtil.html", type:"class" },
+ { id:84, label:"com.google.android.gms.plus.PlusClient", link:"reference/com/google/android/gms/plus/PlusClient.html", type:"class" },
+ { id:85, label:"com.google.android.gms.plus.PlusOneButton", link:"reference/com/google/android/gms/plus/PlusOneButton.html", type:"class" },
+ { id:86, label:"com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener", link:"reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html", type:"class" },
+ { id:87, label:"com.google.android.gms.plus.PlusShare", link:"reference/com/google/android/gms/plus/PlusShare.html", type:"class" },
+ { id:88, label:"com.google.android.gms.plus.PlusShare.Builder", link:"reference/com/google/android/gms/plus/PlusShare.Builder.html", type:"class" },
+ { id:89, label:"com.google.android.gms.plus.PlusSignInButton", link:"reference/com/google/android/gms/plus/PlusSignInButton.html", type:"class" }
+
+ ];
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index cb9d2ef..dff3a32 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -3,43 +3,44 @@
header.hide=1
page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
-sdk.win32_bundle_download=adt-bundle-windows-x86.zip
-sdk.win32_bundle_bytes=418030942
-sdk.win32_bundle_checksum=ce32861d8f7c93ff6ff6971bd99d228e
-
-sdk.win64_bundle_download=adt-bundle-windows-x86_64.zip
-sdk.win64_bundle_bytes=418155677
-sdk.win64_bundle_checksum=f09aa4557bd1dc2703fde95dcdd6b92e
-
-sdk.mac64_bundle_download=adt-bundle-mac-x86_64.zip
-sdk.mac64_bundle_bytes=383216991
-sdk.mac64_bundle_checksum=ea6c074ee30c426c503dab5c225a5076
sdk.linux32_bundle_download=adt-bundle-linux-x86.zip
-sdk.linux32_bundle_bytes=411205048
-sdk.linux32_bundle_checksum=e64594cd339b8d9a400b9d16c616b3c3
+sdk.linux32_bundle_bytes=418614971
+sdk.linux32_bundle_checksum=24506708af221a887326c2a9ca9625dc
sdk.linux64_bundle_download=adt-bundle-linux-x86_64.zip
-sdk.linux64_bundle_bytes=411478695
-sdk.linux64_bundle_checksum=582bfc9083ff4cbcfacc8223bd8c3be1
+sdk.linux64_bundle_bytes=418889835
+sdk.linux64_bundle_checksum=464c1fbe92ea293d6b2292c27af5066a
+
+sdk.mac64_bundle_download=adt-bundle-mac-x86_64.zip
+sdk.mac64_bundle_bytes=390649300
+sdk.mac64_bundle_checksum=f557bc61a4bff466633037839771bffb
+
+sdk.win32_bundle_download=adt-bundle-windows-x86.zip
+sdk.win32_bundle_bytes=425429957
+sdk.win32_bundle_checksum=cca97f12904774385a57d542e70a490f
+
+sdk.win64_bundle_download=adt-bundle-windows-x86_64.zip
+sdk.win64_bundle_bytes=425553759
+sdk.win64_bundle_checksum=c51679f4517e1c3ddefa1e662bbf17f6
-sdk.win_installer=installer_r21.0.1-windows.exe
-sdk.win_installer_bytes=76520869
-sdk.win_installer_checksum=e2012262471a2583d4a559b15fcf45ff
+sdk.linux_download=android-sdk_r21.1.0-linux.tgz
+sdk.linux_bytes=91617112
+sdk.linux_checksum=3369a439240cf3dbe165d6b4173900a8
-sdk.win_download=android-sdk_r21.0.1-windows.zip
-sdk.win_bytes=99107847
-sdk.win_checksum=613568d774c3bf25c5d24db16601af83
+sdk.mac_download=android-sdk_r21.1.0-macosx.zip
+sdk.mac_bytes=66077080
+sdk.mac_checksum=49903cf79e1f8e3fde54a95bd3666385
-sdk.mac_download=android-sdk_r21.0.1-macosx.zip
-sdk.mac_bytes=65804128
-sdk.mac_checksum=30401c43a014cd5d6ec9d0c62854a1d9
+sdk.win_download=android-sdk_r21.1.0-windows.zip
+sdk.win_bytes=99360755
+sdk.win_checksum=dbece8859da9b66a1e8e7cd47b1e647e
-sdk.linux_download=android-sdk_r21.0.1-linux.tgz
-sdk.linux_bytes=91394975
-sdk.linux_checksum=eaa5a8d76d692d1d027f2bbcee019644
+sdk.win_installer=installer_r21.1.0-windows.exe
+sdk.win_installer_bytes=77767013
+sdk.win_installer_checksum=594d8ff8e349db9e783a5f2229561353
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index 804030b..d956af2 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
page.title=Installing the Eclipse Plugin
adt.zip.version=21.0.1
-adt.zip.download=ADT-21.0.1.zip
-adt.zip.bytes=13569302
-adt.zip.checksum=acfb01bf3fd1240f1fc21488c3dd16bf
+adt.zip.download=ADT-21.1.0.zip
+adt.zip.bytes=13564671
+adt.zip.checksum=f1ae183891229784bb9c33bcc9c5ef1e
@jd:body
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index 243683c..4adb7b2 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -57,6 +57,63 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>ADT 21.1.0</a> <em>(February 2013)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+<dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Java 1.6 or higher is required for ADT 21.1.0.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 21.1.0.</li>
+ <li>ADT 21.1.0 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
+ Tools r21.1.0</a>. If you haven't already installed SDK Tools r21.1.0 into your SDK, use the
+ Android SDK Manager to do so.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Added new <a href="{@docRoot}tools/projects/templates.html">code templates</a> for
+ notifications, blank fragments and list fragments.</li>
+ <li>Added support for resource rename refactoring. Renaming a resource XML file, drawable
+ icon, an {@code R.} field name or ID in the layout editor invokes a refactoring routine
+ to update all resource references.</li>
+ <li>Added more than 15 new Lint checks, including checks for overriding older APIs, XML
+ resource problems, graphic asset issues and manifest tags.
+ <li>Updated XML Editor to respond to refactoring shortcut keys such as <strong>Refactor
+ > Rename</strong>.</li>
+ <li>Updated XML Editor to improve double click handling.</li>
+ <li>Added code completion improvements for custom views, theme references and class
+ references. For example, code completion in a {@code <fragment android:name=””>} tag
+ now suggests completion with a list of fragment classes. Similarly, code completion in the
+ manifest now offers implementations suitable for the given tag.</li>
+ <li>Updated the <strong>Project Import</strong> dialog so that it shows a table for all
+ imported projects where you can edit the name of the imported project.</li>
+ <li>Added support for layout aliases in the Layout Editor.</li>
+ </ul>
+ </dd>
+
+ <dt>Bug fixes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed issued with refactoring support for renaming and moving classes and packages.
+ </li>
+ </ul>
+ </dd>
+
+</dl>
+</div>
+</div>
+
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>ADT 21.0.1</a> <em>(December 2012)</em>
</p>
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index 9349a4e..a5b7eee 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -28,6 +28,41 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>SDK Tools, Revision 21.1.0</a> <em>(February 2013)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+
+ <dl>
+ <dt>Dependencies:</dt>
+ <dd>
+ <ul>
+ <li>Android SDK Platform-tools revision 16 or later.</li>
+ <li>If you are developing in Eclipse with ADT, note that the SDK Tools r21.1.0 is
+ designed for use with ADT 21.1.0 and later. If you haven't already, update your
+ <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 21.1.0.</li>
+ <li>If you are developing outside Eclipse, you must have
+ <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Improved error reporting in {@code dx} when dex merging fails in the build
+ system.</li>
+ <li>Added more than 15 new Lint checks, including checks for overriding older APIs, XML
+ resource problems, graphic asset issues and manifest tags.</li>
+ <li>Added new aapt feature to compile resources.</li>
+ </ul>
+ </dd>
+ </dl>
+ </div>
+</div>
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>SDK Tools, Revision 21.0.1</a> <em>(December 2012)</em>
</p>
@@ -40,7 +75,7 @@
<li>Android SDK Platform-tools revision 16 or later.</li>
<li>If you are developing in Eclipse with ADT, note that the SDK Tools r21.0.1 is
designed for use with ADT 21.0.1 and later. If you haven't already, update your
- <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 21.0.0.</li>
+ <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 21.0.1.</li>
<li>If you are developing outside Eclipse, you must have
<a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
</ul>
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 5f0844a..1c83c51 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -488,7 +488,11 @@
*/
public void copyFromUnchecked(int[] d) {
mRS.validate();
- copy1DRangeFromUnchecked(0, mCurrentCount, d);
+ if (mCurrentDimY > 0) {
+ copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
+ } else {
+ copy1DRangeFromUnchecked(0, mCurrentCount, d);
+ }
}
/**
* Copy an allocation from an array. This variant is not type
@@ -499,7 +503,11 @@
*/
public void copyFromUnchecked(short[] d) {
mRS.validate();
- copy1DRangeFromUnchecked(0, mCurrentCount, d);
+ if (mCurrentDimY > 0) {
+ copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
+ } else {
+ copy1DRangeFromUnchecked(0, mCurrentCount, d);
+ }
}
/**
* Copy an allocation from an array. This variant is not type
@@ -510,7 +518,11 @@
*/
public void copyFromUnchecked(byte[] d) {
mRS.validate();
- copy1DRangeFromUnchecked(0, mCurrentCount, d);
+ if (mCurrentDimY > 0) {
+ copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
+ } else {
+ copy1DRangeFromUnchecked(0, mCurrentCount, d);
+ }
}
/**
* Copy an allocation from an array. This variant is not type
@@ -521,7 +533,11 @@
*/
public void copyFromUnchecked(float[] d) {
mRS.validate();
- copy1DRangeFromUnchecked(0, mCurrentCount, d);
+ if (mCurrentDimY > 0) {
+ copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
+ } else {
+ copy1DRangeFromUnchecked(0, mCurrentCount, d);
+ }
}
/**
@@ -533,7 +549,11 @@
*/
public void copyFrom(int[] d) {
mRS.validate();
- copy1DRangeFrom(0, mCurrentCount, d);
+ if (mCurrentDimY > 0) {
+ copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
+ } else {
+ copy1DRangeFrom(0, mCurrentCount, d);
+ }
}
/**
@@ -545,7 +565,11 @@
*/
public void copyFrom(short[] d) {
mRS.validate();
- copy1DRangeFrom(0, mCurrentCount, d);
+ if (mCurrentDimY > 0) {
+ copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
+ } else {
+ copy1DRangeFrom(0, mCurrentCount, d);
+ }
}
/**
@@ -557,7 +581,11 @@
*/
public void copyFrom(byte[] d) {
mRS.validate();
- copy1DRangeFrom(0, mCurrentCount, d);
+ if (mCurrentDimY > 0) {
+ copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
+ } else {
+ copy1DRangeFrom(0, mCurrentCount, d);
+ }
}
/**
@@ -569,7 +597,11 @@
*/
public void copyFrom(float[] d) {
mRS.validate();
- copy1DRangeFrom(0, mCurrentCount, d);
+ if (mCurrentDimY > 0) {
+ copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
+ } else {
+ copy1DRangeFrom(0, mCurrentCount, d);
+ }
}
/**
@@ -827,6 +859,35 @@
}
}
+ void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, byte[] data) {
+ mRS.validate();
+ validate2DRange(xoff, yoff, w, h);
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+ w, h, data, data.length);
+ }
+
+ void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, short[] data) {
+ mRS.validate();
+ validate2DRange(xoff, yoff, w, h);
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+ w, h, data, data.length * 2);
+ }
+
+ void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, int[] data) {
+ mRS.validate();
+ validate2DRange(xoff, yoff, w, h);
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+ w, h, data, data.length * 4);
+ }
+
+ void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, float[] data) {
+ mRS.validate();
+ validate2DRange(xoff, yoff, w, h);
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+ w, h, data, data.length * 4);
+ }
+
+
/**
* Copy a rectangular region from the array into the allocation.
* The incoming array is assumed to be tightly packed.
@@ -838,31 +899,23 @@
* @param data to be placed into the allocation
*/
public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
- mRS.validate();
- validate2DRange(xoff, yoff, w, h);
- mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
- w, h, data, data.length);
+ validateIsInt8();
+ copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
}
public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
- mRS.validate();
- validate2DRange(xoff, yoff, w, h);
- mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
- w, h, data, data.length * 2);
+ validateIsInt16();
+ copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
}
public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
- mRS.validate();
- validate2DRange(xoff, yoff, w, h);
- mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
- w, h, data, data.length * 4);
+ validateIsInt32();
+ copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
}
public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
- mRS.validate();
- validate2DRange(xoff, yoff, w, h);
- mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
- w, h, data, data.length * 4);
+ validateIsFloat32();
+ copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
}
/**
diff --git a/graphics/java/android/renderscript/FieldPacker.java b/graphics/java/android/renderscript/FieldPacker.java
index a215a57..0a7e882 100644
--- a/graphics/java/android/renderscript/FieldPacker.java
+++ b/graphics/java/android/renderscript/FieldPacker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,6 +29,12 @@
mData = new byte[len];
}
+ public FieldPacker(byte[] data) {
+ mPos = 0;
+ mLen = data.length;
+ mData = data;
+ }
+
public void align(int v) {
if ((v <= 0) || ((v & (v - 1)) != 0)) {
throw new RSIllegalArgumentException("argument must be a non-negative non-zero power of 2: " + v);
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
index b53ba0d..b405588 100644
--- a/graphics/java/android/renderscript/Script.java
+++ b/graphics/java/android/renderscript/Script.java
@@ -171,6 +171,11 @@
throw new RSIllegalArgumentException(
"At least one of ain or aout is required to be non-null.");
}
+
+ if (sc == null) {
+ forEach(slot, ain, aout, v);
+ return;
+ }
int in_id = 0;
if (ain != null) {
in_id = ain.getID(mRS);
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 48f5bf3..5b45d70 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -855,6 +855,7 @@
DENSITY_HIGH = ACONFIGURATION_DENSITY_HIGH,
DENSITY_XHIGH = ACONFIGURATION_DENSITY_XHIGH,
DENSITY_XXHIGH = ACONFIGURATION_DENSITY_XXHIGH,
+ DENSITY_XXXHIGH = ACONFIGURATION_DENSITY_XXXHIGH,
DENSITY_NONE = ACONFIGURATION_DENSITY_NONE
};
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 08e2332..62f268d 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1179,6 +1179,10 @@
delete bounds;
}
+ // We must clear the list of dirty rects before we
+ // call setupDraw() to prevent stencil setup to do
+ // the same thing again
+ mLayers.clear();
setupDraw(false);
setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
@@ -1195,9 +1199,8 @@
for (uint32_t i = 0; i < count; i++) {
delete mLayers.itemAt(i);
}
+ mLayers.clear();
}
-
- mLayers.clear();
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 1afcb46..1a75ea8 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -189,7 +189,10 @@
vOffset += glyph->mBitmapTop + height;
SkPoint destination[4];
- measure.getPosTan(x + hOffset + glyph->mBitmapLeft + halfWidth, position, tangent);
+ bool ok = measure.getPosTan(x + hOffset + glyph->mBitmapLeft + halfWidth, position, tangent);
+ if (!ok) {
+ ALOGW("The path for drawTextOnPath is empty or null");
+ }
// Move along the tangent and offset by the normal
destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index f930a03..5d27966 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -19,7 +19,6 @@
#define LOG_TAG "MediaScannerJNI"
#include <utils/Log.h>
#include <utils/threads.h>
-#include <utils/Unicode.h>
#include <media/mediascanner.h>
#include <media/stagefright/StagefrightMediaScanner.h>
@@ -57,6 +56,53 @@
return OK;
}
+// stolen from dalvik/vm/checkJni.cpp
+static bool isValidUtf8(const char* bytes) {
+ while (*bytes != '\0') {
+ unsigned char utf8 = *(bytes++);
+ // Switch on the high four bits.
+ switch (utf8 >> 4) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ // Bit pattern 0xxx. No need for any extra bytes.
+ break;
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0f:
+ /*
+ * Bit pattern 10xx or 1111, which are illegal start bytes.
+ * Note: 1111 is valid for normal UTF-8, but not the
+ * modified UTF-8 used here.
+ */
+ return false;
+ case 0x0e:
+ // Bit pattern 1110, so there are two additional bytes.
+ utf8 = *(bytes++);
+ if ((utf8 & 0xc0) != 0x80) {
+ return false;
+ }
+ // Fall through to take care of the final byte.
+ case 0x0c:
+ case 0x0d:
+ // Bit pattern 110x, so there is one additional byte.
+ utf8 = *(bytes++);
+ if ((utf8 & 0xc0) != 0x80) {
+ return false;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
class MyMediaScannerClient : public MediaScannerClient
{
public:
@@ -124,11 +170,8 @@
mEnv->ExceptionClear();
return NO_MEMORY;
}
-
- // Check if the value is valid UTF-8 string and replace
- // any un-printable characters with '?' when it's not.
char *cleaned = NULL;
- if (utf8_length(value) == -1) {
+ if (!isValidUtf8(value)) {
cleaned = strdup(value);
char *chp = cleaned;
char ch;
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index dc54eae..e79b2c6 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -45,6 +45,8 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
@@ -162,7 +164,7 @@
if (convertView == null) {
convertView = createView(parent);
}
- ViewHolder holder = (ViewHolder) convertView.getTag();
+ final ViewHolder holder = (ViewHolder) convertView.getTag();
// index is reverse since most recent appears at the bottom...
final int index = mRecentTaskDescriptions.size() - position - 1;
@@ -191,24 +193,49 @@
holder.calloutLine.setTranslationY(0f);
}
}
- mItemToAnimateInWhenWindowAnimationIsFinished = holder;
- final int translation = -getResources().getDimensionPixelSize(
- R.dimen.status_bar_recents_app_icon_translate_distance);
- final Configuration config = getResources().getConfiguration();
- if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
- holder.iconView.setAlpha(0f);
- holder.iconView.setTranslationX(translation);
- holder.labelView.setAlpha(0f);
- holder.labelView.setTranslationX(translation);
- holder.calloutLine.setAlpha(0f);
- holder.calloutLine.setTranslationX(translation);
- } else {
- holder.iconView.setAlpha(0f);
- holder.iconView.setTranslationY(translation);
- }
- if (!mWaitingForWindowAnimation) {
- animateInIconOfFirstTask();
- }
+ mItemToAnimateInWhenWindowAnimationIsFinished = null;
+
+ final ViewTreeObserver observer = getViewTreeObserver();
+ final OnGlobalLayoutListener animateFirstIcon = new OnGlobalLayoutListener() {
+ public void onGlobalLayout() {
+ if (mItemToAnimateInWhenWindowAnimationIsFinished != null) {
+ holder.iconView.setAlpha(1f);
+ holder.iconView.setTranslationX(0f);
+ holder.iconView.setTranslationY(0f);
+ holder.labelView.setAlpha(1f);
+ holder.labelView.setTranslationX(0f);
+ holder.labelView.setTranslationY(0f);
+ if (holder.calloutLine != null) {
+ holder.calloutLine.setAlpha(1f);
+ holder.calloutLine.setTranslationX(0f);
+ holder.calloutLine.setTranslationY(0f);
+ }
+ }
+ mItemToAnimateInWhenWindowAnimationIsFinished = holder;
+ int translation = -getResources().getDimensionPixelSize(
+ R.dimen.status_bar_recents_app_icon_translate_distance);
+ final Configuration config = getResources().getConfiguration();
+ if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
+ if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+ translation = -translation;
+ }
+ holder.iconView.setAlpha(0f);
+ holder.iconView.setTranslationX(translation);
+ holder.labelView.setAlpha(0f);
+ holder.labelView.setTranslationX(translation);
+ holder.calloutLine.setAlpha(0f);
+ holder.calloutLine.setTranslationX(translation);
+ } else {
+ holder.iconView.setAlpha(0f);
+ holder.iconView.setTranslationY(translation);
+ }
+ if (!mWaitingForWindowAnimation) {
+ animateInIconOfFirstTask();
+ }
+ getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ }
+ };
+ observer.addOnGlobalLayoutListener(animateFirstIcon);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 3bac146..f941f89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -597,6 +597,10 @@
y = (int) ((dm.heightPixels - statusBarHeight - height) / 2f + thumbTopMargin
+ recentsItemTopPadding + thumbBgPadding + statusBarHeight);
}
+ if (mLayoutDirection == View.LAYOUT_DIRECTION_RTL) {
+ x = dm.widthPixels - x - res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width);
+ }
ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(
getStatusBarView(),
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 88ea1f1..dfde692 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -133,7 +133,7 @@
class BackupManagerService extends IBackupManager.Stub {
private static final String TAG = "BackupManagerService";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
private static final boolean MORE_DEBUG = false;
// Name and current contents version of the full-backup manifest file
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 1a2c3de..13bf39f 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -235,6 +235,31 @@
}
};
}
+
+ public StatusBarNotification[] getArray(int count) {
+ if (count == 0) count = Archive.BUFFER_SIZE;
+ final StatusBarNotification[] a
+ = new StatusBarNotification[Math.min(count, mBuffer.size())];
+ Iterator<StatusBarNotification> iter = descendingIterator();
+ int i=0;
+ while (iter.hasNext() && i < count) {
+ a[i++] = iter.next();
+ }
+ return a;
+ }
+
+ public StatusBarNotification[] getArray(int count, String pkg, int userId) {
+ if (count == 0) count = Archive.BUFFER_SIZE;
+ final StatusBarNotification[] a
+ = new StatusBarNotification[Math.min(count, mBuffer.size())];
+ Iterator<StatusBarNotification> iter = filter(descendingIterator(), pkg, userId);
+ int i=0;
+ while (iter.hasNext() && i < count) {
+ a[i++] = iter.next();
+ }
+ return a;
+ }
+
}
Archive mArchive = new Archive();
@@ -347,10 +372,9 @@
public StatusBarNotification[] getActiveNotifications(String callingPkg) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
- "NotificationManagerService");
+ "NotificationManagerService.getActiveNotifications");
StatusBarNotification[] tmp = null;
- int userId = UserHandle.getCallingUserId();
int uid = Binder.getCallingUid();
if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
@@ -366,6 +390,22 @@
return tmp;
}
+ public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
+ "NotificationManagerService.getHistoricalNotifications");
+
+ StatusBarNotification[] tmp = null;
+ int uid = Binder.getCallingUid();
+
+ if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+ == AppOpsManager.MODE_ALLOWED) {
+ synchronized (mArchive) {
+ tmp = mArchive.getArray(count);
+ }
+ }
+ return tmp;
+ }
+
public static final class NotificationRecord
{
final StatusBarNotification sbn;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 608ad1c..22af3d5 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -2838,11 +2838,8 @@
for (int i=0; i<activities.size(); i++) {
ActivityRecord r = activities.get(i);
if (!r.finishing) {
- int index = mMainStack.indexOfTokenLocked(r.appToken);
- if (index >= 0) {
- mMainStack.finishActivityLocked(r, index, Activity.RESULT_CANCELED,
- null, "finish-heavy", true);
- }
+ mMainStack.finishActivityLocked(r, Activity.RESULT_CANCELED,
+ null, "finish-heavy", true);
}
}
@@ -8002,33 +7999,7 @@
}
mMainStack.resumeTopActivityLocked(null);
} else {
- ActivityRecord r = mMainStack.topRunningActivityLocked(null);
- if (r != null && r.app == app) {
- // If the top running activity is from this crashing
- // process, then terminate it to avoid getting in a loop.
- Slog.w(TAG, " Force finishing activity "
- + r.intent.getComponent().flattenToShortString());
- int index = mMainStack.indexOfActivityLocked(r);
- r.stack.finishActivityLocked(r, index,
- Activity.RESULT_CANCELED, null, "crashed", false);
- // Also terminate any activities below it that aren't yet
- // stopped, to avoid a situation where one will get
- // re-start our crashing activity once it gets resumed again.
- index--;
- if (index >= 0) {
- r = mMainStack.getActivityAtIndex(index);
- if (r.state == ActivityState.RESUMED
- || r.state == ActivityState.PAUSING
- || r.state == ActivityState.PAUSED) {
- if (!r.isHomeActivity || mHomeProcess != r.app) {
- Slog.w(TAG, " Force finishing activity "
- + r.intent.getComponent().flattenToShortString());
- r.stack.finishActivityLocked(r, index,
- Activity.RESULT_CANCELED, null, "crashed", false);
- }
- }
- }
- }
+ mMainStack.finishTopRunningActivityLocked(app);
}
// Bump up the crash count of any services currently running in the proc.
@@ -12370,7 +12341,6 @@
public boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode,
Intent resultData) {
- ComponentName dest = destIntent.getComponent();
synchronized (this) {
ActivityRecord srec = ActivityRecord.forToken(token);
@@ -12378,87 +12348,7 @@
return false;
}
ActivityStack stack = srec.stack;
- final int start = stack.indexOfActivityLocked(srec);
- if (start < 0) {
- // Current activity is not in history stack; do nothing.
- return false;
- }
- int finishTo = start - 1;
- ActivityRecord parent = null;
- boolean foundParentInTask = false;
- if (dest != null) {
- TaskRecord tr = srec.task;
- for (int i = start - 1; i >= 0; i--) {
- ActivityRecord r = stack.getActivityAtIndex(i);
- if (tr != r.task) {
- // Couldn't find parent in the same task; stop at the one above this.
- // (Root of current task; in-app "home" behavior)
- // Always at least finish the current activity.
- finishTo = Math.min(start - 1, i + 1);
- parent = stack.getActivityAtIndex(finishTo);
- break;
- } else if (r.info.packageName.equals(dest.getPackageName()) &&
- r.info.name.equals(dest.getClassName())) {
- finishTo = i;
- parent = r;
- foundParentInTask = true;
- break;
- }
- }
- }
-
- if (mController != null) {
- ActivityRecord next = mMainStack.topRunningActivityLocked(token, 0);
- if (next != null) {
- // ask watcher if this is allowed
- boolean resumeOK = true;
- try {
- resumeOK = mController.activityResuming(next.packageName);
- } catch (RemoteException e) {
- mController = null;
- }
-
- if (!resumeOK) {
- return false;
- }
- }
- }
- final long origId = Binder.clearCallingIdentity();
- for (int i = start; i > finishTo; i--) {
- ActivityRecord r = stack.getActivityAtIndex(i);
- mMainStack.requestFinishActivityLocked(r.appToken, resultCode, resultData,
- "navigate-up", true);
- // Only return the supplied result for the first activity finished
- resultCode = Activity.RESULT_CANCELED;
- resultData = null;
- }
-
- if (parent != null && foundParentInTask) {
- final int parentLaunchMode = parent.info.launchMode;
- final int destIntentFlags = destIntent.getFlags();
- if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ||
- parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK ||
- parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP ||
- (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
- parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent);
- } else {
- try {
- ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
- destIntent.getComponent(), 0, srec.userId);
- int res = mMainStack.startActivityLocked(srec.app.thread, destIntent,
- null, aInfo, parent.appToken, null,
- 0, -1, parent.launchedFromUid, parent.launchedFromPackage,
- 0, null, true, null);
- foundParentInTask = res == ActivityManager.START_SUCCESS;
- } catch (RemoteException e) {
- foundParentInTask = false;
- }
- mMainStack.requestFinishActivityLocked(parent.appToken, resultCode,
- resultData, "navigate-up", true);
- }
- }
- Binder.restoreCallingIdentity(origId);
- return foundParentInTask;
+ return stack.navigateUpToLocked(srec, destIntent, resultCode, resultData);
}
}
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index cde17c9..c1b406e 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -22,6 +22,7 @@
import android.app.Activity;
import android.app.ActivityOptions;
+import android.app.ResultInfo;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -95,9 +96,9 @@
ActivityRecord resultTo; // who started this entry, so will get our reply
final String resultWho; // additional identifier for use by resultTo.
final int requestCode; // code given by requester (resultTo)
- ArrayList results; // pending ActivityResult objs we have received
+ ArrayList<ResultInfo> results; // pending ActivityResult objs we have received
HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
- ArrayList newIntents; // any pending new intents for single-top mode
+ ArrayList<Intent> newIntents; // any pending new intents for single-top mode
ActivityOptions pendingOptions; // most recently given options
HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
UriPermissionOwner uriPermissions; // current special URI access perms.
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index d969709..76836f9 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -24,11 +24,13 @@
import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
import com.android.server.wm.AppTransition;
+import com.android.server.wm.TaskGroup;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AppGlobals;
+import android.app.IActivityController;
import android.app.IActivityManager;
import android.app.IThumbnailReceiver;
import android.app.IThumbnailRetriever;
@@ -501,14 +503,10 @@
return null;
}
- final int indexOfTokenLocked(IBinder token) {
+ private final int indexOfTokenLocked(IBinder token) {
return mHistory.indexOf(ActivityRecord.forToken(token));
}
- final int indexOfActivityLocked(ActivityRecord r) {
- return mHistory.indexOf(r);
- }
-
final ActivityRecord isInStackLocked(IBinder token) {
ActivityRecord r = ActivityRecord.forToken(token);
if (mHistory.contains(r)) {
@@ -517,14 +515,6 @@
return null;
}
- // TODO: This exposes mHistory too much, replace usage with ActivityStack methods.
- final ActivityRecord getActivityAtIndex(int index) {
- if (index >= 0 && index < mHistory.size()) {
- return mHistory.get(index);
- }
- return null;
- }
-
int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
TaskRecord lastTask = null;
final int N = mHistory.size();
@@ -745,7 +735,13 @@
try {
profileFd = profileFd.dup();
} catch (IOException e) {
- profileFd = null;
+ if (profileFd != null) {
+ try {
+ profileFd.close();
+ } catch (IOException o) {
+ }
+ profileFd = null;
+ }
}
}
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
@@ -1758,7 +1754,7 @@
try {
// Deliver all pending results.
- ArrayList a = next.results;
+ ArrayList<ResultInfo> a = next.results;
if (a != null) {
final int N = a.size();
if (!next.finishing && N > 0) {
@@ -2156,6 +2152,7 @@
}
i++;
}
+ mService.mWindowManager.moveTaskToBottom(target.task.taskId);
if (taskTop == p) {
taskTop = below;
}
@@ -2304,6 +2301,8 @@
validateAppTokensLocked();
}
}
+ // TODO: This is wrong because it doesn't take lastReparentPos into account.
+ mService.mWindowManager.moveTaskToTop(task.taskId);
replyChainEnd = -1;
// Now we've moved it in to place... but what if this is
@@ -2413,7 +2412,7 @@
if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
&& (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
if (!ret.finishing) {
- int index = indexOfTokenLocked(ret.appToken);
+ int index = mHistory.indexOf(ret);
if (index >= 0) {
finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
null, "clear", false);
@@ -3568,7 +3567,7 @@
}
// Get the activity record.
- int index = indexOfActivityLocked(r);
+ int index = mHistory.indexOf(r);
if (index >= 0) {
res = r;
@@ -3654,7 +3653,7 @@
// Stop any activities that are scheduled to do so but have been
// waiting for the next one to start.
for (i=0; i<NS; i++) {
- ActivityRecord r = (ActivityRecord)stops.get(i);
+ ActivityRecord r = stops.get(i);
synchronized (mService) {
if (r.finishing) {
finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
@@ -3667,7 +3666,7 @@
// Finish any activities that are scheduled to do so but have been
// waiting for the next one to start.
for (i=0; i<NF; i++) {
- ActivityRecord r = (ActivityRecord)finishes.get(i);
+ ActivityRecord r = finishes.get(i);
synchronized (mService) {
activityRemoved = destroyActivityLocked(r, true, false, "finish-idle");
}
@@ -3675,7 +3674,7 @@
// Report back to any thumbnail receivers.
for (i=0; i<NT; i++) {
- ActivityRecord r = (ActivityRecord)thumbnails.get(i);
+ ActivityRecord r = thumbnails.get(i);
mService.sendPendingThumbnail(r, null, null, null, true);
}
@@ -3730,7 +3729,7 @@
int i;
for (i=mHistory.size()-1; i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
if (r.resultTo == self && r.requestCode == requestCode) {
if ((r.resultWho == null && resultWho == null) ||
(r.resultWho != null && r.resultWho.equals(resultWho))) {
@@ -3742,6 +3741,36 @@
mService.updateOomAdjLocked();
}
+ final void finishTopRunningActivityLocked(ProcessRecord app) {
+ ActivityRecord r = topRunningActivityLocked(null);
+ if (r != null && r.app == app) {
+ // If the top running activity is from this crashing
+ // process, then terminate it to avoid getting in a loop.
+ Slog.w(TAG, " Force finishing activity "
+ + r.intent.getComponent().flattenToShortString());
+ int index = mHistory.indexOf(r);
+ r.stack.finishActivityLocked(r, index,
+ Activity.RESULT_CANCELED, null, "crashed", false);
+ // Also terminate any activities below it that aren't yet
+ // stopped, to avoid a situation where one will get
+ // re-start our crashing activity once it gets resumed again.
+ index--;
+ if (index >= 0) {
+ r = mHistory.get(index);
+ if (r.state == ActivityState.RESUMED
+ || r.state == ActivityState.PAUSING
+ || r.state == ActivityState.PAUSED) {
+ if (!r.isHomeActivity || mService.mHomeProcess != r.app) {
+ Slog.w(TAG, " Force finishing activity "
+ + r.intent.getComponent().flattenToShortString());
+ r.stack.finishActivityLocked(r, index,
+ Activity.RESULT_CANCELED, null, "crashed", false);
+ }
+ }
+ }
+ }
+ }
+
final boolean finishActivityAffinityLocked(IBinder token) {
int index = indexOfTokenLocked(token);
if (DEBUG_RESULTS) Slog.v(
@@ -3800,6 +3829,19 @@
* @return Returns true if this activity has been removed from the history
* list, or false if it is still in the list and will be removed later.
*/
+ final boolean finishActivityLocked(ActivityRecord r,
+ int resultCode, Intent resultData, String reason, boolean oomAdj) {
+ int index = mHistory.indexOf(r);
+ if (index >= 0) {
+ return finishActivityLocked(r, index, resultCode, resultData, reason, false, oomAdj);
+ }
+ return false;
+ }
+
+ /**
+ * @return Returns true if this activity has been removed from the history
+ * list, or false if it is still in the list and will be removed later.
+ */
final boolean finishActivityLocked(ActivityRecord r, int index,
int resultCode, Intent resultData, String reason, boolean oomAdj) {
return finishActivityLocked(r, index, resultCode, resultData, reason, false, oomAdj);
@@ -3892,7 +3934,7 @@
private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
int mode, boolean oomAdj) {
- final int index = indexOfActivityLocked(r);
+ final int index = mHistory.indexOf(r);
if (index < 0) {
return null;
}
@@ -3948,16 +3990,102 @@
resumeTopActivityLocked(null);
}
return activityRemoved ? null : r;
- } else {
- // Need to go through the full pause cycle to get this
- // activity into the stopped state and then finish it.
- if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
- mFinishingActivities.add(r);
- resumeTopActivityLocked(null);
}
+
+ // Need to go through the full pause cycle to get this
+ // activity into the stopped state and then finish it.
+ if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
+ mFinishingActivities.add(r);
+ resumeTopActivityLocked(null);
return r;
}
+ final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
+ Intent resultData) {
+ final int start = mHistory.indexOf(srec);
+ if (start < 0) {
+ // Current activity is not in history stack; do nothing.
+ return false;
+ }
+ int finishTo = start - 1;
+ ActivityRecord parent = null;
+ boolean foundParentInTask = false;
+ ComponentName dest = destIntent.getComponent();
+ if (dest != null) {
+ TaskRecord tr = srec.task;
+ for (int i = start - 1; i >= 0; i--) {
+ ActivityRecord r = mHistory.get(i);
+ if (tr != r.task) {
+ // Couldn't find parent in the same task; stop at the one above this.
+ // (Root of current task; in-app "home" behavior)
+ // Always at least finish the current activity.
+ finishTo = Math.min(start - 1, i + 1);
+ parent = mHistory.get(finishTo);
+ break;
+ } else if (r.info.packageName.equals(dest.getPackageName()) &&
+ r.info.name.equals(dest.getClassName())) {
+ finishTo = i;
+ parent = r;
+ foundParentInTask = true;
+ break;
+ }
+ }
+ }
+
+ IActivityController controller = mService.mController;
+ if (controller != null) {
+ ActivityRecord next = topRunningActivityLocked(srec.appToken, 0);
+ if (next != null) {
+ // ask watcher if this is allowed
+ boolean resumeOK = true;
+ try {
+ resumeOK = controller.activityResuming(next.packageName);
+ } catch (RemoteException e) {
+ mService.mController = null;
+ }
+
+ if (!resumeOK) {
+ return false;
+ }
+ }
+ }
+ final long origId = Binder.clearCallingIdentity();
+ for (int i = start; i > finishTo; i--) {
+ ActivityRecord r = mHistory.get(i);
+ requestFinishActivityLocked(r.appToken, resultCode, resultData,
+ "navigate-up", true);
+ // Only return the supplied result for the first activity finished
+ resultCode = Activity.RESULT_CANCELED;
+ resultData = null;
+ }
+
+ if (parent != null && foundParentInTask) {
+ final int parentLaunchMode = parent.info.launchMode;
+ final int destIntentFlags = destIntent.getFlags();
+ if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ||
+ parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK ||
+ parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP ||
+ (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
+ parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent);
+ } else {
+ try {
+ ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
+ destIntent.getComponent(), 0, srec.userId);
+ int res = startActivityLocked(srec.app.thread, destIntent,
+ null, aInfo, parent.appToken, null,
+ 0, -1, parent.launchedFromUid, parent.launchedFromPackage,
+ 0, null, true, null);
+ foundParentInTask = res == ActivityManager.START_SUCCESS;
+ } catch (RemoteException e) {
+ foundParentInTask = false;
+ }
+ requestFinishActivityLocked(parent.appToken, resultCode,
+ resultData, "navigate-up", true);
+ }
+ }
+ Binder.restoreCallingIdentity(origId);
+ return foundParentInTask;
+ }
/**
* Perform the common clean-up of an activity record. This is called both
* as part of destroyActivityLocked() (when destroying the client-side
@@ -4216,7 +4344,7 @@
mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
}
- int index = indexOfActivityLocked(r);
+ int index = mHistory.indexOf(r);
if (index >= 0) {
if (r.state == ActivityState.DESTROYING) {
cleanUpActivityLocked(r, true, false);
@@ -4230,15 +4358,15 @@
}
}
- private void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app,
- String listName) {
+ private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
+ ProcessRecord app, String listName) {
int i = list.size();
if (DEBUG_CLEANUP) Slog.v(
TAG, "Removing app " + app + " from list " + listName
+ " with " + i + " entries");
while (i > 0) {
i--;
- ActivityRecord r = (ActivityRecord)list.get(i);
+ ActivityRecord r = list.get(i);
if (DEBUG_CLEANUP) Slog.v(TAG, "Record #" + i + " " + r);
if (r.app == app) {
if (DEBUG_CLEANUP) Slog.v(TAG, "---> REMOVING this entry!");
@@ -4264,7 +4392,7 @@
TAG, "Removing app " + app + " from history with " + i + " entries");
while (i > 0) {
i--;
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
if (DEBUG_CLEANUP) Slog.v(
TAG, "Record #" + i + " " + r + ": app=" + r.app);
if (r.app == app) {
@@ -4440,6 +4568,7 @@
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
+ mService.mWindowManager.moveTaskToTop(task);
finishTaskMoveLocked(task);
EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, task);
@@ -4532,6 +4661,7 @@
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
+ mService.mWindowManager.moveTaskToBottom(task);
finishTaskMoveLocked(task);
return true;
@@ -4561,9 +4691,8 @@
TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
if (info.numSubThumbbails <= 0) {
return info.mainThumbnail != null ? info.mainThumbnail : tr.lastThumbnail;
- } else {
- return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail;
}
+ return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail;
}
public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex,
@@ -4643,6 +4772,7 @@
}
if (thumbs.numSubThumbbails > 0) {
thumbs.retriever = new IThumbnailRetriever.Stub() {
+ @Override
public Bitmap getThumbnail(int index) {
if (index < 0 || index >= thumbs.subtasks.size()) {
return null;
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 5760dcd..18ccf75 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -547,6 +547,11 @@
UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED);
mUsers.put(0, primary);
mNextSerialNumber = MIN_USER_ID;
+
+ Bundle restrictions = new Bundle();
+ initRestrictionsToDefaults(restrictions);
+ mUserRestrictions.append(0, restrictions);
+
updateUserIdsLocked();
writeUserListLocked();
@@ -805,6 +810,9 @@
userInfo.partial = false;
writeUserLocked(userInfo);
updateUserIdsLocked();
+ Bundle restrictions = new Bundle();
+ initRestrictionsToDefaults(restrictions);
+ mUserRestrictions.append(userId, restrictions);
}
}
if (userInfo != null) {
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 906ea57..43a5f0c 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -16,12 +16,16 @@
package com.android.server.wm;
+import android.os.Debug;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
class DisplayContentList extends ArrayList<DisplayContent> {
}
@@ -34,7 +38,7 @@
* WindowManagerService.mWindowMap.
*/
class DisplayContent {
-// private final static String TAG = "DisplayContent";
+ private final static String TAG = "DisplayContent";
/** Unique identifier of this stack. */
private final int mDisplayId;
@@ -97,7 +101,7 @@
/**
* Sorted most recent at top, oldest at [0].
*/
-// ArrayList<TaskList> mTaskLists = new ArrayList<TaskList>();
+ ArrayList<TaskList> mTaskLists = new ArrayList<TaskList>();
SparseArray<TaskList> mTaskIdToTaskList = new SparseArray<TaskList>();
/**
@@ -133,24 +137,28 @@
/**
* Find the location to insert a new AppWindowToken into the window-ordered app token list.
* @param addPos The location the token was inserted into in mAppTokens.
- * @param atoken The token to insert.
+ * @param wtoken The token to insert.
*/
- void addAppToken(final int addPos, final AppWindowToken atoken) {
- mAppTokens.add(addPos, atoken);
+ void addAppToken(final int addPos, final AppWindowToken wtoken) {
+ mAppTokens.add(addPos, wtoken);
if (addPos == 0 || addPos == mAnimatingAppTokens.size()) {
// It was inserted into the beginning or end of mAppTokens. Honor that.
- mAnimatingAppTokens.add(addPos, atoken);
+ mAnimatingAppTokens.add(addPos, wtoken);
} else {
// Find the item immediately above the mAppTokens insertion point and put the token
// immediately below that one in mAnimatingAppTokens.
final AppWindowToken aboveAnchor = mAppTokens.get(addPos + 1);
- mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), atoken);
+ mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), wtoken);
}
- TaskList task = mTaskIdToTaskList.get(atoken.groupId);
+ TaskList task = mTaskIdToTaskList.get(wtoken.groupId);
if (task == null) {
- mTaskIdToTaskList.put(atoken.groupId, new TaskList(atoken));
+ task = new TaskList(wtoken, this);
+ mTaskIdToTaskList.put(wtoken.groupId, task);
+ mTaskLists.add(task);
+ } else {
+ task.mAppTokens.add(wtoken);
}
}
@@ -163,6 +171,7 @@
AppTokenList appTokens = task.mAppTokens;
appTokens.remove(wtoken);
if (appTokens.size() == 0) {
+ mTaskLists.remove(task);
mTaskIdToTaskList.delete(taskId);
}
}
@@ -186,7 +195,7 @@
task = mTaskIdToTaskList.get(newTaskId);
if (task == null) {
- task = new TaskList(wtoken);
+ task = new TaskList(wtoken, this);
mTaskIdToTaskList.put(newTaskId, task);
} else {
task.mAppTokens.add(wtoken);
@@ -195,6 +204,122 @@
wtoken.groupId = newTaskId;
}
+ class TaskListsIterator implements Iterator<TaskList> {
+ private int mCur;
+ private boolean mReverse;
+
+ TaskListsIterator() {
+ this(false);
+ }
+
+ TaskListsIterator(boolean reverse) {
+ mReverse = reverse;
+ int numTaskLists = mTaskLists.size();
+ mCur = reverse ? numTaskLists - 1 : 0;
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (mReverse) {
+ return mCur >= 0;
+ }
+ return mCur < mTaskLists.size();
+ }
+
+ @Override
+ public TaskList next() {
+ if (hasNext()) {
+ TaskList taskList = mTaskLists.get(mCur);
+ mCur += (mReverse ? -1 : 1);
+ return taskList;
+ }
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public void remove() {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ class AppTokenIterator implements Iterator<AppWindowToken> {
+ final TaskListsIterator mIterator;
+ final boolean mReverse;
+ int mCur;
+ TaskList mTaskList;
+
+ public AppTokenIterator() {
+ this(false);
+ }
+
+ public AppTokenIterator(boolean reverse) {
+ mReverse = reverse;
+ mIterator = new TaskListsIterator(reverse);
+ getNextTaskList();
+ }
+
+ private void getNextTaskList() {
+ if (mIterator.hasNext()) {
+ mTaskList = mIterator.next();
+ mCur = mReverse ? mTaskList.mAppTokens.size() - 1 : 0;
+ }
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (mTaskList == null) {
+ return false;
+ }
+ if (mReverse) {
+ return mCur >= 0;
+ }
+ return mCur < mTaskList.mAppTokens.size();
+ }
+
+ @Override
+ public AppWindowToken next() {
+ if (hasNext()) {
+ AppWindowToken wtoken = mTaskList.mAppTokens.get(mCur);
+ mCur += mReverse ? -1 : 1;
+ if (!hasNext()) {
+ getNextTaskList();
+ }
+ return wtoken;
+ }
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public void remove() {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ void verifyAppTokens() {
+ AppTokenIterator iterator = new AppTokenIterator();
+ for (int i = 0; i < mAppTokens.size(); ++i) {
+ if (!iterator.hasNext()) {
+ Slog.e(TAG, "compareAppTokens: More mAppTokens than TaskList tokens. Callers="
+ + Debug.getCallers(4));
+ while (i < mAppTokens.size()) {
+ Slog.e(TAG, "compareAppTokens: mAppTokens[" + i + "]=" + mAppTokens.get(i));
+ i++;
+ }
+ return;
+ }
+ AppWindowToken appToken = mAppTokens.get(i);
+ AppWindowToken taskListToken = iterator.next();
+ if (appToken != taskListToken) {
+ Slog.e(TAG, "compareAppTokens: Mismatch at " + i + " appToken=" + appToken
+ + " taskListToken=" + taskListToken + ". Callers=" + Debug.getCallers(4));
+ }
+ }
+ if (iterator.hasNext()) {
+ Slog.e(TAG, "compareAppTokens: More TaskList tokens than mAppTokens Callers="
+ + Debug.getCallers(4));
+ }
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
final String subPrefix = " " + prefix;
diff --git a/services/java/com/android/server/am/TaskGroup.java b/services/java/com/android/server/wm/TaskGroup.java
similarity index 96%
rename from services/java/com/android/server/am/TaskGroup.java
rename to services/java/com/android/server/wm/TaskGroup.java
index 7574103..5e82af2 100644
--- a/services/java/com/android/server/am/TaskGroup.java
+++ b/services/java/com/android/server/wm/TaskGroup.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.am;
+package com.android.server.wm;
import android.view.IApplicationToken;
diff --git a/services/java/com/android/server/wm/TaskList.java b/services/java/com/android/server/wm/TaskList.java
index fe12b98..88791f2 100644
--- a/services/java/com/android/server/wm/TaskList.java
+++ b/services/java/com/android/server/wm/TaskList.java
@@ -16,15 +16,15 @@
package com.android.server.wm;
-import com.android.server.am.TaskGroup;
-
-class TaskList extends TaskGroup {
+class TaskList {
// private final String TAG = "TaskGroup";
- AppTokenList mAppTokens = new AppTokenList();
+ DisplayContent mDisplayContent;
+ final AppTokenList mAppTokens = new AppTokenList();
+ final int taskId;
- TaskList(AppWindowToken wtoken) {
+ TaskList(AppWindowToken wtoken, DisplayContent displayContent) {
taskId = wtoken.groupId;
- tokens.add(wtoken.appToken);
mAppTokens.add(wtoken);
+ mDisplayContent = displayContent;
}
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 62eccdf..d51c07b 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -54,7 +54,6 @@
import com.android.server.EventLogTags;
import com.android.server.Watchdog;
import com.android.server.am.BatteryStatsService;
-import com.android.server.am.TaskGroup;
import com.android.server.display.DisplayManagerService;
import com.android.server.input.InputManagerService;
import com.android.server.power.PowerManagerService;
@@ -330,8 +329,7 @@
/**
* Mapping from a token IBinder to a WindowToken object.
*/
- final HashMap<IBinder, WindowToken> mTokenMap =
- new HashMap<IBinder, WindowToken>();
+ final HashMap<IBinder, WindowToken> mTokenMap = new HashMap<IBinder, WindowToken>();
/**
* List of window tokens that have finished starting their application,
@@ -746,6 +744,14 @@
mActivityManager = ActivityManagerNative.getDefault();
mBatteryStats = BatteryStatsService.getService();
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
+ mAppOps.startWatchingMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, null,
+ new AppOpsManager.Callback() {
+ @Override
+ public void opChanged(int op, String packageName) {
+ updateAppOpsState();
+ }
+ }
+ );
// Get persisted window scale setting
mWindowAnimationScale = Settings.Global.getFloat(context.getContentResolver(),
@@ -2150,7 +2156,10 @@
win.attach();
mWindowMap.put(client.asBinder(), win);
if (win.mAppOp != AppOpsManager.OP_NONE) {
- mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage());
+ if (mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage())
+ != AppOpsManager.MODE_ALLOWED) {
+ win.setAppOpVisibilityLw(false);
+ }
}
if (type == TYPE_APPLICATION_STARTING && token.appWindowToken != null) {
@@ -2439,6 +2448,27 @@
mInputMonitor.updateInputWindowsLw(true /*force*/);
}
+ public void updateAppOpsState() {
+ synchronized(mWindowMap) {
+ boolean changed = false;
+ for (int i=0; i<mDisplayContents.size(); i++) {
+ DisplayContent display = mDisplayContents.valueAt(i);
+ WindowList windows = display.getWindowList();
+ for (int j=0; j<windows.size(); j++) {
+ final WindowState win = windows.get(j);
+ if (win.mAppOp != AppOpsManager.OP_NONE) {
+ changed |= win.setAppOpVisibilityLw(mAppOps.checkOpNoThrow(win.mAppOp,
+ win.getOwningUid(),
+ win.getOwningPackage()) == AppOpsManager.MODE_ALLOWED);
+ }
+ }
+ }
+ if (changed) {
+ scheduleAnimationLocked();
+ }
+ }
+ }
+
static void logSurface(WindowState w, String msg, RuntimeException where) {
String str = " SURFACE " + msg + ": " + w;
if (where != null) {
@@ -3286,6 +3316,7 @@
mTaskIdToDisplayContents.put(taskId, displayContent);
}
displayContent.addAppToken(addPos, atoken);
+ displayContent.verifyAppTokens();
mTokenMap.put(token.asBinder(), atoken);
mTaskIdToDisplayContents.put(taskId, displayContent);
@@ -4269,11 +4300,12 @@
TAG, "Removing app " + wtoken + " delayed=" + delayed
+ " animation=" + wtoken.mAppAnimator.animation
+ " animating=" + wtoken.mAppAnimator.animating);
+ DisplayContent displayContent = mTaskIdToDisplayContents.get(wtoken.groupId);
if (delayed) {
// set the token aside because it has an active animation to be finished
if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
"removeAppToken make exiting: " + wtoken);
- mTaskIdToDisplayContents.get(wtoken.groupId).mExitingAppTokens.add(wtoken);
+ displayContent.mExitingAppTokens.add(wtoken);
} else {
// Make sure there is no animation running on this token,
// so any windows associated with it will be removed as
@@ -4283,7 +4315,8 @@
}
if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
"removeAppToken: " + wtoken);
- mTaskIdToDisplayContents.get(wtoken.groupId).removeAppToken(wtoken);
+ displayContent.removeAppToken(wtoken);
+ displayContent.verifyAppTokens();
wtoken.removed = true;
if (wtoken.startingData != null) {
startingToken = wtoken;
@@ -4675,6 +4708,44 @@
Binder.restoreCallingIdentity(origId);
}
+ public void moveTaskToTop(int taskId) {
+ DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
+ if (displayContent == null) {
+ Slog.e(TAG, "moveTaskToTop: taskId=" + taskId
+ + " not found in mTaskIdToDisplayContents");
+ return;
+ }
+ TaskList taskList = displayContent.mTaskIdToTaskList.get(taskId);
+ if (taskList == null) {
+ Slog.e(TAG, "moveTaskToTop: taskId=" + taskId + " not found in mTaskIdToTaskLists");
+ return;
+ }
+ if (!displayContent.mTaskLists.remove(taskList)) {
+ Slog.e(TAG, "moveTaskToTop: taskId=" + taskId + " not found in mTaskLists");
+ }
+ displayContent.mTaskLists.add(taskList);
+ displayContent.verifyAppTokens();
+ }
+
+ public void moveTaskToBottom(int taskId) {
+ DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
+ if (displayContent == null) {
+ Slog.e(TAG, "moveTaskToBottom: taskId=" + taskId
+ + " not found in mTaskIdToDisplayContents");
+ return;
+ }
+ TaskList taskList = displayContent.mTaskIdToTaskList.get(taskId);
+ if (taskList == null) {
+ Slog.e(TAG, "moveTaskToTopBottomtaskId=" + taskId + " not found in mTaskIdToTaskLists");
+ return;
+ }
+ if (!displayContent.mTaskLists.remove(taskList)) {
+ Slog.e(TAG, "moveTaskToBottom: taskId=" + taskId + " not found in mTaskLists");
+ }
+ displayContent.mTaskLists.add(0, taskList);
+ displayContent.verifyAppTokens();
+ }
+
// -------------------------------------------------------------
// Misc IWindowSession methods
// -------------------------------------------------------------
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 6648e56..8dda544 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -96,6 +96,7 @@
int mSystemUiVisibility;
boolean mPolicyVisibility = true;
boolean mPolicyVisibilityAfterAnim = true;
+ boolean mAppOpVisibility = true;
boolean mAppFreezing;
boolean mAttachedHidden; // is our parent window hidden?
boolean mWallpaperVisible; // for wallpaper, what was last vis report?
@@ -982,6 +983,10 @@
+ this + ", type " + mAttrs.type + ", belonging to " + mOwnerUid);
return false;
}
+ if (!mAppOpVisibility) {
+ // Being hidden due to app op request.
+ return false;
+ }
if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
// Already showing.
return false;
@@ -1053,6 +1058,25 @@
return true;
}
+ public boolean setAppOpVisibilityLw(boolean state) {
+ if (mAppOpVisibility != state) {
+ mAppOpVisibility = state;
+ if (state) {
+ // If the policy visibility had last been to hide, then this
+ // will incorrectly show at this point since we lost that
+ // information. Not a big deal -- for the windows that have app
+ // ops modifies they should only be hidden by policy due to the
+ // lock screen, and the user won't be changing this if locked.
+ // Plus it will quickly be fixed the next time we do a layout.
+ showLw(true, false);
+ } else {
+ hideLw(true, false);
+ }
+ return true;
+ }
+ return false;
+ }
+
@Override
public boolean isAlive() {
return mClient.asBinder().isBinderAlive();
@@ -1179,11 +1203,14 @@
pw.print(" mSystemUiVisibility=0x");
pw.println(Integer.toHexString(mSystemUiVisibility));
}
- if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) {
+ if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || !mAppOpVisibility
+ || mAttachedHidden) {
pw.print(prefix); pw.print("mPolicyVisibility=");
pw.print(mPolicyVisibility);
pw.print(" mPolicyVisibilityAfterAnim=");
pw.print(mPolicyVisibilityAfterAnim);
+ pw.print(" mAppOpVisibility=");
+ pw.print(mAppOpVisibility);
pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
}
if (!mRelayoutCalled || mLayoutNeeded) {
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 35dea24..d7a58b6 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -26,7 +26,7 @@
public final class CellInfoLte extends CellInfo implements Parcelable {
private static final String LOG_TAG = "CellInfoLte";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private CellIdentityLte mCellIdentityLte;
private CellSignalStrengthLte mCellSignalStrengthLte;
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_alloc.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_alloc.java
index ddc6a99..3af3745 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_alloc.java
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_alloc.java
@@ -39,6 +39,7 @@
typeBuilder.setX(X).setY(Y);
Allocation A = Allocation.createTyped(RS, typeBuilder.create());
s.bind_a(A);
+ s.set_aRaw(A);
typeBuilder = new Type.Builder(RS, Element.I32(RS));
typeBuilder.setX(X).setY(Y).setFaces(true);
@@ -59,6 +60,7 @@
ScriptC_alloc s = new ScriptC_alloc(pRS);
pRS.setMessageHandler(mRsMessage);
initializeGlobals(pRS, s);
+ s.forEach_root(s.get_aRaw());
s.invoke_alloc_test();
pRS.finish();
waitForMessage();
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach.java
index c3f3ca0..fd18f93 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach.java
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach.java
@@ -37,7 +37,7 @@
s.set_dimY(Y);
typeBuilder.setX(X).setY(Y);
A = Allocation.createTyped(RS, typeBuilder.create());
- s.bind_a(A);
+ s.set_aRaw(A);
return;
}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach_bounds.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach_bounds.java
index 653ebd5..13fefe7 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach_bounds.java
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach_bounds.java
@@ -37,7 +37,7 @@
s.set_dimY(Y);
typeBuilder.setX(X).setY(Y);
A = Allocation.createTyped(RS, typeBuilder.create());
- s.bind_a(A);
+ s.set_aRaw(A);
s.set_s(s);
s.set_ain(A);
s.set_aout(A);
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_noroot.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_noroot.java
index 69fc97f..606af4d 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_noroot.java
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_noroot.java
@@ -37,7 +37,7 @@
s.set_dimY(Y);
typeBuilder.setX(X).setY(Y);
A = Allocation.createTyped(RS, typeBuilder.create());
- s.bind_a(A);
+ s.set_aRaw(A);
return;
}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/alloc.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/alloc.rs
index 3116e5a..1b5e2ac 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/alloc.rs
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/alloc.rs
@@ -5,39 +5,37 @@
int dimY;
int dimZ;
+rs_allocation aRaw;
rs_allocation aFaces;
rs_allocation aLOD;
rs_allocation aFacesLOD;
+void root(int *o, uint32_t x, uint32_t y) {
+ *o = x + y * dimX;
+}
+
static bool test_alloc_dims() {
bool failed = false;
int i, j;
- for (j = 0; j < dimY; j++) {
- for (i = 0; i < dimX; i++) {
- a[i + j * dimX] = i + j * dimX;
- }
- }
-
- rs_allocation alloc = rsGetAllocation(a);
- _RS_ASSERT(rsAllocationGetDimX(alloc) == dimX);
- _RS_ASSERT(rsAllocationGetDimY(alloc) == dimY);
- _RS_ASSERT(rsAllocationGetDimZ(alloc) == dimZ);
+ _RS_ASSERT(rsAllocationGetDimX(aRaw) == dimX);
+ _RS_ASSERT(rsAllocationGetDimY(aRaw) == dimY);
+ _RS_ASSERT(rsAllocationGetDimZ(aRaw) == dimZ);
// Test 2D addressing
for (j = 0; j < dimY; j++) {
for (i = 0; i < dimX; i++) {
rsDebug("Verifying ", i + j * dimX);
- const void *p = rsGetElementAt(alloc, i, j);
+ const void *p = rsGetElementAt(aRaw, i, j);
int val = *(const int *)p;
_RS_ASSERT(val == (i + j * dimX));
}
}
// Test 1D addressing
- for (i = 0; i < dimX * dimY; i++) {
+ for (i = 0; i < dimX; i++) {
rsDebug("Verifying ", i);
- const void *p = rsGetElementAt(alloc, i);
+ const void *p = rsGetElementAt(aRaw, i);
int val = *(const int *)p;
_RS_ASSERT(val == i);
}
@@ -46,7 +44,7 @@
for (j = 0; j < dimY; j++) {
for (i = 0; i < dimX; i++) {
rsDebug("Verifying ", i + j * dimX);
- const void *p = rsGetElementAt(alloc, i, j, 0);
+ const void *p = rsGetElementAt(aRaw, i, j, 0);
int val = *(const int *)p;
_RS_ASSERT(val == (i + j * dimX));
}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach.rs
index ac527b5..08e6bed 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach.rs
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach.rs
@@ -1,6 +1,6 @@
#include "shared.rsh"
-int *a;
+rs_allocation aRaw;
int dimX;
int dimY;
static bool failed = false;
@@ -21,7 +21,8 @@
for (j = 0; j < dimY; j++) {
for (i = 0; i < dimX; i++) {
- _RS_ASSERT(a[i + j * dimX] == (i + j * dimX));
+ int v = rsGetElementAt_int(aRaw, i, j);
+ _RS_ASSERT(v == (i + j * dimX));
}
}
@@ -41,7 +42,8 @@
for (j = 0; j < dimY; j++) {
for (i = 0; i < dimX; i++) {
- _RS_ASSERT(a[i + j * dimX] == (99 + i + j * dimX));
+ int v = rsGetElementAt_int(aRaw, i, j);
+ _RS_ASSERT(v == (99 + i + j * dimX));
}
}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach_bounds.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach_bounds.rs
index ddf17f8..89df090 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach_bounds.rs
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach_bounds.rs
@@ -1,6 +1,5 @@
#include "shared.rsh"
-int *a;
int dimX;
int dimY;
int xStart = 0;
@@ -9,6 +8,7 @@
int yEnd = 0;
rs_script s;
+rs_allocation aRaw;
rs_allocation ain;
rs_allocation aout;
@@ -26,13 +26,14 @@
for (j = 0; j < dimY; j++) {
for (i = 0; i < dimX; i++) {
+ int v = rsGetElementAt_int(aRaw, i, j);
rsDebug("i: ", i);
rsDebug("j: ", j);
- rsDebug("a[j][i]: ", a[i + j * dimX]);
+ rsDebug("a[j][i]: ", v);
if (i < xStart || i >= xEnd || j < yStart || j >= yEnd) {
- _RS_ASSERT(a[i + j * dimX] == 0);
+ _RS_ASSERT(v == 0);
} else {
- _RS_ASSERT(a[i + j * dimX] == (i + j * dimX));
+ _RS_ASSERT(v == (i + j * dimX));
}
}
}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/noroot.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/noroot.rs
index 33944aa..2c807bd 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/noroot.rs
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/noroot.rs
@@ -1,6 +1,6 @@
#include "shared.rsh"
-int *a;
+rs_allocation aRaw;
int dimX;
int dimY;
static bool failed = false;
@@ -15,7 +15,8 @@
for (j = 0; j < dimY; j++) {
for (i = 0; i < dimX; i++) {
- _RS_ASSERT(a[i + j * dimX] == (99 + i + j * dimX));
+ int v = rsGetElementAt_int(aRaw, i, j);
+ _RS_ASSERT(v == (99 + i + j * dimX));
}
}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_alloc.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_alloc.java
index a06d820..3ea942c 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_alloc.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_alloc.java
@@ -39,6 +39,7 @@
typeBuilder.setX(X).setY(Y);
Allocation A = Allocation.createTyped(RS, typeBuilder.create());
s.bind_a(A);
+ s.set_aRaw(A);
typeBuilder = new Type.Builder(RS, Element.I32(RS));
typeBuilder.setX(X).setY(Y).setFaces(true);
@@ -59,6 +60,7 @@
ScriptC_alloc s = new ScriptC_alloc(pRS);
pRS.setMessageHandler(mRsMessage);
initializeGlobals(pRS, s);
+ s.forEach_root(s.get_aRaw());
s.invoke_alloc_test();
pRS.finish();
waitForMessage();
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java
index 4951970..6c95109 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java
@@ -37,7 +37,7 @@
s.set_dimY(Y);
typeBuilder.setX(X).setY(Y);
A = Allocation.createTyped(RS, typeBuilder.create());
- s.bind_a(A);
+ s.set_aRaw(A);
return;
}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java
index bda055b..782f788 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java
@@ -37,7 +37,7 @@
s.set_dimY(Y);
typeBuilder.setX(X).setY(Y);
A = Allocation.createTyped(RS, typeBuilder.create());
- s.bind_a(A);
+ s.set_aRaw(A);
s.set_s(s);
s.set_ain(A);
s.set_aout(A);
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_noroot.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_noroot.java
index cc48591..69526a8 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_noroot.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_noroot.java
@@ -37,7 +37,7 @@
s.set_dimY(Y);
typeBuilder.setX(X).setY(Y);
A = Allocation.createTyped(RS, typeBuilder.create());
- s.bind_a(A);
+ s.set_aRaw(A);
return;
}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/alloc.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/alloc.rs
index 3116e5a..1b5e2ac 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/alloc.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/alloc.rs
@@ -5,39 +5,37 @@
int dimY;
int dimZ;
+rs_allocation aRaw;
rs_allocation aFaces;
rs_allocation aLOD;
rs_allocation aFacesLOD;
+void root(int *o, uint32_t x, uint32_t y) {
+ *o = x + y * dimX;
+}
+
static bool test_alloc_dims() {
bool failed = false;
int i, j;
- for (j = 0; j < dimY; j++) {
- for (i = 0; i < dimX; i++) {
- a[i + j * dimX] = i + j * dimX;
- }
- }
-
- rs_allocation alloc = rsGetAllocation(a);
- _RS_ASSERT(rsAllocationGetDimX(alloc) == dimX);
- _RS_ASSERT(rsAllocationGetDimY(alloc) == dimY);
- _RS_ASSERT(rsAllocationGetDimZ(alloc) == dimZ);
+ _RS_ASSERT(rsAllocationGetDimX(aRaw) == dimX);
+ _RS_ASSERT(rsAllocationGetDimY(aRaw) == dimY);
+ _RS_ASSERT(rsAllocationGetDimZ(aRaw) == dimZ);
// Test 2D addressing
for (j = 0; j < dimY; j++) {
for (i = 0; i < dimX; i++) {
rsDebug("Verifying ", i + j * dimX);
- const void *p = rsGetElementAt(alloc, i, j);
+ const void *p = rsGetElementAt(aRaw, i, j);
int val = *(const int *)p;
_RS_ASSERT(val == (i + j * dimX));
}
}
// Test 1D addressing
- for (i = 0; i < dimX * dimY; i++) {
+ for (i = 0; i < dimX; i++) {
rsDebug("Verifying ", i);
- const void *p = rsGetElementAt(alloc, i);
+ const void *p = rsGetElementAt(aRaw, i);
int val = *(const int *)p;
_RS_ASSERT(val == i);
}
@@ -46,7 +44,7 @@
for (j = 0; j < dimY; j++) {
for (i = 0; i < dimX; i++) {
rsDebug("Verifying ", i + j * dimX);
- const void *p = rsGetElementAt(alloc, i, j, 0);
+ const void *p = rsGetElementAt(aRaw, i, j, 0);
int val = *(const int *)p;
_RS_ASSERT(val == (i + j * dimX));
}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs
index ac527b5..08e6bed 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs
@@ -1,6 +1,6 @@
#include "shared.rsh"
-int *a;
+rs_allocation aRaw;
int dimX;
int dimY;
static bool failed = false;
@@ -21,7 +21,8 @@
for (j = 0; j < dimY; j++) {
for (i = 0; i < dimX; i++) {
- _RS_ASSERT(a[i + j * dimX] == (i + j * dimX));
+ int v = rsGetElementAt_int(aRaw, i, j);
+ _RS_ASSERT(v == (i + j * dimX));
}
}
@@ -41,7 +42,8 @@
for (j = 0; j < dimY; j++) {
for (i = 0; i < dimX; i++) {
- _RS_ASSERT(a[i + j * dimX] == (99 + i + j * dimX));
+ int v = rsGetElementAt_int(aRaw, i, j);
+ _RS_ASSERT(v == (99 + i + j * dimX));
}
}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs
index ddf17f8..89df090 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs
@@ -1,6 +1,5 @@
#include "shared.rsh"
-int *a;
int dimX;
int dimY;
int xStart = 0;
@@ -9,6 +8,7 @@
int yEnd = 0;
rs_script s;
+rs_allocation aRaw;
rs_allocation ain;
rs_allocation aout;
@@ -26,13 +26,14 @@
for (j = 0; j < dimY; j++) {
for (i = 0; i < dimX; i++) {
+ int v = rsGetElementAt_int(aRaw, i, j);
rsDebug("i: ", i);
rsDebug("j: ", j);
- rsDebug("a[j][i]: ", a[i + j * dimX]);
+ rsDebug("a[j][i]: ", v);
if (i < xStart || i >= xEnd || j < yStart || j >= yEnd) {
- _RS_ASSERT(a[i + j * dimX] == 0);
+ _RS_ASSERT(v == 0);
} else {
- _RS_ASSERT(a[i + j * dimX] == (i + j * dimX));
+ _RS_ASSERT(v == (i + j * dimX));
}
}
}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/noroot.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/noroot.rs
index 33944aa..2c807bd 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/noroot.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/noroot.rs
@@ -1,6 +1,6 @@
#include "shared.rsh"
-int *a;
+rs_allocation aRaw;
int dimX;
int dimY;
static bool failed = false;
@@ -15,7 +15,8 @@
for (j = 0; j < dimY; j++) {
for (i = 0; i < dimX; i++) {
- _RS_ASSERT(a[i + j * dimX] == (99 + i + j * dimX));
+ int v = rsGetElementAt_int(aRaw, i, j);
+ _RS_ASSERT(v == (99 + i + j * dimX));
}
}
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 5b71adc..2149190 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1185,6 +1185,11 @@
return true;
}
+ if (strcmp(name, "xxxhdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
+ return true;
+ }
+
char* c = (char*)name;
while (*c >= '0' && *c <= '9') {
c++;
diff --git a/tools/layoutlib/bridge/src/android/text/format/DateFormat_Delegate.java b/tools/layoutlib/bridge/src/android/text/format/DateFormat_Delegate.java
new file mode 100644
index 0000000..8cd1a69
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/format/DateFormat_Delegate.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.format;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.content.Context;
+
+
+/**
+ * Delegate used to provide new implementation for the native methods of {@link DateFormat}
+ *
+ * Through the layoutlib_create tool, the original methods of DateFormat have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class DateFormat_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static boolean is24HourFormat(Context context) {
+ return false;
+ }
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 80a1a60..d955040 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -110,6 +110,7 @@
"android.os.Handler#sendMessageAtTime",
"android.os.HandlerThread#run",
"android.os.Build#getString",
+ "android.text.format.DateFormat#is24HourFormat",
"android.view.Choreographer#getRefreshRate",
"android.view.Display#updateDisplayInfoLocked",
"android.view.LayoutInflater#rInflate",
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index 66c2f3f..eb2f74c 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -35,6 +35,7 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.UserHandle;
+import android.security.KeyStore;
import android.text.TextUtils;
import android.util.Log;
@@ -144,6 +145,7 @@
private static final String EOS = "eos";
private WifiNative mWifiNative;
+ private final KeyStore mKeyStore = KeyStore.getInstance();
WifiConfigStore(Context c, WifiNative wn) {
mContext = c;
@@ -295,16 +297,7 @@
boolean forgetNetwork(int netId) {
if (mWifiNative.removeNetwork(netId)) {
mWifiNative.saveConfig();
- WifiConfiguration target = null;
- WifiConfiguration config = mConfiguredNetworks.get(netId);
- if (config != null) {
- target = mConfiguredNetworks.remove(netId);
- mNetworkIds.remove(configKey(config));
- }
- if (target != null) {
- writeIpAndProxyConfigurations();
- sendConfiguredNetworksChangedBroadcast(target, WifiManager.CHANGE_REASON_REMOVED);
- }
+ removeConfigAndSendBroadcastIfNeeded(netId);
return true;
} else {
loge("Failed to remove network " + netId);
@@ -342,20 +335,27 @@
*/
boolean removeNetwork(int netId) {
boolean ret = mWifiNative.removeNetwork(netId);
- WifiConfiguration config = null;
if (ret) {
- config = mConfiguredNetworks.get(netId);
- if (config != null) {
- config = mConfiguredNetworks.remove(netId);
- mNetworkIds.remove(configKey(config));
- }
- }
- if (config != null) {
- sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED);
+ removeConfigAndSendBroadcastIfNeeded(netId);
}
return ret;
}
+ private void removeConfigAndSendBroadcastIfNeeded(int netId) {
+ WifiConfiguration config = mConfiguredNetworks.get(netId);
+ if (config != null) {
+ // Remove any associated keys
+ if (config.enterpriseConfig != null) {
+ config.enterpriseConfig.removeKeys(mKeyStore);
+ }
+ mConfiguredNetworks.remove(netId);
+ mNetworkIds.remove(configKey(config));
+
+ writeIpAndProxyConfigurations();
+ sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED);
+ }
+ }
+
/**
* Enable a network. Note that there is no saveConfig operation.
* This function is retained for compatibility with the public
@@ -1090,13 +1090,48 @@
}
if (config.enterpriseConfig != null) {
- HashMap<String, String> enterpriseFields = config.enterpriseConfig.getFields();
+
+ WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
+
+ if (enterpriseConfig.needsKeyStore()) {
+ /**
+ * Keyguard settings may eventually be controlled by device policy.
+ * We check here if keystore is unlocked before installing
+ * credentials.
+ * TODO: Figure a way to store these credentials for wifi alone
+ * TODO: Do we need a dialog here ?
+ */
+ if (mKeyStore.state() != KeyStore.State.UNLOCKED) {
+ loge(config.SSID + ": key store is locked");
+ break setVariables;
+ }
+
+ try {
+ /* config passed may include only fields being updated.
+ * In order to generate the key id, fetch uninitialized
+ * fields from the currently tracked configuration
+ */
+ WifiConfiguration currentConfig = mConfiguredNetworks.get(netId);
+ String keyId = config.getKeyIdForCredentials(currentConfig);
+
+ if (!enterpriseConfig.installKeys(mKeyStore, keyId)) {
+ loge(config.SSID + ": failed to install keys");
+ break setVariables;
+ }
+ } catch (IllegalStateException e) {
+ loge(config.SSID + " invalid config for key installation");
+ break setVariables;
+ }
+ }
+
+ HashMap<String, String> enterpriseFields = enterpriseConfig.getFields();
for (String key : enterpriseFields.keySet()) {
String value = enterpriseFields.get(key);
if (!mWifiNative.setNetworkVariable(
netId,
key,
value)) {
+ enterpriseConfig.removeKeys(mKeyStore);
loge(config.SSID + ": failed to set " + key +
": " + value);
break setVariables;
@@ -1104,7 +1139,7 @@
}
}
updateFailed = false;
- }
+ } //end of setVariables
if (updateFailed) {
if (newNetwork) {
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 552356c..bf82792 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -19,6 +19,7 @@
import android.net.LinkProperties;
import android.os.Parcelable;
import android.os.Parcel;
+import android.text.TextUtils;
import java.util.BitSet;
@@ -274,7 +275,8 @@
*/
public BitSet allowedGroupCiphers;
/**
- * The enterprise configuration details
+ * The enterprise configuration details specifying the EAP method,
+ * certificates and other settings associated with the EAP.
* @hide
*/
public WifiEnterpriseConfig enterpriseConfig;
@@ -462,6 +464,47 @@
return SSID;
}
+ /**
+ * Get an identifier for associating credentials with this config
+ * @param current configuration contains values for additional fields
+ * that are not part of this configuration. Used
+ * when a config with some fields is passed by an application.
+ * @throws IllegalStateException if config is invalid for key id generation
+ * @hide
+ */
+ String getKeyIdForCredentials(WifiConfiguration current) {
+ String keyMgmt = null;
+
+ try {
+ // Get current config details for fields that are not initialized
+ if (TextUtils.isEmpty(SSID)) SSID = current.SSID;
+ if (allowedKeyManagement.cardinality() == 0) {
+ allowedKeyManagement = current.allowedKeyManagement;
+ }
+ if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
+ keyMgmt = KeyMgmt.strings[KeyMgmt.WPA_EAP];
+ }
+ if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+ keyMgmt += KeyMgmt.strings[KeyMgmt.IEEE8021X];
+ }
+
+ if (TextUtils.isEmpty(keyMgmt)) {
+ throw new IllegalStateException("Not an EAP network");
+ }
+
+ return trimStringForKeyId(SSID) + "_" + keyMgmt + "_" +
+ trimStringForKeyId(enterpriseConfig.getKeyId(current != null ?
+ current.enterpriseConfig : null));
+ } catch (NullPointerException e) {
+ throw new IllegalStateException("Invalid config details");
+ }
+ }
+
+ private String trimStringForKeyId(String string) {
+ // Remove quotes and spaces
+ return string.replace("\"", "").replace(" ", "");
+ }
+
private static BitSet readBitSet(Parcel src) {
int cardinality = src.readInt();
@@ -485,6 +528,9 @@
/** @hide */
public int getAuthType() {
+ if (allowedKeyManagement.cardinality() > 1) {
+ throw new IllegalStateException("More than one auth type set");
+ }
if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
return KeyMgmt.WPA_PSK;
} else if (allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) {
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 4dca7ac..7313e7e 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -19,7 +19,26 @@
import android.os.Parcelable;
import android.security.Credentials;
import android.text.TextUtils;
+import android.util.Log;
+import com.android.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.org.bouncycastle.asn1.DEROctetString;
+import com.android.org.bouncycastle.asn1.x509.BasicConstraints;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
@@ -70,6 +89,9 @@
private static final String PRIVATE_KEY_ID_KEY = "key_id";
private HashMap<String, String> mFields = new HashMap<String, String>();
+ private X509Certificate mCaCert;
+ private PrivateKey mClientPrivateKey;
+ private X509Certificate mClientCertificate;
/** This represents an empty value of an enterprise field.
* NULL is used at wpa_supplicant to indicate an empty value
@@ -103,6 +125,34 @@
dest.writeString(entry.getKey());
dest.writeString(entry.getValue());
}
+
+ writeCertificate(dest, mCaCert);
+
+ if (mClientPrivateKey != null) {
+ String algorithm = mClientPrivateKey.getAlgorithm();
+ byte[] userKeyBytes = mClientPrivateKey.getEncoded();
+ dest.writeInt(userKeyBytes.length);
+ dest.writeByteArray(userKeyBytes);
+ dest.writeString(algorithm);
+ } else {
+ dest.writeInt(0);
+ }
+
+ writeCertificate(dest, mClientCertificate);
+ }
+
+ private void writeCertificate(Parcel dest, X509Certificate cert) {
+ if (cert != null) {
+ try {
+ byte[] certBytes = cert.getEncoded();
+ dest.writeInt(certBytes.length);
+ dest.writeByteArray(certBytes);
+ } catch (CertificateEncodingException e) {
+ dest.writeInt(0);
+ }
+ } else {
+ dest.writeInt(0);
+ }
}
public static final Creator<WifiEnterpriseConfig> CREATOR =
@@ -115,9 +165,47 @@
String value = in.readString();
enterpriseConfig.mFields.put(key, value);
}
+
+ enterpriseConfig.mCaCert = readCertificate(in);
+
+ PrivateKey userKey = null;
+ int len = in.readInt();
+ if (len > 0) {
+ try {
+ byte[] bytes = new byte[len];
+ in.readByteArray(bytes);
+ String algorithm = in.readString();
+ KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
+ userKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes));
+ } catch (NoSuchAlgorithmException e) {
+ userKey = null;
+ } catch (InvalidKeySpecException e) {
+ userKey = null;
+ }
+ }
+
+ enterpriseConfig.mClientPrivateKey = userKey;
+ enterpriseConfig.mClientCertificate = readCertificate(in);
return enterpriseConfig;
}
+ private X509Certificate readCertificate(Parcel in) {
+ X509Certificate cert = null;
+ int len = in.readInt();
+ if (len > 0) {
+ try {
+ byte[] bytes = new byte[len];
+ in.readByteArray(bytes);
+ CertificateFactory cFactory = CertificateFactory.getInstance("X.509");
+ cert = (X509Certificate) cFactory
+ .generateCertificate(new ByteArrayInputStream(bytes));
+ } catch (CertificateException e) {
+ cert = null;
+ }
+ }
+ return cert;
+ }
+
public WifiEnterpriseConfig[] newArray(int size) {
return new WifiEnterpriseConfig[size];
}
@@ -145,13 +233,13 @@
public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP", "MSCHAPV2", "GTC" };
}
- /** Internal use only @hide */
- public HashMap<String, String> getFields() {
+ /** Internal use only */
+ HashMap<String, String> getFields() {
return mFields;
}
- /** Internal use only @hide */
- public static String[] getSupplicantKeys() {
+ /** Internal use only */
+ static String[] getSupplicantKeys() {
return new String[] { EAP_KEY, PHASE2_KEY, IDENTITY_KEY, ANON_IDENTITY_KEY, PASSWORD_KEY,
CLIENT_CERT_KEY, CA_CERT_KEY, SUBJECT_MATCH_KEY, ENGINE_KEY, ENGINE_ID_KEY,
PRIVATE_KEY_ID_KEY };
@@ -271,28 +359,47 @@
* a certificate
* </p>
* @param alias identifies the certificate
+ * @hide
*/
- public void setCaCertificate(String alias) {
+ public void setCaCertificateAlias(String alias) {
setFieldValue(CA_CERT_KEY, alias, CA_CERT_PREFIX);
}
/**
* Get CA certificate alias
* @return alias to the CA certificate
+ * @hide
*/
- public String getCaCertificate() {
+ public String getCaCertificateAlias() {
return getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX);
}
/**
+ * Specify a X.509 certificate that identifies the server.
+ *
+ * <p>A default name is automatically assigned to the certificate and used
+ * with this configuration.
+ * @param cert X.509 CA certificate
+ * @throws IllegalArgumentException if not a CA certificate
+ */
+ public void setCaCertificate(X509Certificate cert) {
+ if (cert.getBasicConstraints() >= 0) {
+ mCaCert = cert;
+ } else {
+ throw new IllegalArgumentException("Not a CA certificate");
+ }
+ }
+
+ /**
* Set Client certificate alias.
*
* <p> See the {@link android.security.KeyChain} for details on installing or choosing
* a certificate
* </p>
* @param alias identifies the certificate
+ * @hide
*/
- public void setClientCertificate(String alias) {
+ public void setClientCertificateAlias(String alias) {
setFieldValue(CLIENT_CERT_KEY, alias, CLIENT_CERT_PREFIX);
setFieldValue(PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY);
// Also, set engine parameters
@@ -308,12 +415,118 @@
/**
* Get client certificate alias
* @return alias to the client certificate
+ * @hide
*/
- public String getClientCertificate() {
+ public String getClientCertificateAlias() {
return getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX);
}
/**
+ * Specify a private key and client certificate for client authorization.
+ *
+ * <p>A default name is automatically assigned to the key entry and used
+ * with this configuration.
+ * @param privateKey
+ * @param clientCertificate
+ */
+ public void setClientKeyEntry(PrivateKey privateKey, X509Certificate clientCertificate) {
+ if (clientCertificate != null) {
+ if (clientCertificate.getBasicConstraints() != -1) {
+ throw new IllegalArgumentException("Cannot be a CA certificate");
+ }
+ if (privateKey == null) {
+ throw new IllegalArgumentException("Client cert without a private key");
+ }
+ if (privateKey.getEncoded() == null) {
+ throw new IllegalArgumentException("Private key cannot be encoded");
+ }
+ }
+
+ mClientPrivateKey = privateKey;
+ mClientCertificate = clientCertificate;
+ }
+
+ boolean needsKeyStore() {
+ // Has no keys to be installed
+ if (mClientCertificate == null && mCaCert == null) return false;
+ return true;
+ }
+
+ boolean installKeys(android.security.KeyStore keyStore, String name) {
+ boolean ret = true;
+ String privKeyName = Credentials.USER_PRIVATE_KEY + name;
+ String userCertName = Credentials.USER_CERTIFICATE + name;
+ String caCertName = Credentials.CA_CERTIFICATE + name;
+ if (mClientCertificate != null) {
+ byte[] privKeyData = mClientPrivateKey.getEncoded();
+ ret = keyStore.importKey(privKeyName, privKeyData);
+ if (ret == false) {
+ return ret;
+ }
+
+ ret = putCertInKeyStore(keyStore, userCertName, mClientCertificate);
+ if (ret == false) {
+ // Remove private key installed
+ keyStore.delKey(privKeyName);
+ return ret;
+ }
+ }
+
+ if (mCaCert != null) {
+ ret = putCertInKeyStore(keyStore, caCertName, mCaCert);
+ if (ret == false) {
+ if (mClientCertificate != null) {
+ // Remove client key+cert
+ keyStore.delKey(privKeyName);
+ keyStore.delete(userCertName);
+ }
+ return ret;
+ }
+ }
+
+ // Set alias names
+ if (mClientCertificate != null) {
+ setClientCertificateAlias(name);
+ mClientPrivateKey = null;
+ mClientCertificate = null;
+ }
+
+ if (mCaCert != null) {
+ setCaCertificateAlias(name);
+ mCaCert = null;
+ }
+
+ return ret;
+ }
+
+ private boolean putCertInKeyStore(android.security.KeyStore keyStore, String name,
+ Certificate cert) {
+ try {
+ byte[] certData = Credentials.convertToPem(cert);
+ return keyStore.put(name, certData);
+ } catch (IOException e1) {
+ return false;
+ } catch (CertificateException e2) {
+ return false;
+ }
+ }
+
+ void removeKeys(android.security.KeyStore keyStore) {
+ String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX);
+ // a valid client certificate is configured
+ if (!TextUtils.isEmpty(client)) {
+ keyStore.delKey(Credentials.USER_PRIVATE_KEY + client);
+ keyStore.delete(Credentials.USER_CERTIFICATE + client);
+ }
+
+ String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX);
+ // a valid ca certificate is configured
+ if (!TextUtils.isEmpty(ca)) {
+ keyStore.delete(Credentials.CA_CERTIFICATE + ca);
+ }
+ }
+
+ /**
* Set subject match. This is the substring to be matched against the subject of the
* authentication server certificate.
* @param subjectMatch substring to be matched
@@ -330,13 +543,28 @@
return getFieldValue(SUBJECT_MATCH_KEY, "");
}
+ /** See {@link WifiConfiguration#getKeyIdForCredentials} @hide */
+ String getKeyId(WifiEnterpriseConfig current) {
+ String eap = mFields.get(EAP_KEY);
+ String phase2 = mFields.get(PHASE2_KEY);
+
+ // If either eap or phase2 are not initialized, use current config details
+ if (TextUtils.isEmpty((eap))) {
+ eap = current.mFields.get(EAP_KEY);
+ }
+ if (TextUtils.isEmpty(phase2)) {
+ phase2 = current.mFields.get(PHASE2_KEY);
+ }
+ return eap + "_" + phase2;
+ }
+
/** Migrates the old style TLS config to the new config style. This should only be used
* when restoring an old wpa_supplicant.conf or upgrading from a previous
* platform version.
* @return true if the config was updated
* @hide
*/
- public boolean migrateOldEapTlsNative(WifiNative wifiNative, int netId) {
+ boolean migrateOldEapTlsNative(WifiNative wifiNative, int netId) {
String oldPrivateKey = wifiNative.getNetworkVariable(netId, OLD_PRIVATE_KEY_NAME);
/*
* If the old configuration value is not present, then there is nothing
@@ -395,6 +623,7 @@
* @return the index into array
*/
private int getStringIndex(String arr[], String toBeFound, int defaultIndex) {
+ if (TextUtils.isEmpty(toBeFound)) return defaultIndex;
for (int i = 0; i < arr.length; i++) {
if (toBeFound.equals(arr[i])) return i;
}
@@ -408,7 +637,8 @@
*/
private String getFieldValue(String key, String prefix) {
String value = mFields.get(key);
- if (EMPTY_VALUE.equals(value)) return "";
+ // Uninitialized or known to be empty after reading from supplicant
+ if (TextUtils.isEmpty(value) || EMPTY_VALUE.equals(value)) return "";
return removeDoubleQuotes(value).substring(prefix.length());
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 77604a4..1589fec 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -1332,10 +1332,19 @@
P2pStateMachine.this, mGroup.getInterface());
mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
WifiP2pDevice groupOwner = mGroup.getOwner();
- /* update group owner details with the ones found at discovery */
- groupOwner.updateSupplicantDetails(mPeers.get(groupOwner.deviceAddress));
- mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
- sendPeersChangedBroadcast();
+ WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress);
+ if (peer != null) {
+ // update group owner details with peer details found at discovery
+ groupOwner.updateSupplicantDetails(peer);
+ mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
+ sendPeersChangedBroadcast();
+ } else {
+ // A supplicant bug can lead to reporting an invalid
+ // group owner address (all zeroes) at times. Avoid a
+ // crash, but continue group creation since it is not
+ // essential.
+ logw("Unknown group owner " + groupOwner);
+ }
}
transitionTo(mGroupCreatedState);
break;