Merge "Make touch states neutralized by replacing default pressed states for most fw widgets" into klp-dev
diff --git a/Android.mk b/Android.mk
index 30b17f5..14d1a02 100644
--- a/Android.mk
+++ b/Android.mk
@@ -120,6 +120,7 @@
core/java/android/hardware/ICameraServiceListener.aidl \
core/java/android/hardware/ICamera.aidl \
core/java/android/hardware/ICameraClient.aidl \
+ core/java/android/hardware/IConsumerIrService.aidl \
core/java/android/hardware/IProCameraUser.aidl \
core/java/android/hardware/IProCameraCallbacks.aidl \
core/java/android/hardware/camera2/ICameraDeviceUser.aidl \
@@ -195,8 +196,6 @@
core/java/android/view/IWindowSession.aidl \
core/java/android/speech/IRecognitionListener.aidl \
core/java/android/speech/IRecognitionService.aidl \
- core/java/android/speech/hotword/IHotwordRecognitionListener.aidl \
- core/java/android/speech/hotword/IHotwordRecognitionService.aidl \
core/java/android/speech/tts/ITextToSpeechCallback.aidl \
core/java/android/speech/tts/ITextToSpeechService.aidl \
core/java/com/android/internal/app/IAppOpsCallback.aidl \
@@ -266,6 +265,8 @@
wifi/java/android/net/wifi/IWifiManager.aidl \
wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
packages/services/PacProcessor/com/android/net/IProxyService.aidl \
+ packages/services/Proxy/com/android/net/IProxyCallback.aidl \
+ packages/services/Proxy/com/android/net/IProxyPortListener.aidl \
# FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk
LOCAL_AIDL_INCLUDES += $(FRAMEWORKS_BASE_JAVA_SRC_DIRS)
@@ -537,6 +538,13 @@
sample_dir := development/samples
new_sample_dir := developers/samples/android
+# Whitelist of valid groups, used for default TOC grouping. Each sample must
+# belong to one (and only one) group. Assign samples to groups by setting
+# a sample.group var to one of these groups in the sample's _index.jd.
+sample_groups := -samplegroup Input \
+ -samplegroup Sensors \
+ -samplegroup Connectivity
+
# the list here should match the list of samples included in the sdk samples package
# (see development/build/sdk.atree)
# remove htmlified samples for now -- samples are still available through the SDK
@@ -770,7 +778,8 @@
LOCAL_DROIDDOC_OPTIONS:= \
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
-toroot / \
- -hdf android.whichdoc online
+ -hdf android.whichdoc online
+# $(sample_groups) \
# $(web_docs_sample_code_flags)
LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 8809bc7..797d088 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -179,6 +179,7 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/usr/idc/frameworks)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/usr/keylayout/frameworks)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/usr/keychars/frameworks)
+$(call add-clean-step, rm -f $(PRODUCT_OUT)/system/media/video/*)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
diff --git a/api/current.txt b/api/current.txt
index fe0fd6e..cbed2e7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20,6 +20,7 @@
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+ field public static final java.lang.String BIND_CALL_SERVICE = "android.permission.BIND_CALL_SERVICE";
field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
@@ -129,6 +130,7 @@
field public static final java.lang.String SUBSCRIBED_FEEDS_READ = "android.permission.SUBSCRIBED_FEEDS_READ";
field public static final java.lang.String SUBSCRIBED_FEEDS_WRITE = "android.permission.SUBSCRIBED_FEEDS_WRITE";
field public static final java.lang.String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
+ field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS";
field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
@@ -227,6 +229,7 @@
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
field public static final int accessibilityFlags = 16843652; // 0x1010384
+ field public static final int accessibilityLiveRegion = 16843758; // 0x10103ee
field public static final int accountPreferences = 16843423; // 0x101029f
field public static final int accountType = 16843407; // 0x101028f
field public static final int action = 16842797; // 0x101002d
@@ -289,14 +292,14 @@
field public static final deprecated int animationResolution = 16843546; // 0x101031a
field public static final int antialias = 16843034; // 0x101011a
field public static final int anyDensity = 16843372; // 0x101026c
- field public static final int apduServiceBanner = 16843758; // 0x10103ee
+ field public static final int apduServiceBanner = 16843757; // 0x10103ed
field public static final int apiKey = 16843281; // 0x1010211
field public static final int author = 16843444; // 0x10102b4
field public static final int authorities = 16842776; // 0x1010018
field public static final int autoAdvanceViewId = 16843535; // 0x101030f
field public static final int autoCompleteTextViewStyle = 16842859; // 0x101006b
field public static final int autoLink = 16842928; // 0x10100b0
- field public static final int autoMirrored = 16843755; // 0x10103eb
+ field public static final int autoMirrored = 16843754; // 0x10103ea
field public static final int autoStart = 16843445; // 0x10102b5
field public static final deprecated int autoText = 16843114; // 0x101016a
field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -393,7 +396,6 @@
field public static final int cropToPadding = 16843043; // 0x1010123
field public static final int cursorVisible = 16843090; // 0x1010152
field public static final int customNavigationLayout = 16843474; // 0x10102d2
- field public static final int customRoots = 16843754; // 0x10103ea
field public static final int customTokens = 16843579; // 0x101033b
field public static final int cycles = 16843220; // 0x10101d4
field public static final int dashGap = 16843175; // 0x10101a7
@@ -846,7 +848,6 @@
field public static final int prompt = 16843131; // 0x101017b
field public static final int propertyName = 16843489; // 0x10102e1
field public static final int protectionLevel = 16842761; // 0x1010009
- field public static final int provideAssistData = 16843759; // 0x10103ef
field public static final int publicKey = 16843686; // 0x10103a6
field public static final int queryActionMsg = 16843227; // 0x10101db
field public static final int queryAfterZeroResults = 16843394; // 0x1010282
@@ -871,7 +872,7 @@
field public static final int reqKeyboardType = 16843304; // 0x1010228
field public static final int reqNavigation = 16843306; // 0x101022a
field public static final int reqTouchScreen = 16843303; // 0x1010227
- field public static final int requireDeviceUnlock = 16843757; // 0x10103ed
+ field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
@@ -1020,7 +1021,7 @@
field public static final int summaryOff = 16843248; // 0x10101f0
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsRtl = 16843695; // 0x10103af
- field public static final int supportsSwitchingToNextInputMethod = 16843756; // 0x10103ec
+ field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
field public static final int supportsUploading = 16843419; // 0x101029b
field public static final int switchMinWidth = 16843632; // 0x1010370
field public static final int switchPadding = 16843633; // 0x1010371
@@ -2726,8 +2727,6 @@
method public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public void closeContextMenu();
method public void closeOptionsMenu();
- method public void convertFromTranslucent();
- method public void convertToTranslucent(android.app.Activity.TranslucentConversionListener);
method public android.app.PendingIntent createPendingResult(int, android.content.Intent, int);
method public final deprecated void dismissDialog(int);
method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
@@ -2913,10 +2912,6 @@
field public static final int RESULT_OK = -1; // 0xffffffff
}
- public static abstract interface Activity.TranslucentConversionListener {
- method public abstract void onTranslucentConversionComplete(boolean);
- }
-
public deprecated class ActivityGroup extends android.app.Activity {
ctor public ActivityGroup();
ctor public ActivityGroup(boolean);
@@ -4247,7 +4242,6 @@
method public void onCreate();
method public void onDestroy();
method public void onLowMemory();
- method public void onProvideAssistData(android.os.Bundle);
method public void onRebind(android.content.Intent);
method public deprecated void onStart(android.content.Intent, int);
method public int onStartCommand(android.content.Intent, int, int);
@@ -4371,6 +4365,7 @@
method public void clear() throws java.io.IOException;
method public void clearWallpaperOffsets(android.os.IBinder);
method public void forgetLoadedWallpaper();
+ method public android.content.Intent getCropAndSetWallpaperIntent(android.net.Uri);
method public int getDesiredMinimumHeight();
method public int getDesiredMinimumWidth();
method public android.graphics.drawable.Drawable getDrawable();
@@ -4388,6 +4383,7 @@
method public void setWallpaperOffsets(android.os.IBinder, float, float);
method public void suggestDesiredDimensions(int, int);
field public static final java.lang.String ACTION_CHANGE_LIVE_WALLPAPER = "android.service.wallpaper.CHANGE_LIVE_WALLPAPER";
+ field public static final java.lang.String ACTION_CROP_AND_SET_WALLPAPER = "android.service.wallpaper.CROP_AND_SET_WALLPAPER";
field public static final java.lang.String ACTION_LIVE_WALLPAPER_CHOOSER = "android.service.wallpaper.LIVE_WALLPAPER_CHOOSER";
field public static final java.lang.String COMMAND_DROP = "android.home.drop";
field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
@@ -5971,6 +5967,7 @@
field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
+ field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
field public static final int CONTEXT_INCLUDE_CODE = 1; // 0x1
field public static final int CONTEXT_RESTRICTED = 4; // 0x4
@@ -5990,6 +5987,7 @@
field public static final int MODE_PRIVATE = 0; // 0x0
field public static final deprecated int MODE_WORLD_READABLE = 1; // 0x1
field public static final deprecated int MODE_WORLD_WRITEABLE = 2; // 0x2
+ field public static final java.lang.String NETWORKMANAGEMENT_SERVICE = "network_management";
field public static final java.lang.String NFC_SERVICE = "nfc";
field public static final java.lang.String NOTIFICATION_SERVICE = "notification";
field public static final java.lang.String NSD_SERVICE = "servicediscovery";
@@ -6407,7 +6405,6 @@
field public static final java.lang.String ACTION_USER_INITIALIZE = "android.intent.action.USER_INITIALIZE";
field public static final java.lang.String ACTION_USER_PRESENT = "android.intent.action.USER_PRESENT";
field public static final java.lang.String ACTION_VIEW = "android.intent.action.VIEW";
- field public static final java.lang.String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
field public static final java.lang.String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
field public static final deprecated java.lang.String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED";
field public static final java.lang.String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH";
@@ -6449,8 +6446,6 @@
field public static final deprecated java.lang.String EXTRA_ALLOW_REPLACE = "android.intent.extra.ALLOW_REPLACE";
field public static final java.lang.String EXTRA_ASSIST_CONTEXT = "android.intent.extra.ASSIST_CONTEXT";
field public static final java.lang.String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
- field public static final java.lang.String EXTRA_ASSIST_SERVICES_CONTEXTS = "android.intent.extra.ASSIST_SERVICES_CONTEXTS";
- field public static final java.lang.String EXTRA_ASSIST_SERVICES_PACKAGES = "android.intent.extra.ASSIST_SERVICES_PACKAGES";
field public static final java.lang.String EXTRA_BCC = "android.intent.extra.BCC";
field public static final java.lang.String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
field public static final java.lang.String EXTRA_CC = "android.intent.extra.CC";
@@ -7265,6 +7260,7 @@
field public static final java.lang.String FEATURE_CAMERA_AUTOFOCUS = "android.hardware.camera.autofocus";
field public static final java.lang.String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
field public static final java.lang.String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
+ field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
@@ -7450,7 +7446,6 @@
method public void dump(android.util.Printer, java.lang.String);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int FLAG_ISOLATED_PROCESS = 2; // 0x2
- field public static final int FLAG_PROVIDE_ASSIST_DATA = 4; // 0x4
field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1
field public int flags;
@@ -8140,7 +8135,7 @@
public class MatrixCursor.RowBuilder {
method public android.database.MatrixCursor.RowBuilder add(java.lang.Object);
- method public android.database.MatrixCursor.RowBuilder offer(java.lang.String, java.lang.Object);
+ method public android.database.MatrixCursor.RowBuilder add(java.lang.String, java.lang.Object);
}
public class MergeCursor extends android.database.AbstractCursor {
@@ -9926,7 +9921,7 @@
method public abstract void onFrameAvailable(android.graphics.SurfaceTexture);
}
- public static class SurfaceTexture.OutOfResourcesException extends java.lang.Exception {
+ public static deprecated class SurfaceTexture.OutOfResourcesException extends java.lang.Exception {
ctor public SurfaceTexture.OutOfResourcesException();
ctor public SurfaceTexture.OutOfResourcesException(java.lang.String);
}
@@ -10629,6 +10624,18 @@
field public int width;
}
+ public final class ConsumerIrManager {
+ method public android.hardware.ConsumerIrManager.CarrierFrequencyRange[] getCarrierFrequencies();
+ method public boolean hasIrEmitter();
+ method public void transmit(int, int[]);
+ }
+
+ public final class ConsumerIrManager.CarrierFrequencyRange {
+ ctor public ConsumerIrManager.CarrierFrequencyRange(int, int);
+ method public int getMaxFrequency();
+ method public int getMinFrequency();
+ }
+
public abstract interface FlushCompleteListener {
method public abstract void onFlushCompleted(android.hardware.Sensor);
}
@@ -10807,58 +10814,58 @@
}
public abstract interface CameraDevice implements java.lang.AutoCloseable {
- method public abstract void capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener) throws android.hardware.camera2.CameraAccessException;
- method public abstract void captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract void close() throws java.lang.Exception;
method public abstract void configureOutputs(java.util.List<android.view.Surface>) throws android.hardware.camera2.CameraAccessException;
- method public abstract android.hardware.camera2.CaptureRequest createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
+ method public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
method public abstract void flush() throws android.hardware.camera2.CameraAccessException;
+ method public abstract java.lang.String getId();
method public abstract android.hardware.camera2.CameraProperties getProperties() throws android.hardware.camera2.CameraAccessException;
- method public abstract void setErrorListener(android.hardware.camera2.CameraDevice.ErrorListener);
- method public abstract void setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener) throws android.hardware.camera2.CameraAccessException;
- method public abstract void setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void setDeviceListener(android.hardware.camera2.CameraDevice.CameraDeviceListener, android.os.Handler);
+ method public abstract void setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException;
method public abstract void waitUntilIdle() throws android.hardware.camera2.CameraAccessException;
- field public static final int TEMPLATE_MANUAL = 5; // 0x5
field public static final int TEMPLATE_PREVIEW = 1; // 0x1
field public static final int TEMPLATE_RECORD = 3; // 0x3
field public static final int TEMPLATE_STILL_CAPTURE = 2; // 0x2
field public static final int TEMPLATE_VIDEO_SNAPSHOT = 4; // 0x4
}
- public static abstract interface CameraDevice.CaptureListener {
- method public abstract void onCaptureComplete(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
- method public abstract void onCaptureFailed(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest);
+ public static abstract class CameraDevice.CameraDeviceListener {
+ ctor public CameraDevice.CameraDeviceListener();
+ method public void onCameraDisconnected(android.hardware.camera2.CameraDevice);
+ method public void onCameraError(android.hardware.camera2.CameraDevice, int);
+ method public void onCameraIdle(android.hardware.camera2.CameraDevice);
+ field public static final int ERROR_CAMERA_DEVICE = 1; // 0x1
+ field public static final int ERROR_CAMERA_SERVICE = 2; // 0x2
}
- public static abstract interface CameraDevice.ErrorListener {
- method public abstract void onCameraDeviceError(android.hardware.camera2.CameraDevice, int);
- field public static final int DEVICE_DISCONNECTED = 1; // 0x1
- field public static final int DEVICE_ERROR = 2; // 0x2
- field public static final int SERVICE_ERROR = 3; // 0x3
+ public static abstract class CameraDevice.CaptureListener {
+ ctor public CameraDevice.CaptureListener();
+ method public void onCaptureCompleted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
+ method public void onCaptureFailed(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest);
+ method public void onCaptureStarted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, long);
}
public final class CameraManager {
+ method public void addAvailabilityListener(android.hardware.camera2.CameraManager.AvailabilityListener, android.os.Handler);
+ method public java.lang.String[] getCameraIdList() throws android.hardware.camera2.CameraAccessException;
method public android.hardware.camera2.CameraProperties getCameraProperties(java.lang.String) throws android.hardware.camera2.CameraAccessException;
- method public java.lang.String[] getDeviceIdList() throws android.hardware.camera2.CameraAccessException;
method public android.hardware.camera2.CameraDevice openCamera(java.lang.String) throws android.hardware.camera2.CameraAccessException;
- method public void registerCameraListener(android.hardware.camera2.CameraManager.CameraListener);
- method public void unregisterCameraListener(android.hardware.camera2.CameraManager.CameraListener);
+ method public void removeAvailabilityListener(android.hardware.camera2.CameraManager.AvailabilityListener);
}
- public static abstract interface CameraManager.CameraListener {
- method public abstract void onCameraAvailable(java.lang.String);
- method public abstract void onCameraUnavailable(java.lang.String);
+ public static abstract class CameraManager.AvailabilityListener {
+ ctor public CameraManager.AvailabilityListener();
+ method public void onCameraAvailable(java.lang.String);
+ method public void onCameraUnavailable(java.lang.String);
}
- public class CameraMetadata implements java.lang.AutoCloseable android.os.Parcelable {
- ctor public CameraMetadata();
- method public void close() throws java.lang.Exception;
- method public int describeContents();
- method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
- method public void readFromParcel(android.os.Parcel);
- method public void set(android.hardware.camera2.CameraMetadata.Key<T>, T);
- method public void writeToParcel(android.os.Parcel, int);
+ public abstract class CameraMetadata {
+ method public abstract T get(android.hardware.camera2.CameraMetadata.Key<T>);
+ method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getKeys();
field public static final int COLOR_CORRECTION_MODE_FAST = 1; // 0x1
field public static final int COLOR_CORRECTION_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0; // 0x0
@@ -10942,7 +10949,6 @@
field public static final int CONTROL_SCENE_MODE_SUNSET = 10; // 0xa
field public static final int CONTROL_SCENE_MODE_THEATRE = 7; // 0x7
field public static final int CONTROL_SCENE_MODE_UNSUPPORTED = 0; // 0x0
- field public static final android.os.Parcelable.Creator CREATOR;
field public static final int EDGE_MODE_FAST = 1; // 0x1
field public static final int EDGE_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int EDGE_MODE_OFF = 0; // 0x0
@@ -10959,6 +10965,7 @@
field public static final int LENS_FACING_FRONT = 0; // 0x0
field public static final int LENS_OPTICAL_STABILIZATION_MODE_OFF = 0; // 0x0
field public static final int LENS_OPTICAL_STABILIZATION_MODE_ON = 1; // 0x1
+ field public static final int LENS_STATE_MOVING = 1; // 0x1
field public static final int LENS_STATE_STATIONARY = 0; // 0x0
field public static final int NOISE_REDUCTION_MODE_FAST = 1; // 0x1
field public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2; // 0x2
@@ -10966,6 +10973,8 @@
field public static final int STATISTICS_FACE_DETECT_MODE_FULL = 2; // 0x2
field public static final int STATISTICS_FACE_DETECT_MODE_OFF = 0; // 0x0
field public static final int STATISTICS_FACE_DETECT_MODE_SIMPLE = 1; // 0x1
+ field public static final int STATISTICS_LENS_SHADING_MAP_MODE_OFF = 0; // 0x0
+ field public static final int STATISTICS_LENS_SHADING_MAP_MODE_ON = 1; // 0x1
field public static final int STATISTICS_SCENE_FLICKER_50HZ = 1; // 0x1
field public static final int STATISTICS_SCENE_FLICKER_60HZ = 2; // 0x2
field public static final int STATISTICS_SCENE_FLICKER_NONE = 0; // 0x0
@@ -10975,14 +10984,15 @@
}
public static class CameraMetadata.Key {
- ctor public CameraMetadata.Key(java.lang.String, java.lang.Class<T>);
method public final boolean equals(java.lang.Object);
method public final java.lang.String getName();
method public final int hashCode();
}
public final class CameraProperties extends android.hardware.camera2.CameraMetadata {
- ctor public CameraProperties();
+ method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
+ method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getAvailableCaptureRequestKeys();
+ method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getAvailableCaptureResultKeys();
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_COMPENSATION_RANGE;
@@ -11025,10 +11035,10 @@
}
public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
- method public void addTarget(android.view.Surface);
+ method public int describeContents();
+ method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
method public java.lang.Object getTag();
- method public void removeTarget(android.view.Surface);
- method public void setTag(java.lang.Object);
+ method public void writeToParcel(android.os.Parcel, int);
field public static final android.hardware.camera2.CameraMetadata.Key BLACK_LEVEL_LOCK;
field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_GAINS;
field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_MODE;
@@ -11072,13 +11082,24 @@
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_DETECT_MODE;
+ field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_BLUE;
field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_GREEN;
field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_RED;
field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
}
+ public static final class CaptureRequest.Builder {
+ method public void addTarget(android.view.Surface);
+ method public android.hardware.camera2.CaptureRequest build();
+ method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
+ method public void removeTarget(android.view.Surface);
+ method public void set(android.hardware.camera2.CameraMetadata.Key<T>, T);
+ method public void setTag(java.lang.Object);
+ }
+
public final class CaptureResult extends android.hardware.camera2.CameraMetadata {
+ method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
field public static final android.hardware.camera2.CameraMetadata.Key BLACK_LEVEL_LOCK;
field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_GAINS;
field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_TRANSFORM;
@@ -11116,6 +11137,7 @@
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEMPERATURE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TIMESTAMP;
+ field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACES;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_DETECT_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_IDS;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_LANDMARKS;
@@ -11131,14 +11153,16 @@
field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
}
- public static class CaptureResult.Face {
- ctor public CaptureResult.Face();
+ public final class Face {
method public android.graphics.Rect getBounds();
method public int getId();
- method public android.graphics.Point getLeftEye();
- method public android.graphics.Point getMouth();
- method public android.graphics.Point getRightEye();
+ method public android.graphics.Point getLeftEyePosition();
+ method public android.graphics.Point getMouthPosition();
+ method public android.graphics.Point getRightEyePosition();
method public int getScore();
+ field public static final int ID_UNSUPPORTED = -1; // 0xffffffff
+ field public static final int SCORE_MAX = 100; // 0x64
+ field public static final int SCORE_MIN = 1; // 0x1
}
public final class Rational {
@@ -12173,7 +12197,7 @@
method public int getSampleRate();
method public int getState();
method public int getStreamType();
- method public android.media.AudioTimestamp getTimestamp(android.media.AudioTimestamp);
+ method public boolean getTimestamp(android.media.AudioTimestamp);
method public void pause() throws java.lang.IllegalStateException;
method public void play() throws java.lang.IllegalStateException;
method public void release();
@@ -12319,7 +12343,7 @@
field public static final int EULER_Z = 2; // 0x2
}
- public abstract interface Image implements java.lang.AutoCloseable {
+ public abstract class Image implements java.lang.AutoCloseable {
method public abstract void close();
method public abstract int getFormat();
method public abstract int getHeight();
@@ -12328,23 +12352,23 @@
method public abstract int getWidth();
}
- public static abstract interface Image.Plane {
+ public static abstract class Image.Plane {
method public abstract java.nio.ByteBuffer getBuffer();
method public abstract int getPixelStride();
method public abstract int getRowStride();
}
- public final class ImageReader implements java.lang.AutoCloseable {
- ctor public ImageReader(int, int, int, int);
+ public class ImageReader implements java.lang.AutoCloseable {
+ method public android.media.Image acquireLatestImage();
+ method public android.media.Image acquireNextImage();
method public void close();
method public int getHeight();
method public int getImageFormat();
method public int getMaxImages();
- method public android.media.Image getNextImage();
method public android.view.Surface getSurface();
method public int getWidth();
- method public void releaseImage(android.media.Image);
- method public void setImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
+ method public static android.media.ImageReader newInstance(int, int, int, int);
+ method public void setOnImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
}
public static abstract interface ImageReader.OnImageAvailableListener {
@@ -12737,7 +12761,9 @@
field public static final java.lang.String KEY_IS_ADTS = "is-adts";
field public static final java.lang.String KEY_I_FRAME_INTERVAL = "i-frame-interval";
field public static final java.lang.String KEY_LANGUAGE = "language";
+ field public static final java.lang.String KEY_MAX_HEIGHT = "max-height";
field public static final java.lang.String KEY_MAX_INPUT_SIZE = "max-input-size";
+ field public static final java.lang.String KEY_MAX_WIDTH = "max-width";
field public static final java.lang.String KEY_MIME = "mime";
field public static final java.lang.String KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
field public static final java.lang.String KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after";
@@ -12745,6 +12771,25 @@
field public static final java.lang.String KEY_WIDTH = "width";
}
+ public abstract class MediaMetadataEditor {
+ method public synchronized void addEditableKey(int);
+ method public abstract void apply();
+ method public synchronized void clear();
+ method public synchronized android.graphics.Bitmap getBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+ method public synchronized int[] getEditableKeys();
+ method public synchronized long getLong(int, long) throws java.lang.IllegalArgumentException;
+ method public synchronized java.lang.Object getObject(int, java.lang.Object) throws java.lang.IllegalArgumentException;
+ method public synchronized java.lang.String getString(int, java.lang.String) throws java.lang.IllegalArgumentException;
+ method public synchronized android.media.MediaMetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+ method public synchronized android.media.MediaMetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
+ method public synchronized android.media.MediaMetadataEditor putObject(int, java.lang.Object) throws java.lang.IllegalArgumentException;
+ method public synchronized android.media.MediaMetadataEditor putString(int, java.lang.String) throws java.lang.IllegalArgumentException;
+ method public synchronized void removeEditableKeys();
+ field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
+ field public static final int RATING_KEY_BY_OTHERS = 101; // 0x65
+ field public static final int RATING_KEY_BY_USER = 268435457; // 0x10000001
+ }
+
public class MediaMetadataRetriever {
ctor public MediaMetadataRetriever();
method public java.lang.String extractMetadata(int);
@@ -12791,6 +12836,7 @@
ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException;
method public int addTrack(android.media.MediaFormat);
method public void release();
+ method public void setLocation(float, float);
method public void setOrientationHint(int);
method public void start();
method public void stop();
@@ -13160,6 +13206,29 @@
ctor public NotProvisionedException(java.lang.String);
}
+ public final class Rating implements android.os.Parcelable {
+ method public int describeContents();
+ method public float getPercentRating();
+ method public int getRatingStyle();
+ method public float getStarRating();
+ method public boolean hasHeart();
+ method public boolean isRated();
+ method public boolean isThumbUp();
+ method public static android.media.Rating newHeartRating(boolean);
+ method public static android.media.Rating newPercentageRating(float);
+ method public static android.media.Rating newStarRating(int, float);
+ method public static android.media.Rating newThumbRating(boolean);
+ method public static android.media.Rating newUnratedRating(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int RATING_3_STARS = 3; // 0x3
+ field public static final int RATING_4_STARS = 4; // 0x4
+ field public static final int RATING_5_STARS = 5; // 0x5
+ field public static final int RATING_HEART = 1; // 0x1
+ field public static final int RATING_PERCENTAGE = 6; // 0x6
+ field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+ }
+
public class RemoteControlClient {
ctor public RemoteControlClient(android.app.PendingIntent);
ctor public RemoteControlClient(android.app.PendingIntent, android.os.Looper);
@@ -13191,21 +13260,9 @@
field public static final int PLAYSTATE_STOPPED = 1; // 0x1
}
- public class RemoteControlClient.MetadataEditor {
- method public synchronized void addEditableKey(int);
+ public class RemoteControlClient.MetadataEditor extends android.media.MediaMetadataEditor {
method public synchronized void apply();
- method public synchronized void clear();
- method public synchronized void clearEditableKeys();
- method public synchronized android.media.RemoteControlClient.MetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
- method public synchronized android.media.RemoteControlClient.MetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
- method public synchronized android.media.RemoteControlClient.MetadataEditor putString(int, java.lang.String) throws java.lang.IllegalArgumentException;
field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
- field public static final int LONG_KEY_RATING_BY_OTHERS = 102; // 0x66
- field public static final int LONG_KEY_RATING_BY_USER = 268435457; // 0x10000001
- field public static final int LONG_KEY_RATING_TYPE = 101; // 0x65
- field public static final long RATING_HEART = -1L; // 0xffffffffffffffffL
- field public static final long RATING_NOT_RATED = -101L; // 0xffffffffffffff9bL
- field public static final long RATING_THUMB_UP_DOWN = -2L; // 0xfffffffffffffffeL
}
public static abstract interface RemoteControlClient.OnGetPlaybackPositionListener {
@@ -13213,9 +13270,7 @@
}
public static abstract interface RemoteControlClient.OnMetadataUpdateListener {
- method public abstract void onMetadataUpdateBitmap(int, android.graphics.Bitmap);
- method public abstract void onMetadataUpdateLong(int, long);
- method public abstract void onMetadataUpdateString(int, java.lang.String);
+ method public abstract void onMetadataUpdate(int, java.lang.Object);
}
public static abstract interface RemoteControlClient.OnPlaybackPositionUpdateListener {
@@ -13616,6 +13671,12 @@
field public short numBands;
}
+ public class LoudnessEnhancer extends android.media.audiofx.AudioEffect {
+ method public float getTargetGain() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
+ method public void setTargetGain(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
+ field public static final int PARAM_TARGET_GAIN_MB = 0; // 0x0
+ }
+
public class NoiseSuppressor extends android.media.audiofx.AudioEffect {
method public static android.media.audiofx.NoiseSuppressor create(int);
method public static boolean isAvailable();
@@ -15193,9 +15254,9 @@
field public static final java.lang.String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
field public static final java.lang.String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
field public static final java.lang.String EXTRA_TAG = "android.nfc.extra.TAG";
- field public static final int FLAG_READER_KOVIO = 16; // 0x10
field public static final int FLAG_READER_NFC_A = 1; // 0x1
field public static final int FLAG_READER_NFC_B = 2; // 0x2
+ field public static final int FLAG_READER_NFC_BARCODE = 16; // 0x10
field public static final int FLAG_READER_NFC_F = 4; // 0x4
field public static final int FLAG_READER_NFC_V = 8; // 0x8
field public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 256; // 0x100
@@ -15267,7 +15328,7 @@
method public final void notifyUnhandled();
method public final android.os.IBinder onBind(android.content.Intent);
method public abstract void onDeactivated(int);
- method public byte[] processCommandApdu(byte[], android.os.Bundle);
+ method public abstract byte[] processCommandApdu(byte[], android.os.Bundle);
method public final void sendResponseApdu(byte[]);
field public static final int DEACTIVATION_DESELECTED = 1; // 0x1
field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
@@ -17885,13 +17946,6 @@
public static class Debug.MemoryInfo implements android.os.Parcelable {
ctor public Debug.MemoryInfo();
method public int describeContents();
- method public static java.lang.String getOtherLabel(int);
- method public int getOtherPrivateClean(int);
- method public int getOtherPrivateDirty(int);
- method public int getOtherPss(int);
- method public int getOtherSharedClean(int);
- method public int getOtherSharedDirty(int);
- method public int getOtherSwappablePss(int);
method public int getTotalPrivateClean();
method public int getTotalPrivateDirty();
method public int getTotalPss();
@@ -17957,6 +18011,7 @@
method public static boolean isExternalStorageRemovable();
field public static java.lang.String DIRECTORY_ALARMS;
field public static java.lang.String DIRECTORY_DCIM;
+ field public static java.lang.String DIRECTORY_DOCUMENTS;
field public static java.lang.String DIRECTORY_DOWNLOADS;
field public static java.lang.String DIRECTORY_MOVIES;
field public static java.lang.String DIRECTORY_MUSIC;
@@ -19021,8 +19076,8 @@
method public void clear();
method public int describeContents();
method public int getColorMode();
- method public android.print.PrintAttributes.Margins getMargins();
method public android.print.PrintAttributes.MediaSize getMediaSize();
+ method public android.print.PrintAttributes.Margins getMinMargins();
method public android.print.PrintAttributes.Resolution getResolution();
method public void writeToParcel(android.os.Parcel, int);
field public static final int COLOR_MODE_COLOR = 2; // 0x2
@@ -19032,10 +19087,10 @@
public static final class PrintAttributes.Builder {
ctor public PrintAttributes.Builder();
- method public android.print.PrintAttributes create();
+ method public android.print.PrintAttributes build();
method public android.print.PrintAttributes.Builder setColorMode(int);
- method public android.print.PrintAttributes.Builder setMargins(android.print.PrintAttributes.Margins);
method public android.print.PrintAttributes.Builder setMediaSize(android.print.PrintAttributes.MediaSize);
+ method public android.print.PrintAttributes.Builder setMinMargins(android.print.PrintAttributes.Margins);
method public android.print.PrintAttributes.Builder setResolution(android.print.PrintAttributes.Resolution);
}
@@ -19090,19 +19145,61 @@
field public static final android.print.PrintAttributes.MediaSize ISO_C7;
field public static final android.print.PrintAttributes.MediaSize ISO_C8;
field public static final android.print.PrintAttributes.MediaSize ISO_C9;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B0;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B1;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B10;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B2;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B3;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B4;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B5;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B6;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B7;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B8;
+ field public static final android.print.PrintAttributes.MediaSize JIS_B9;
+ field public static final android.print.PrintAttributes.MediaSize JIS_EXEC;
+ field public static final android.print.PrintAttributes.MediaSize JPN_CHOU2;
+ field public static final android.print.PrintAttributes.MediaSize JPN_CHOU3;
+ field public static final android.print.PrintAttributes.MediaSize JPN_CHOU4;
+ field public static final android.print.PrintAttributes.MediaSize JPN_HAGAKI;
+ field public static final android.print.PrintAttributes.MediaSize JPN_KAHU;
+ field public static final android.print.PrintAttributes.MediaSize JPN_KAKU2;
+ field public static final android.print.PrintAttributes.MediaSize JPN_OUFUKU;
+ field public static final android.print.PrintAttributes.MediaSize JPN_YOU4;
+ field public static final android.print.PrintAttributes.MediaSize NA_FOOLSCAP;
field public static final android.print.PrintAttributes.MediaSize NA_GOVT_LETTER;
+ field public static final android.print.PrintAttributes.MediaSize NA_INDEX_3X5;
+ field public static final android.print.PrintAttributes.MediaSize NA_INDEX_4X6;
+ field public static final android.print.PrintAttributes.MediaSize NA_INDEX_5X8;
field public static final android.print.PrintAttributes.MediaSize NA_JUNIOR_LEGAL;
field public static final android.print.PrintAttributes.MediaSize NA_LEDGER;
field public static final android.print.PrintAttributes.MediaSize NA_LEGAL;
field public static final android.print.PrintAttributes.MediaSize NA_LETTER;
+ field public static final android.print.PrintAttributes.MediaSize NA_MONARCH;
+ field public static final android.print.PrintAttributes.MediaSize NA_QUARTO;
field public static final android.print.PrintAttributes.MediaSize NA_TBLOID;
+ field public static final android.print.PrintAttributes.MediaSize OM_DAI_PA_KAI;
+ field public static final android.print.PrintAttributes.MediaSize OM_JUURO_KU_KAI;
+ field public static final android.print.PrintAttributes.MediaSize OM_PA_KAI;
+ field public static final android.print.PrintAttributes.MediaSize PRC_1;
+ field public static final android.print.PrintAttributes.MediaSize PRC_10;
+ field public static final android.print.PrintAttributes.MediaSize PRC_16k;
+ field public static final android.print.PrintAttributes.MediaSize PRC_2;
+ field public static final android.print.PrintAttributes.MediaSize PRC_3;
+ field public static final android.print.PrintAttributes.MediaSize PRC_4;
+ field public static final android.print.PrintAttributes.MediaSize PRC_5;
+ field public static final android.print.PrintAttributes.MediaSize PRC_6;
+ field public static final android.print.PrintAttributes.MediaSize PRC_7;
+ field public static final android.print.PrintAttributes.MediaSize PRC_8;
+ field public static final android.print.PrintAttributes.MediaSize PRC_9;
+ field public static final android.print.PrintAttributes.MediaSize ROC_16K;
+ field public static final android.print.PrintAttributes.MediaSize ROC_8K;
}
public static final class PrintAttributes.Resolution {
ctor public PrintAttributes.Resolution(java.lang.String, java.lang.String, int, int);
method public int getHorizontalDpi();
method public java.lang.String getId();
- method public java.lang.String getLabel(android.content.pm.PackageManager);
+ method public java.lang.String getLabel();
method public int getVerticalDpi();
}
@@ -19143,7 +19240,7 @@
public static final class PrintDocumentInfo.Builder {
ctor public PrintDocumentInfo.Builder(java.lang.String);
- method public android.print.PrintDocumentInfo create();
+ method public android.print.PrintDocumentInfo build();
method public android.print.PrintDocumentInfo.Builder setContentType(int);
method public android.print.PrintDocumentInfo.Builder setPageCount(int);
}
@@ -19156,15 +19253,21 @@
public final class PrintJob {
method public void cancel();
- method public int getId();
+ method public android.print.PrintJobId getId();
method public android.print.PrintJobInfo getInfo();
}
+ public final class PrintJobId implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public final class PrintJobInfo implements android.os.Parcelable {
method public int describeContents();
method public android.print.PrintAttributes getAttributes();
method public int getCopies();
- method public int getId();
+ method public android.print.PrintJobId getId();
method public java.lang.String getLabel();
method public android.print.PageRange[] getPages();
method public android.print.PrinterId getPrinterId();
@@ -19176,6 +19279,7 @@
field public static final int STATE_BLOCKED = 4; // 0x4
field public static final int STATE_CANCELED = 7; // 0x7
field public static final int STATE_COMPLETED = 5; // 0x5
+ field public static final int STATE_CREATED = 1; // 0x1
field public static final int STATE_FAILED = 6; // 0x6
field public static final int STATE_QUEUED = 2; // 0x2
field public static final int STATE_STARTED = 3; // 0x3
@@ -19183,14 +19287,13 @@
public final class PrintManager {
method public java.util.List<android.print.PrintJob> getPrintJobs();
- method public android.print.PrintJob print(java.lang.String, java.io.File, android.print.PrintDocumentInfo, android.print.PrintAttributes);
method public android.print.PrintJob print(java.lang.String, android.print.PrintDocumentAdapter, android.print.PrintAttributes);
}
public final class PrinterCapabilitiesInfo implements android.os.Parcelable {
method public int describeContents();
method public int getColorModes();
- method public void getDefaults(android.print.PrintAttributes);
+ method public android.print.PrintAttributes getDefaults();
method public java.util.List<android.print.PrintAttributes.MediaSize> getMediaSizes();
method public android.print.PrintAttributes.Margins getMinMargins();
method public java.util.List<android.print.PrintAttributes.Resolution> getResolutions();
@@ -19202,9 +19305,9 @@
ctor public PrinterCapabilitiesInfo.Builder(android.print.PrinterId);
method public android.print.PrinterCapabilitiesInfo.Builder addMediaSize(android.print.PrintAttributes.MediaSize, boolean);
method public android.print.PrinterCapabilitiesInfo.Builder addResolution(android.print.PrintAttributes.Resolution, boolean);
- method public android.print.PrinterCapabilitiesInfo create();
+ method public android.print.PrinterCapabilitiesInfo build();
method public android.print.PrinterCapabilitiesInfo.Builder setColorModes(int, int);
- method public android.print.PrinterCapabilitiesInfo.Builder setMinMargins(android.print.PrintAttributes.Margins, android.print.PrintAttributes.Margins);
+ method public android.print.PrinterCapabilitiesInfo.Builder setMinMargins(android.print.PrintAttributes.Margins);
}
public final class PrinterId implements android.os.Parcelable {
@@ -19231,7 +19334,7 @@
public static final class PrinterInfo.Builder {
ctor public PrinterInfo.Builder(android.print.PrinterId, java.lang.String, int);
ctor public PrinterInfo.Builder(android.print.PrinterInfo);
- method public android.print.PrinterInfo create();
+ method public android.print.PrinterInfo build();
method public android.print.PrinterInfo.Builder setCapabilities(android.print.PrinterCapabilitiesInfo);
method public android.print.PrinterInfo.Builder setDescription(java.lang.String);
method public android.print.PrinterInfo.Builder setName(java.lang.String);
@@ -19294,7 +19397,7 @@
method public boolean complete();
method public boolean fail(java.lang.String);
method public android.printservice.PrintDocument getDocument();
- method public int getId();
+ method public android.print.PrintJobId getId();
method public android.print.PrintJobInfo getInfo();
method public boolean isBlocked();
method public boolean isCancelled();
@@ -20774,7 +20877,6 @@
method public static android.net.Uri buildRootUri(java.lang.String, java.lang.String);
method public static android.net.Uri buildRootsUri(java.lang.String);
method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
- method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
method public static java.lang.String getDocumentId(android.net.Uri);
method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal);
@@ -20795,10 +20897,10 @@
field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
field public static final java.lang.String COLUMN_SIZE = "_size";
field public static final java.lang.String COLUMN_SUMMARY = "summary";
- field public static final int FLAG_DIR_PREFERS_GRID = 32; // 0x20
- field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 64; // 0x40
+ field public static final int FLAG_DIR_HIDE_GRID_TITLES = 64; // 0x40
+ field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10
+ field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20
field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
- field public static final int FLAG_DIR_SUPPORTS_SEARCH = 16; // 0x10
field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
@@ -20816,9 +20918,11 @@
field public static final java.lang.String COLUMN_SUMMARY = "summary";
field public static final java.lang.String COLUMN_TITLE = "title";
field public static final int FLAG_ADVANCED = 4; // 0x4
+ field public static final int FLAG_EMPTY = 32; // 0x20
field public static final int FLAG_LOCAL_ONLY = 2; // 0x2
field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
field public static final int FLAG_SUPPORTS_RECENTS = 8; // 0x8
+ field public static final int FLAG_SUPPORTS_SEARCH = 16; // 0x10
field public static final int ROOT_TYPE_DEVICE = 3; // 0x3
field public static final int ROOT_TYPE_SERVICE = 1; // 0x1
field public static final int ROOT_TYPE_SHORTCUT = 2; // 0x2
@@ -22812,35 +22916,6 @@
}
-package android.speech.hotword {
-
- public abstract class HotwordRecognitionService extends android.app.Service {
- ctor public HotwordRecognitionService();
- method public android.os.IBinder onBind(android.content.Intent);
- method public abstract void onStartHotwordRecognition(android.speech.hotword.HotwordRecognitionService.Callback);
- method public abstract void onStopHotwordRecognition();
- field public static final int ERROR_AUDIO = 1; // 0x1
- field public static final int ERROR_CLIENT = 4; // 0x4
- field public static final int ERROR_FAILED = 3; // 0x3
- field public static final int ERROR_RECOGNIZER_BUSY = 2; // 0x2
- field public static final int ERROR_SERVICE_ALREADY_STARTED = 6; // 0x6
- field public static final int ERROR_TIMEOUT = 5; // 0x5
- field public static final int ERROR_UNAVAILABLE = 7; // 0x7
- field public static final int EVENT_TYPE_PROMPT_CHANGED = 1; // 0x1
- field public static final java.lang.String KEY_PROMPT_TEXT = "prompt_text";
- field public static final java.lang.String SERVICE_INTERFACE = "android.speech.hotword.HotwordRecognitionService";
- }
-
- public static class HotwordRecognitionService.Callback {
- method public void onError(int) throws android.os.RemoteException;
- method public void onHotwordEvent(int, android.os.Bundle) throws android.os.RemoteException;
- method public void onHotwordRecognitionStarted() throws android.os.RemoteException;
- method public void onHotwordRecognitionStopped() throws android.os.RemoteException;
- method public void onHotwordRecognized(android.content.Intent) throws android.os.RemoteException;
- }
-
-}
-
package android.speech.tts {
public abstract interface SynthesisCallback {
@@ -25528,12 +25603,18 @@
public abstract class Transition implements java.lang.Cloneable {
ctor public Transition();
method public android.transition.Transition addListener(android.transition.Transition.TransitionListener);
+ method public android.transition.Transition addTarget(int);
method public android.transition.Transition addTarget(android.view.View);
- method public android.transition.Transition addTargetId(int);
method public abstract void captureEndValues(android.transition.TransitionValues);
method public abstract void captureStartValues(android.transition.TransitionValues);
method public android.transition.Transition clone();
method public android.animation.Animator createAnimator(android.view.ViewGroup, android.transition.TransitionValues, android.transition.TransitionValues);
+ method public android.transition.Transition excludeChildren(int, boolean);
+ method public android.transition.Transition excludeChildren(android.view.View, boolean);
+ method public android.transition.Transition excludeChildren(java.lang.Class, boolean);
+ method public android.transition.Transition excludeTarget(int, boolean);
+ method public android.transition.Transition excludeTarget(android.view.View, boolean);
+ method public android.transition.Transition excludeTarget(java.lang.Class, boolean);
method public long getDuration();
method public android.animation.TimeInterpolator getInterpolator();
method public java.lang.String getName();
@@ -25543,8 +25624,8 @@
method public java.lang.String[] getTransitionProperties();
method public android.transition.TransitionValues getTransitionValues(android.view.View, boolean);
method public android.transition.Transition removeListener(android.transition.Transition.TransitionListener);
+ method public android.transition.Transition removeTarget(int);
method public android.transition.Transition removeTarget(android.view.View);
- method public android.transition.Transition removeTargetId(int);
method public android.transition.Transition setDuration(long);
method public android.transition.Transition setInterpolator(android.animation.TimeInterpolator);
method public android.transition.Transition setStartDelay(long);
@@ -27256,6 +27337,7 @@
method public float getScaleFactor();
method public long getTimeDelta();
method public boolean isInProgress();
+ method public boolean isQuickScaleEnabled();
method public boolean onTouchEvent(android.view.MotionEvent);
method public void setQuickScaleEnabled(boolean);
}
@@ -27311,7 +27393,7 @@
field public static final int ROTATION_90 = 1; // 0x1
}
- public static class Surface.OutOfResourcesException extends java.lang.Exception {
+ public static class Surface.OutOfResourcesException extends java.lang.RuntimeException {
ctor public Surface.OutOfResourcesException();
ctor public Surface.OutOfResourcesException(java.lang.String);
}
@@ -27489,6 +27571,7 @@
method public android.view.View focusSearch(int);
method public void forceLayout();
method public static int generateViewId();
+ method public int getAccessibilityLiveRegion();
method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
method public float getAlpha();
method public android.view.animation.Animation getAnimation();
@@ -27750,6 +27833,7 @@
method public void sendAccessibilityEvent(int);
method public void sendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent);
method public void setAccessibilityDelegate(android.view.View.AccessibilityDelegate);
+ method public void setAccessibilityLiveRegion(int);
method public void setActivated(boolean);
method public void setAlpha(float);
method public void setAnimation(android.view.animation.Animation);
@@ -27855,6 +27939,9 @@
method protected boolean verifyDrawable(android.graphics.drawable.Drawable);
method public boolean willNotCacheDrawing();
method public boolean willNotDraw();
+ field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
+ field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
+ field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
field public static final android.util.Property ALPHA;
field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0
field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000
@@ -28163,7 +28250,6 @@
method public void bringChildToFront(android.view.View);
method protected boolean canAnimate();
method protected boolean checkLayoutParams(android.view.ViewGroup.LayoutParams);
- method public void childAccessibilityStateChanged(android.view.View);
method public void childDrawableStateChanged(android.view.View);
method public void childHasTransientStateChanged(android.view.View, boolean);
method protected void cleanupLayoutState(android.view.View);
@@ -28212,6 +28298,7 @@
method protected void measureChild(android.view.View, int, int);
method protected void measureChildWithMargins(android.view.View, int, int, int, int);
method protected void measureChildren(int, int);
+ method public void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
method public final void offsetDescendantRectToMyCoords(android.view.View, android.graphics.Rect);
method public final void offsetRectIntoDescendantCoords(android.view.View, android.graphics.Rect);
method public boolean onInterceptHoverEvent(android.view.MotionEvent);
@@ -28329,7 +28416,6 @@
method public abstract boolean canResolveLayoutDirection();
method public abstract boolean canResolveTextAlignment();
method public abstract boolean canResolveTextDirection();
- method public abstract void childAccessibilityStateChanged(android.view.View);
method public abstract void childDrawableStateChanged(android.view.View);
method public abstract void childHasTransientStateChanged(android.view.View, boolean);
method public abstract void clearChildFocus(android.view.View);
@@ -28348,6 +28434,7 @@
method public abstract boolean isLayoutRequested();
method public abstract boolean isTextAlignmentResolved();
method public abstract boolean isTextDirectionResolved();
+ method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
method public abstract void recomputeViewAttributes(android.view.View);
method public abstract void requestChildFocus(android.view.View, android.view.View);
method public abstract boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean);
@@ -28773,7 +28860,7 @@
method public int describeContents();
method public static java.lang.String eventTypeToString(int);
method public int getAction();
- method public int getContentChangeType();
+ method public int getContentChangeTypes();
method public long getEventTime();
method public int getEventType();
method public int getMovementGranularity();
@@ -28785,14 +28872,16 @@
method public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent);
method public static android.view.accessibility.AccessibilityEvent obtain();
method public void setAction(int);
- method public void setContentChangeType(int);
+ method public void setContentChangeTypes(int);
method public void setEventTime(long);
method public void setEventType(int);
method public void setMovementGranularity(int);
method public void setPackageName(java.lang.CharSequence);
method public void writeToParcel(android.os.Parcel, int);
- field public static final int CONTENT_CHANGE_TYPE_NODE = 1; // 0x1
- field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 0; // 0x0
+ field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+ field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+ field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
+ field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int INVALID_POSITION = -1; // 0xffffffff
field public static final deprecated int MAX_TEXT_LENGTH = 500; // 0x1f4
@@ -28865,6 +28954,7 @@
method public int getInputType();
method public android.view.accessibility.AccessibilityNodeInfo getLabelFor();
method public android.view.accessibility.AccessibilityNodeInfo getLabeledBy();
+ method public int getLiveRegion();
method public int getMovementGranularities();
method public java.lang.CharSequence getPackageName();
method public android.view.accessibility.AccessibilityNodeInfo getParent();
@@ -28882,11 +28972,8 @@
method public boolean isDismissable();
method public boolean isEditable();
method public boolean isEnabled();
- method public boolean isExpandable();
- method public boolean isExpanded();
method public boolean isFocusable();
method public boolean isFocused();
- method public boolean isLiveRegion();
method public boolean isLongClickable();
method public boolean isMultiLine();
method public boolean isPassword();
@@ -28916,8 +29003,6 @@
method public void setDismissable(boolean);
method public void setEditable(boolean);
method public void setEnabled(boolean);
- method public void setExpandable(boolean);
- method public void setExpanded(boolean);
method public void setFocusable(boolean);
method public void setFocused(boolean);
method public void setInputType(int);
@@ -28925,7 +29010,7 @@
method public void setLabelFor(android.view.View, int);
method public void setLabeledBy(android.view.View);
method public void setLabeledBy(android.view.View, int);
- method public void setLiveRegion(boolean);
+ method public void setLiveRegion(int);
method public void setLongClickable(boolean);
method public void setMovementGranularities(int);
method public void setMultiLine(boolean);
@@ -30169,6 +30254,7 @@
method public void clearSslPreferences();
method public deprecated void clearView();
method public android.webkit.WebBackForwardList copyBackForwardList();
+ method public android.print.PrintDocumentAdapter createPrintDocumentAdapter();
method public void destroy();
method public void documentHasImages(android.os.Message);
method public void evaluateJavascript(java.lang.String, android.webkit.ValueCallback<java.lang.String>);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index d78572b..c18f542 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -100,6 +100,7 @@
" am monitor [--gdb <port>]\n" +
" am hang [--allow-restart]\n" +
" am restart\n" +
+ " am idle-maintenance\n" +
" am screen-compat [on|off] <PACKAGE>\n" +
" am to-uri [INTENT]\n" +
" am to-intent-uri [INTENT]\n" +
@@ -189,6 +190,8 @@
"\n" +
"am restart: restart the user-space system.\n" +
"\n" +
+ "am idle-maintenance: perform idle maintenance now.\n" +
+ "\n" +
"am screen-compat: control screen compatibility mode of <PACKAGE>.\n" +
"\n" +
"am to-uri: print the given Intent specification as a URI.\n" +
@@ -295,6 +298,8 @@
runHang();
} else if (op.equals("restart")) {
runRestart();
+ } else if (op.equals("idle-maintenance")) {
+ runIdleMaintenance();
} else if (op.equals("screen-compat")) {
runScreenCompat();
} else if (op.equals("to-uri")) {
@@ -1393,6 +1398,20 @@
mAm.restart();
}
+ private void runIdleMaintenance() throws Exception {
+ String opt;
+ while ((opt=nextOption()) != null) {
+ System.err.println("Error: Unknown option: " + opt);
+ return;
+ }
+
+ System.out.println("Performing idle maintenance...");
+ Intent intent = new Intent(
+ "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE");
+ mAm.broadcastIntent(null, intent, null, null, 0, null, null, null,
+ android.app.AppOpsManager.OP_NONE, true, false, UserHandle.USER_ALL);
+ }
+
private void runScreenCompat() throws Exception {
String mode = nextArgRequired();
boolean enabled;
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 6394299..86da673 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1027,6 +1027,8 @@
long currentPlayTime = currentTime - mStartTime;
long timeLeft = mDuration - currentPlayTime;
mStartTime = currentTime - timeLeft;
+ } else if (mStarted) {
+ end();
} else {
start(true);
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 57686a4..a38fbbf 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4907,6 +4907,8 @@
*
* @see #convertToTranslucent(TranslucentConversionListener)
* @see TranslucentConversionListener
+ *
+ * @hide
*/
public void convertFromTranslucent() {
try {
@@ -4937,6 +4939,8 @@
*
* @see #convertFromTranslucent()
* @see TranslucentConversionListener
+ *
+ * @hide
*/
public void convertToTranslucent(TranslucentConversionListener callback) {
try {
@@ -5441,6 +5445,8 @@
* opaque using {@link Activity#convertFromTranslucent()} and before it has been drawn
* translucent again following a call to {@link
* Activity#convertToTranslucent(TranslucentConversionListener)}.
+ *
+ * @hide
*/
public interface TranslucentConversionListener {
/**
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 653559d..a727b07 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1917,7 +1917,8 @@
data.enforceInterface(IActivityManager.descriptor);
int pid = data.readInt();
boolean aboveSystem = data.readInt() != 0;
- long res = inputDispatchingTimedOut(pid, aboveSystem);
+ String reason = data.readString();
+ long res = inputDispatchingTimedOut(pid, aboveSystem, reason);
reply.writeNoException();
reply.writeLong(res);
return true;
@@ -1936,8 +1937,7 @@
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
Bundle extras = data.readBundle();
- int index = data.readInt();
- reportAssistContextExtras(token, extras, index);
+ reportAssistContextExtras(token, extras);
reply.writeNoException();
return true;
}
@@ -1995,6 +1995,13 @@
reply.writeParcelableArray(uris, 0);
return true;
}
+
+ case PERFORM_IDLE_MAINTENANCE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ performIdleMaintenance();
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -4462,12 +4469,14 @@
reply.recycle();
}
- public long inputDispatchingTimedOut(int pid, boolean aboveSystem) throws RemoteException {
+ public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason)
+ throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(pid);
data.writeInt(aboveSystem ? 1 : 0);
+ data.writeString(reason);
mRemote.transact(INPUT_DISPATCHING_TIMED_OUT_TRANSACTION, data, reply, 0);
reply.readException();
long res = reply.readInt();
@@ -4489,14 +4498,13 @@
return res;
}
- public void reportAssistContextExtras(IBinder token, Bundle extras, int index)
+ public void reportAssistContextExtras(IBinder token, Bundle extras)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
data.writeBundle(extras);
- data.writeInt(index);
mRemote.transact(REPORT_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -4577,5 +4585,15 @@
return uris;
}
+ public void performIdleMaintenance() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(PERFORM_IDLE_MAINTENANCE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 018fbe0..209514a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -528,7 +528,6 @@
IBinder activityToken;
IBinder requestToken;
int requestType;
- int index;
}
private native void dumpGraphicsInfo(FileDescriptor fd);
@@ -1194,12 +1193,11 @@
@Override
public void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
- int requestType, int index) {
+ int requestType) {
RequestAssistContextExtras cmd = new RequestAssistContextExtras();
cmd.activityToken = activityToken;
cmd.requestToken = requestToken;
cmd.requestType = requestType;
- cmd.index = index;
queueOrSendMessage(H.REQUEST_ASSIST_CONTEXT_EXTRAS, cmd);
}
@@ -2278,18 +2276,13 @@
if (r != null) {
r.activity.getApplication().dispatchOnProvideAssistData(r.activity, data);
r.activity.onProvideAssistData(data);
- } else {
- Service service = mServices.get(cmd.activityToken);
- if (service != null) {
- service.onProvideAssistData(data);
- }
}
if (data.isEmpty()) {
data = null;
}
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
- mgr.reportAssistContextExtras(cmd.requestToken, data, cmd.index);
+ mgr.reportAssistContextExtras(cmd.requestToken, data);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 19a028d..bf2a1e4 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -65,7 +65,7 @@
// when adding one of these:
// - increment _NUM_OP
- // - add rows to sOpToSwitch, sOpNames, sOpPerms
+ // - add rows to sOpToSwitch, sOpNames, sOpPerms, sOpDefaultMode
// - add descriptive strings to Settings/res/values/arrays.xml
// - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app)
@@ -185,11 +185,11 @@
OP_CALL_PHONE,
OP_READ_SMS,
OP_WRITE_SMS,
- OP_READ_SMS,
- OP_READ_SMS,
- OP_READ_SMS,
- OP_READ_SMS,
- OP_WRITE_SMS,
+ OP_RECEIVE_SMS,
+ OP_RECEIVE_SMS,
+ OP_RECEIVE_SMS,
+ OP_RECEIVE_SMS,
+ OP_SEND_SMS,
OP_READ_SMS,
OP_WRITE_SMS,
OP_WRITE_SETTINGS,
@@ -315,6 +315,55 @@
};
/**
+ * This specifies the default mode for each operation.
+ */
+ private static int[] sOpDefaultMode = new int[] {
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_IGNORED, // OP_WRITE_SMS
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ };
+
+ /**
* Retrieve the op switch that controls the given operation.
* @hide
*/
@@ -339,6 +388,14 @@
}
/**
+ * Retrieve the default mode for the operation.
+ * @hide
+ */
+ public static int opToDefaultMode(int op) {
+ return sOpDefaultMode[op];
+ }
+
+ /**
* Class holding all of the operation information associated with an app.
* @hide
*/
@@ -575,6 +632,10 @@
}
}
+ private String buildSecurityExceptionMsg(int op, int uid, String packageName) {
+ return packageName + " from uid " + uid + " not allowed to perform " + sOpNames[op];
+ }
+
/**
* Do a quick check for whether an application might be able to perform an operation.
* This is <em>not</em> a security check; you must use {@link #noteOp(int, int, String)}
@@ -595,7 +656,7 @@
try {
int mode = mService.checkOperation(op, uid, packageName);
if (mode == MODE_ERRORED) {
- throw new SecurityException("Operation not allowed");
+ throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
}
return mode;
} catch (RemoteException e) {
@@ -650,7 +711,7 @@
try {
int mode = mService.noteOperation(op, uid, packageName);
if (mode == MODE_ERRORED) {
- throw new SecurityException("Operation not allowed");
+ throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
}
return mode;
} catch (RemoteException e) {
@@ -672,7 +733,7 @@
/** @hide */
public int noteOp(int op) {
- return noteOp(op, Process.myUid(), mContext.getBasePackageName());
+ return noteOp(op, Process.myUid(), mContext.getOpPackageName());
}
/** @hide */
@@ -710,7 +771,7 @@
try {
int mode = mService.startOperation(getToken(mService), op, uid, packageName);
if (mode == MODE_ERRORED) {
- throw new SecurityException("Operation not allowed");
+ throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
}
return mode;
} catch (RemoteException e) {
@@ -732,7 +793,7 @@
/** @hide */
public int startOp(int op) {
- return startOp(op, Process.myUid(), mContext.getBasePackageName());
+ return startOp(op, Process.myUid(), mContext.getOpPackageName());
}
/**
@@ -749,6 +810,6 @@
}
public void finishOp(int op) {
- finishOp(op, Process.myUid(), mContext.getBasePackageName());
+ finishOp(op, Process.myUid(), mContext.getOpPackageName());
}
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index ab2739d..55c66726 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1251,6 +1251,16 @@
}
@Override
+ public ComponentName getHomeActivities(List<ResolveInfo> outActivities) {
+ try {
+ return mPM.getHomeActivities(outActivities);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ return null;
+ }
+
+ @Override
public void setComponentEnabledSetting(ComponentName componentName,
int newState, int flags) {
try {
@@ -1275,7 +1285,7 @@
int newState, int flags) {
try {
mPM.setApplicationEnabledSetting(packageName, newState, flags,
- mContext.getUserId(), mContext.getBasePackageName());
+ mContext.getUserId(), mContext.getOpPackageName());
} catch (RemoteException e) {
// Should never happen!
}
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index c0080be..a4e80e5 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -606,8 +606,7 @@
IBinder activityToken = data.readStrongBinder();
IBinder requestToken = data.readStrongBinder();
int requestType = data.readInt();
- int index = data.readInt();
- requestAssistContextExtras(activityToken, requestToken, requestType, index);
+ requestAssistContextExtras(activityToken, requestToken, requestType);
reply.writeNoException();
return true;
}
@@ -1243,13 +1242,12 @@
@Override
public void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
- int requestType, int index) throws RemoteException {
+ int requestType) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(activityToken);
data.writeStrongBinder(requestToken);
data.writeInt(requestType);
- data.writeInt(index);
mRemote.transact(REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 7ff7562..8e9f3bb 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -47,6 +47,7 @@
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
+import android.hardware.ConsumerIrManager;
import android.hardware.ISerialManager;
import android.hardware.SerialManager;
import android.hardware.SystemSensorManager;
@@ -183,6 +184,7 @@
/*package*/ LoadedApk mPackageInfo;
private String mBasePackageName;
+ private String mOpPackageName;
private Resources mResources;
/*package*/ ActivityThread mMainThread;
private Context mOuterContext;
@@ -579,6 +581,11 @@
return new PrintManager(ctx.getOuterContext(), service, UserHandle.myUserId(),
UserHandle.getAppId(Process.myUid()));
}});
+
+ registerService(CONSUMER_IR_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new ConsumerIrManager(ctx);
+ }});
}
static ContextImpl getImpl(Context context) {
@@ -679,6 +686,12 @@
return mBasePackageName != null ? mBasePackageName : getPackageName();
}
+ /** @hide */
+ @Override
+ public String getOpPackageName() {
+ return mOpPackageName != null ? mOpPackageName : getBasePackageName();
+ }
+
@Override
public ApplicationInfo getApplicationInfo() {
if (mPackageInfo != null) {
@@ -1961,6 +1974,7 @@
public ContextImpl(ContextImpl context) {
mPackageInfo = context.mPackageInfo;
mBasePackageName = context.mBasePackageName;
+ mOpPackageName = context.mOpPackageName;
mResources = context.mResources;
mMainThread = context.mMainThread;
mContentResolver = context.mContentResolver;
@@ -1977,7 +1991,21 @@
final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread,
Resources container, String basePackageName, UserHandle user) {
mPackageInfo = packageInfo;
- mBasePackageName = basePackageName != null ? basePackageName : packageInfo.mPackageName;
+ if (basePackageName != null) {
+ mBasePackageName = mOpPackageName = basePackageName;
+ } else {
+ mBasePackageName = packageInfo.mPackageName;
+ ApplicationInfo ainfo = packageInfo.getApplicationInfo();
+ if (ainfo.uid == Process.SYSTEM_UID && ainfo.uid != Process.myUid()) {
+ // Special case: system components allow themselves to be loaded in to other
+ // processes. For purposes of app ops, we must then consider the context as
+ // belonging to the package of this process, not the system itself, otherwise
+ // the package+uid verifications in app ops will fail.
+ mOpPackageName = ActivityThread.currentPackageName();
+ } else {
+ mOpPackageName = mBasePackageName;
+ }
+ }
mResources = mPackageInfo.getResources(mainThread);
mResourcesManager = ResourcesManager.getInstance();
@@ -2011,6 +2039,7 @@
final void init(Resources resources, ActivityThread mainThread, UserHandle user) {
mPackageInfo = null;
mBasePackageName = null;
+ mOpPackageName = null;
mResources = resources;
mMainThread = mainThread;
mContentResolver = new ApplicationContentResolver(this, mainThread, user);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index af9a245..25c02df 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -384,12 +384,12 @@
public void requestBugReport() throws RemoteException;
- public long inputDispatchingTimedOut(int pid, boolean aboveSystem) throws RemoteException;
+ public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason)
+ throws RemoteException;
public Bundle getAssistContextExtras(int requestType) throws RemoteException;
- public void reportAssistContextExtras(IBinder token, Bundle extras, int index)
- throws RemoteException;
+ public void reportAssistContextExtras(IBinder token, Bundle extras) throws RemoteException;
public void killUid(int uid, String reason) throws RemoteException;
@@ -403,6 +403,8 @@
String sourcePackage, String targetPackage, int modeFlags, int modeMask)
throws RemoteException;
+ public void performIdleMaintenance() throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -685,4 +687,5 @@
int REPORT_ACTIVITY_FULLY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+176;
int RESTART_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+177;
int GET_GRANTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+178;
+ int PERFORM_IDLE_MAINTENANCE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+179;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 01a0a91..058b975 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -133,8 +133,8 @@
void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
void dumpDbInfo(FileDescriptor fd, String[] args) throws RemoteException;
void unstableProviderDied(IBinder provider) throws RemoteException;
- void requestAssistContextExtras(IBinder activityToken, IBinder requestToken, int requestType,
- int index) throws RemoteException;
+ void requestAssistContextExtras(IBinder activityToken, IBinder requestToken, int requestType)
+ throws RemoteException;
void scheduleTranslucentConversionComplete(IBinder token, boolean timeout)
throws RemoteException;
void setProcessState(int state) throws RemoteException;
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index dbafc78..3ee4306 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -133,7 +133,7 @@
}
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
try {
- service.enqueueNotificationWithTag(pkg, mContext.getBasePackageName(), tag, id,
+ service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
notification, idOut, UserHandle.myUserId());
if (id != idOut[0]) {
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
@@ -158,7 +158,7 @@
}
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
try {
- service.enqueueNotificationWithTag(pkg, mContext.getBasePackageName(), tag, id,
+ service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
notification, idOut, user.getIdentifier());
if (id != idOut[0]) {
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 1254bac..3967740 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
-import android.os.Bundle;
import android.os.RemoteException;
import android.os.IBinder;
import android.util.Log;
@@ -308,18 +307,6 @@
}
/**
- * This is called on foreground services when the user is requesting an assist, to build a
- * full {@link Intent#ACTION_ASSIST} Intent with all of the context of the current
- * running foreground services. You can override this method to place into the bundle
- * anything you would like to appear as an item in the
- * {@link Intent#EXTRA_ASSIST_SERVICES_CONTEXTS} part of the assist Intent.
- * This method will not be called if this service is not in the foreground.
- * The default implementation does nothing.
- */
- public void onProvideAssistData(Bundle data) {
- }
-
- /**
* @deprecated Implement {@link #onStartCommand(Intent, int, int)} instead.
*/
@Deprecated
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 3342068..2bc7cbf 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -16,8 +16,11 @@
package android.app;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -30,7 +33,7 @@
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Binder;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -41,13 +44,13 @@
import android.os.ServiceManager;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.List;
/**
* Provides access to the system wallpaper. With WallpaperManager, you can
@@ -62,6 +65,15 @@
private float mWallpaperYStep = -1;
/**
+ * Activity Action: Show settings for choosing wallpaper. Do not use directly to construct
+ * an intent; instead, use {@link #getCropAndSetWallpaperIntent}.
+ * <p>Input: {@link Intent#getData} is the URI of the image to crop and set as wallpaper.
+ * <p>Output: RESULT_OK if user decided to crop/set the wallpaper, RESULT_CANCEL otherwise
+ */
+ public static final String ACTION_CROP_AND_SET_WALLPAPER =
+ "android.service.wallpaper.CROP_AND_SET_WALLPAPER";
+
+ /**
* Launch an activity for the user to pick the current global live
* wallpaper.
*/
@@ -463,7 +475,39 @@
return null;
}
}
-
+
+ /**
+ * Gets an Intent that will launch an activity that crops the given
+ * image and sets the device's wallpaper. If there is a default HOME activity
+ * that supports cropping wallpapers, it will be preferred as the default.
+ * Use this method instead of directly creating a {@link #ACTION_CROP_AND_SET_WALLPAPER}
+ * intent.
+ */
+ public Intent getCropAndSetWallpaperIntent(Uri imageUri) {
+ final PackageManager packageManager = mContext.getPackageManager();
+ Intent cropAndSetWallpaperIntent =
+ new Intent(ACTION_CROP_AND_SET_WALLPAPER, imageUri);
+ cropAndSetWallpaperIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ // Find out if the default HOME activity supports CROP_AND_SET_WALLPAPER
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
+ ResolveInfo resolvedHome = packageManager.resolveActivity(homeIntent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ if (resolvedHome != null) {
+ cropAndSetWallpaperIntent.setPackage(resolvedHome.activityInfo.packageName);
+
+ List<ResolveInfo> cropAppList = packageManager.queryIntentActivities(
+ cropAndSetWallpaperIntent, 0);
+ if (cropAppList.size() > 0) {
+ return cropAndSetWallpaperIntent;
+ }
+ }
+
+ // fallback crop activity
+ cropAndSetWallpaperIntent.setPackage("com.android.wallpapercropper");
+ return cropAndSetWallpaperIntent;
+ }
+
/**
* Change the current system wallpaper to the bitmap in the given resource.
* The resource is opened as a raw data stream and copied into the
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e0b1c00..ab82531 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1372,7 +1372,7 @@
*
* @hide
*/
- public boolean hasAnyCaCertsInstalled() {
+ public static boolean hasAnyCaCertsInstalled() {
TrustedCertificateStore certStore = new TrustedCertificateStore();
Set<String> aliases = certStore.userAliases();
return aliases != null && !aliases.isEmpty();
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 676fd1f..2172a7b 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -27,7 +27,6 @@
import android.os.ServiceManager;
import android.util.Log;
import android.util.Pair;
-
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -51,7 +50,7 @@
* devices, and start a scan for Bluetooth LE devices.
*
* <p>To get a {@link BluetoothAdapter} representing the local Bluetooth
- * adapter, when running on JELLY_BEAN_MR1 and below, call the
+ * adapter, when running on JELLY_BEAN_MR1 and below, call the
* static {@link #getDefaultAdapter} method; when running on JELLY_BEAN_MR2 and
* higher, retrieve it through
* {@link android.content.Context#getSystemService} with
@@ -1229,6 +1228,9 @@
} else if (profile == BluetoothProfile.HEALTH) {
BluetoothHealth health = new BluetoothHealth(context, listener);
return true;
+ } else if (profile == BluetoothProfile.MAP) {
+ BluetoothMap map = new BluetoothMap(context, listener);
+ return true;
} else {
return false;
}
@@ -1277,6 +1279,10 @@
BluetoothGattServer gattServer = (BluetoothGattServer)proxy;
gattServer.close();
break;
+ case BluetoothProfile.MAP:
+ BluetoothMap map = (BluetoothMap)proxy;
+ map.close();
+ break;
}
}
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index 7de309f..fac8fd5 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -16,6 +16,8 @@
package android.bluetooth;
+import java.util.List;
+import java.util.ArrayList;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -30,25 +32,14 @@
* Profile.
*@hide
*/
-public class BluetoothMap {
+public final class BluetoothMap implements BluetoothProfile {
private static final String TAG = "BluetoothMap";
private static final boolean DBG = true;
private static final boolean VDBG = false;
- /** int extra for MAP_STATE_CHANGED_ACTION */
- public static final String MAP_STATE =
- "android.bluetooth.map.intent.MAP_STATE";
- /** int extra for MAP_STATE_CHANGED_ACTION */
- public static final String MAP_PREVIOUS_STATE =
- "android.bluetooth.map.intent.MAP_PREVIOUS_STATE";
-
- /** Indicates the state of a Map connection state has changed.
- * This intent will always contain MAP_STATE, MAP_PREVIOUS_STATE and
- * BluetoothIntent.ADDRESS extras.
- */
- public static final String MAP_STATE_CHANGED_ACTION =
- "android.bluetooth.map.intent.action.MAP_STATE_CHANGED";
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
private IBluetoothMap mService;
private final Context mContext;
@@ -57,41 +48,12 @@
/** There was an error trying to obtain the state */
public static final int STATE_ERROR = -1;
- /** No client currently connected */
- public static final int STATE_DISCONNECTED = 0;
- /** Connection attempt in progress */
- public static final int STATE_CONNECTING = 1;
- /** Client is currently connected */
- public static final int STATE_CONNECTED = 2;
public static final int RESULT_FAILURE = 0;
public static final int RESULT_SUCCESS = 1;
/** Connection canceled before completion. */
public static final int RESULT_CANCELED = 2;
- /**
- * An interface for notifying Bluetooth PCE IPC clients when they have
- * been connected to the BluetoothMap service.
- */
- public interface ServiceListener {
- /**
- * Called to notify the client when this proxy object has been
- * connected to the BluetoothMap service. Clients must wait for
- * this callback before making IPC calls on the BluetoothMap
- * service.
- */
- public void onServiceConnected(BluetoothMap proxy);
-
- /**
- * Called to notify the client that this proxy object has been
- * disconnected from the BluetoothMap service. Clients must not
- * make IPC calls on the BluetoothMap service after this callback.
- * This callback will currently only occur if the application hosting
- * the BluetoothMap service, but may be called more often in future.
- */
- public void onServiceDisconnected();
- }
-
final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
new IBluetoothStateChangeCallback.Stub() {
public void onBluetoothStateChange(boolean up) {
@@ -111,11 +73,7 @@
try {
if (mService == null) {
if (VDBG) Log.d(TAG,"Binding service...");
- if (!mContext.bindService(
- new Intent(IBluetoothMap.class.getName()),
- mConnection, 0)) {
- Log.e(TAG, "Could not bind to Bluetooth MAP Service");
- }
+ doBind();
}
} catch (Exception re) {
Log.e(TAG,"",re);
@@ -128,7 +86,8 @@
/**
* Create a BluetoothMap proxy object.
*/
- public BluetoothMap(Context context, ServiceListener l) {
+ /*package*/ BluetoothMap(Context context, ServiceListener l) {
+ if (DBG) Log.d(TAG, "Create BluetoothMap proxy object");
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter();
@@ -140,9 +99,18 @@
Log.e(TAG,"",e);
}
}
- if (!context.bindService(new Intent(IBluetoothMap.class.getName()), mConnection, 0)) {
- Log.e(TAG, "Could not bind to Bluetooth Map Service");
+ doBind();
+ }
+
+ boolean doBind() {
+ Intent intent = new Intent(IBluetoothMap.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindService(intent, mConnection, 0)) {
+ Log.e(TAG, "Could not bind to Bluetooth MAP Service with " + intent);
+ return false;
}
+ return true;
}
protected void finalize() throws Throwable {
@@ -221,9 +189,9 @@
}
/**
- * Returns true if the specified Bluetooth device is connected (does not
- * include connecting). Returns false if not connected, or if this proxy
- * object is not currently connected to the Map service.
+ * Returns true if the specified Bluetooth device is connected.
+ * Returns false if not connected, or if this proxy object is not
+ * currently connected to the Map service.
*/
public boolean isConnected(BluetoothDevice device) {
if (VDBG) log("isConnected(" + device + ")");
@@ -239,21 +207,33 @@
}
/**
- * Disconnects the current Map Client. Currently this call blocks,
- * it may soon be made asynchronous. Returns false if this proxy object is
- * not currently connected to the Map service.
+ * Initiate connection. Initiation of outgoing connections is not
+ * supported for MAP server.
*/
- public boolean disconnect() {
- if (DBG) log("disconnect()");
- if (mService != null) {
+ public boolean connect(BluetoothDevice device) {
+ if (DBG) log("connect(" + device + ")" + "not supported for MAPS");
+ return false;
+ }
+
+ /**
+ * Initiate disconnect.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on error,
+ * true otherwise
+ */
+ public boolean disconnect(BluetoothDevice device) {
+ if (DBG) log("disconnect(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
try {
- mService.disconnect();
- return true;
- } catch (RemoteException e) {Log.e(TAG, e.toString());}
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
+ return mService.disconnect(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return false;
+ }
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
return false;
}
@@ -277,19 +257,132 @@
}
}
+ /**
+ * Get the list of connected devices. Currently at most one.
+ *
+ * @return list of connected devices
+ */
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (DBG) log("getConnectedDevices()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * Get the list of devices matching specified states. Currently at most one.
+ *
+ * @return list of matching devices
+ */
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (DBG) log("getDevicesMatchingStates()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * Get connection state of device
+ *
+ * @return device connection state
+ */
+ public int getConnectionState(BluetoothDevice device) {
+ if (DBG) log("getConnectionState(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.getConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ /**
+ * Set priority of the profile
+ *
+ * <p> The device should already be paired.
+ * Priority can be one of {@link #PRIORITY_ON} or
+ * {@link #PRIORITY_OFF},
+ *
+ * @param device Paired bluetooth device
+ * @param priority
+ * @return true if priority is set, false on error
+ */
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setPriority(" + device + ", " + priority + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ if (priority != BluetoothProfile.PRIORITY_OFF &&
+ priority != BluetoothProfile.PRIORITY_ON) {
+ return false;
+ }
+ try {
+ return mService.setPriority(device, priority);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Get the priority of the profile.
+ *
+ * <p> The priority can be any of:
+ * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
+ * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+ *
+ * @param device Bluetooth device
+ * @return priority of the device
+ */
+ public int getPriority(BluetoothDevice device) {
+ if (VDBG) log("getPriority(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.getPriority(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return PRIORITY_OFF;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return PRIORITY_OFF;
+ }
+
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) log("Proxy object connected");
mService = IBluetoothMap.Stub.asInterface(service);
if (mServiceListener != null) {
- mServiceListener.onServiceConnected(BluetoothMap.this);
+ mServiceListener.onServiceConnected(BluetoothProfile.MAP, BluetoothMap.this);
}
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) log("Proxy object disconnected");
mService = null;
if (mServiceListener != null) {
- mServiceListener.onServiceDisconnected();
+ mServiceListener.onServiceDisconnected(BluetoothProfile.MAP);
}
}
};
@@ -297,4 +390,19 @@
private static void log(String msg) {
Log.d(TAG, msg);
}
+
+ private boolean isEnabled() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ log("Bluetooth is Not enabled");
+ return false;
+ }
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+
}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 6609b98..abdf949e 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -67,13 +67,16 @@
public static final ParcelUuid PBAP_PSE =
ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid MAP =
- ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
+ ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid MNS =
ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid MAS =
+ ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
+
public static final ParcelUuid[] RESERVED_UUIDS = {
AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
- ObexObjectPush, PANU, NAP, MAP, MNS};
+ ObexObjectPush, PANU, NAP, MAP, MNS, MAS};
public static boolean isAudioSource(ParcelUuid uuid) {
return uuid.equals(AudioSource);
@@ -124,6 +127,9 @@
public static boolean isMns(ParcelUuid uuid) {
return uuid.equals(MNS);
}
+ public static boolean isMas(ParcelUuid uuid) {
+ return uuid.equals(MAS);
+ }
/**
* Returns true if ParcelUuid is present in uuidArray
diff --git a/core/java/android/bluetooth/IBluetoothMap.aidl b/core/java/android/bluetooth/IBluetoothMap.aidl
index 0c18e06..d4af63d 100644
--- a/core/java/android/bluetooth/IBluetoothMap.aidl
+++ b/core/java/android/bluetooth/IBluetoothMap.aidl
@@ -27,6 +27,11 @@
int getState();
BluetoothDevice getClient();
boolean connect(in BluetoothDevice device);
- void disconnect();
+ boolean disconnect(in BluetoothDevice device);
boolean isConnected(in BluetoothDevice device);
+ List<BluetoothDevice> getConnectedDevices();
+ List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+ int getConnectionState(in BluetoothDevice device);
+ boolean setPriority(in BluetoothDevice device, int priority);
+ int getPriority(in BluetoothDevice device);
}
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 69f9d4a..73e6fd0 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -122,7 +122,7 @@
if (clip != null) {
clip.prepareToLeaveProcess();
}
- getService().setPrimaryClip(clip, mContext.getBasePackageName());
+ getService().setPrimaryClip(clip, mContext.getOpPackageName());
} catch (RemoteException e) {
}
}
@@ -132,7 +132,7 @@
*/
public ClipData getPrimaryClip() {
try {
- return getService().getPrimaryClip(mContext.getBasePackageName());
+ return getService().getPrimaryClip(mContext.getOpPackageName());
} catch (RemoteException e) {
return null;
}
@@ -144,7 +144,7 @@
*/
public ClipDescription getPrimaryClipDescription() {
try {
- return getService().getPrimaryClipDescription(mContext.getBasePackageName());
+ return getService().getPrimaryClipDescription(mContext.getOpPackageName());
} catch (RemoteException e) {
return null;
}
@@ -155,7 +155,7 @@
*/
public boolean hasPrimaryClip() {
try {
- return getService().hasPrimaryClip(mContext.getBasePackageName());
+ return getService().hasPrimaryClip(mContext.getOpPackageName());
} catch (RemoteException e) {
return false;
}
@@ -166,7 +166,7 @@
if (mPrimaryClipChangedListeners.size() == 0) {
try {
getService().addPrimaryClipChangedListener(
- mPrimaryClipChangedServiceListener, mContext.getBasePackageName());
+ mPrimaryClipChangedServiceListener, mContext.getOpPackageName());
} catch (RemoteException e) {
}
}
@@ -213,7 +213,7 @@
*/
public boolean hasText() {
try {
- return getService().hasClipboardText(mContext.getBasePackageName());
+ return getService().hasClipboardText(mContext.getOpPackageName());
} catch (RemoteException e) {
return false;
}
diff --git a/core/java/android/content/ComponentCallbacks.java b/core/java/android/content/ComponentCallbacks.java
index dad60b0..b96c8d3 100644
--- a/core/java/android/content/ComponentCallbacks.java
+++ b/core/java/android/content/ComponentCallbacks.java
@@ -22,6 +22,11 @@
* The set of callback APIs that are common to all application components
* ({@link android.app.Activity}, {@link android.app.Service},
* {@link ContentProvider}, and {@link android.app.Application}).
+ *
+ * <p class="note"><strong>Note:</strong> You should also implement the {@link
+ * ComponentCallbacks2} interface, which provides the {@link
+ * ComponentCallbacks2#onTrimMemory} callback to help your app manage its memory usage more
+ * effectively.</p>
*/
public interface ComponentCallbacks {
/**
@@ -29,26 +34,35 @@
* component is running. Note that, unlike activities, other components
* are never restarted when a configuration changes: they must always deal
* with the results of the change, such as by re-retrieving resources.
- *
+ *
* <p>At the time that this function has been called, your Resources
* object will have been updated to return resource values matching the
* new configuration.
- *
+ *
+ * <p>For more information, read <a href="{@docRoot}guide/topics/resources/runtime-changes.html"
+ * >Handling Runtime Changes</a>.
+ *
* @param newConfig The new device configuration.
*/
void onConfigurationChanged(Configuration newConfig);
-
+
/**
* This is called when the overall system is running low on memory, and
- * would like actively running process to try to tighten their belt. While
+ * actively running processes should trim their memory usage. While
* the exact point at which this will be called is not defined, generally
- * it will happen around the time all background process have been killed,
- * that is before reaching the point of killing processes hosting
+ * it will happen when all background process have been killed.
+ * That is, before reaching the point of killing processes hosting
* service and foreground UI that we would like to avoid killing.
- *
- * <p>Applications that want to be nice can implement this method to release
- * any caches or other unnecessary resources they may be holding on to.
- * The system will perform a gc for you after returning from this method.
+ *
+ * <p>You should implement this method to release
+ * any caches or other unnecessary resources you may be holding on to.
+ * The system will perform a garbage collection for you after returning from this method.
+ * <p>Preferably, you should implement {@link ComponentCallbacks2#onTrimMemory} from
+ * {@link ComponentCallbacks2} to incrementally unload your resources based on various
+ * levels of memory demands. That API is available for API level 14 and higher, so you should
+ * only use this {@link #onLowMemory} method as a fallback for older versions, which can be
+ * treated the same as {@link ComponentCallbacks2#onTrimMemory} with the {@link
+ * ComponentCallbacks2#TRIM_MEMORY_COMPLETE} level.</p>
*/
void onLowMemory();
}
diff --git a/core/java/android/content/ComponentCallbacks2.java b/core/java/android/content/ComponentCallbacks2.java
index a3b4e5e..b78548b 100644
--- a/core/java/android/content/ComponentCallbacks2.java
+++ b/core/java/android/content/ComponentCallbacks2.java
@@ -18,7 +18,68 @@
/**
* Extended {@link ComponentCallbacks} interface with a new callback for
- * finer-grained memory management.
+ * finer-grained memory management. This interface is available in all application components
+ * ({@link android.app.Activity}, {@link android.app.Service},
+ * {@link ContentProvider}, and {@link android.app.Application}).
+ *
+ * <p>You should implement {@link #onTrimMemory} to incrementally release memory based on current
+ * system constraints. Using this callback to release your resources helps provide a more
+ * responsive system overall, but also directly benefits the user experience for
+ * your app by allowing the system to keep your process alive longer. That is,
+ * if you <em>don't</em> trim your resources based on memory levels defined by this callback,
+ * the system is more likely to kill your process while it is cached in the least-recently used
+ * (LRU) list, thus requiring your app to restart and restore all state when the user returns to it.
+ *
+ * <p>The values provided by {@link #onTrimMemory} do not represent a single linear progression of
+ * memory limits, but provide you different types of clues about memory availability:</p>
+ * <ul>
+ * <li>When your app is running:
+ * <ol>
+ * <li>{@link #TRIM_MEMORY_RUNNING_MODERATE} <br>The device is beginning to run low on memory.
+ * Your app is running and not killable.
+ * <li>{@link #TRIM_MEMORY_RUNNING_LOW} <br>The device is running much lower on memory.
+ * Your app is running and not killable, but please release unused resources to improve system
+ * performance (which directly impacts your app's performance).
+ * <li>{@link #TRIM_MEMORY_RUNNING_CRITICAL} <br>The device is running extremely low on memory.
+ * Your app is not yet considered a killable process, but the system will begin killing
+ * background processes if apps do not release resources, so you should release non-critical
+ * resources now to prevent performance degradation.
+ * </ol>
+ * </li>
+ * <li>When your app's visibility changes:
+ * <ol>
+ * <li>{@link #TRIM_MEMORY_UI_HIDDEN} <br>Your app's UI is no longer visible, so this is a good
+ * time to release large resources that are used only by your UI.
+ * </ol>
+ * </li>
+ * <li>When your app's process resides in the background LRU list:
+ * <ol>
+ * <li>{@link #TRIM_MEMORY_BACKGROUND} <br>The system is running low on memory and your process is
+ * near the beginning of the LRU list. Although your app process is not at a high risk of being
+ * killed, the system may already be killing processes in the LRU list, so you should release
+ * resources that are easy to recover so your process will remain in the list and resume
+ * quickly when the user returns to your app.
+ * <li>{@link #TRIM_MEMORY_MODERATE} <br>The system is running low on memory and your process is
+ * near the middle of the LRU list. If the system becomes further constrained for memory, there's a
+ * chance your process will be killed.
+ * <li>{@link #TRIM_MEMORY_COMPLETE} <br>The system is running low on memory and your process is
+ * one of the first to be killed if the system does not recover memory now. You should release
+ * absolutely everything that's not critical to resuming your app state.
+ * <p>To support API levels lower than 14, you can use the {@link #onLowMemory} method as a
+ * fallback that's roughly equivalent to the {@link ComponentCallbacks2#TRIM_MEMORY_COMPLETE} level.
+ * </li>
+ * </ol>
+ * <p class="note"><strong>Note:</strong> When the system begins
+ * killing processes in the LRU list, although it primarily works bottom-up, it does give some
+ * consideration to which processes are consuming more memory and will thus provide more gains in
+ * memory if killed. So the less memory you consume while in the LRU list overall, the better
+ * your chances are to remain in the list and be able to quickly resume.</p>
+ * </li>
+ * </ul>
+ * <p>More information about the different stages of a process lifecycle (such as what it means
+ * to be placed in the background LRU list) is provided in the <a
+ * href="{@docRoot}guide/components/processes-and-threads.html#Lifecycle">Processes and Threads</a>
+ * document.
*/
public interface ComponentCallbacks2 extends ComponentCallbacks {
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 65a3a07..9a258dc 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -34,7 +34,6 @@
import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
import android.os.Process;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
@@ -196,13 +195,13 @@
return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.query(
uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -216,11 +215,11 @@
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return rejectInsert(uri, initialValues);
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.insert(uri, initialValues);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -229,11 +228,11 @@
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.bulkInsert(uri, initialValues);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -256,11 +255,11 @@
}
}
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.applyBatch(operations);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -269,11 +268,11 @@
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.delete(uri, selection, selectionArgs);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -283,11 +282,11 @@
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.update(uri, values, selection, selectionArgs);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -296,12 +295,12 @@
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, mode);
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openFile(
uri, mode, CancellationSignal.fromTransport(cancellationSignal));
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -310,22 +309,22 @@
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, mode);
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openAssetFile(
uri, mode, CancellationSignal.fromTransport(cancellationSignal));
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@Override
public Bundle call(String callingPkg, String method, String arg, Bundle extras) {
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.call(method, arg, extras);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -338,12 +337,12 @@
public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, "r");
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openTypedAssetFile(
uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -357,11 +356,11 @@
if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return null;
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.canonicalize(uri);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -370,11 +369,11 @@
if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return null;
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.uncanonicalize(uri);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -540,6 +539,16 @@
}
/**
+ * Set the calling package, returning the current value (or {@code null})
+ * which can be used later to restore the previous state.
+ */
+ private String setCallingPackage(String callingPackage) {
+ final String original = mCallingPackage.get();
+ mCallingPackage.set(callingPackage);
+ return original;
+ }
+
+ /**
* Return the package name of the caller that initiated the request being
* processed on the current thread. The returned package will have been
* verified to belong to the calling UID. Returns {@code null} if not
@@ -909,8 +918,10 @@
*
* @param url The Uri to remove any canonicalization from.
*
- * @return Return the non-canonical representation of <var>url</var>, or return
- * the <var>url</var> as-is if there is nothing to do. Never return null.
+ * @return Return the non-canonical representation of <var>url</var>, return
+ * the <var>url</var> as-is if there is nothing to do, or return null if
+ * the data identified by the canonical representation can not be found in
+ * the current environment.
*/
public Uri uncanonicalize(Uri url) {
return url;
@@ -1562,8 +1573,10 @@
*/
if (mContext == null) {
mContext = context;
- mTransport.mAppOpsManager = (AppOpsManager) mContext.getSystemService(
- Context.APP_OPS_SERVICE);
+ if (context != null) {
+ mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
+ Context.APP_OPS_SERVICE);
+ }
mMyUid = Process.myUid();
if (info != null) {
setReadPermission(info.readPermission);
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index e83c727..39b453d 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -72,6 +72,7 @@
throws RemoteException {
ICancellationSignal remoteCancellationSignal = null;
if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
remoteCancellationSignal = mContentProvider.createCancellationSignal();
cancellationSignal.setRemote(remoteCancellationSignal);
}
@@ -208,6 +209,7 @@
throws RemoteException, FileNotFoundException {
ICancellationSignal remoteSignal = null;
if (signal != null) {
+ signal.throwIfCanceled();
remoteSignal = mContentProvider.createCancellationSignal();
signal.setRemote(remoteSignal);
}
@@ -244,6 +246,7 @@
throws RemoteException, FileNotFoundException {
ICancellationSignal remoteSignal = null;
if (signal != null) {
+ signal.throwIfCanceled();
remoteSignal = mContentProvider.createCancellationSignal();
signal.setRemote(remoteSignal);
}
@@ -269,6 +272,7 @@
throws RemoteException, FileNotFoundException {
ICancellationSignal remoteSignal = null;
if (signal != null) {
+ signal.throwIfCanceled();
remoteSignal = mContentProvider.createCancellationSignal();
signal.setRemote(remoteSignal);
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index e914604..f250029 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -261,7 +261,7 @@
public ContentResolver(Context context) {
mContext = context != null ? context : ActivityThread.currentApplication();
- mPackageName = mContext.getBasePackageName();
+ mPackageName = mContext.getOpPackageName();
}
/** @hide */
@@ -548,14 +548,16 @@
* it to its local non-canonical form. This can be useful in some cases where
* you know that you will only be using the Uri in the current environment and
* want to avoid any possible overhead when using it with the content
- * provider.
+ * provider or want to verify that the referenced data exists at all in the
+ * new environment.
*
* @param url The canonical {@link Uri} that is to be convered back to its
* non-canonical form.
*
- * @return Returns the non-canonical representation of <var>url</var>. This
- * function never returns null; if there is no conversion to be done, it returns
- * the same Uri that was provided.
+ * @return Returns the non-canonical representation of <var>url</var>. This will
+ * return null if data identified by the canonical Uri can not be found in
+ * the current environment; callers must always check for null and deal with
+ * that by appropriately falling back to an alternative.
*
* @see #canonicalize
*/
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 8df5bee..02ccaa5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -435,6 +435,13 @@
/** @hide Return the name of the base context this context is derived from. */
public abstract String getBasePackageName();
+ /** @hide Return the package name that should be used for app ops calls from
+ * this context. This is the same as {@link #getBasePackageName()} except in
+ * cases where system components are loaded into other app processes, in which
+ * case this will be the name of the primary package in that process (so that app
+ * ops uid verification will work with the name). */
+ public abstract String getOpPackageName();
+
/** Return the full application info for this context's package. */
public abstract ApplicationInfo getApplicationInfo();
@@ -2125,13 +2132,8 @@
public static final String UPDATE_LOCK_SERVICE = "updatelock";
/**
- * Use with {@link #getSystemService} to retrieve a {@link
- * android.net.NetworkManagementService} for handling management of
- * system network services
- *
+ * Constant for the internal network management service, not really a Context service.
* @hide
- * @see #getSystemService
- * @see android.net.NetworkManagementService
*/
public static final String NETWORKMANAGEMENT_SERVICE = "network_management";
@@ -2320,7 +2322,7 @@
* android.hardware.SerialManager} for access to serial ports.
*
* @see #getSystemService
- * @see android.harware.SerialManager
+ * @see android.hardware.SerialManager
*
* @hide
*/
@@ -2346,17 +2348,6 @@
/**
* Use with {@link #getSystemService} to retrieve a
- * {@link android.os.SchedulingPolicyService} for managing scheduling policy.
- *
- * @see #getSystemService
- * @see android.os.SchedulingPolicyService
- *
- * @hide
- */
- public static final String SCHEDULING_POLICY_SERVICE = "scheduling_policy";
-
- /**
- * Use with {@link #getSystemService} to retrieve a
* {@link android.os.UserManager} for managing users on devices that support multiple users.
*
* @see #getSystemService
@@ -2394,6 +2385,16 @@
public static final String PRINT_SERVICE = "print";
/**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.hardware.ConsumerIrManager} for transmitting infrared
+ * signals from the device.
+ *
+ * @see #getSystemService
+ * @see android.hardware.ConsumerIrManager
+ */
+ public static final String CONSUMER_IR_SERVICE = "consumer_ir";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index e09d367..a708dad 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -141,6 +141,12 @@
return mBase.getBasePackageName();
}
+ /** @hide */
+ @Override
+ public String getOpPackageName() {
+ return mBase.getOpPackageName();
+ }
+
@Override
public ApplicationInfo getApplicationInfo() {
return mBase.getApplicationInfo();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2f2aae4..7925123 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1153,9 +1153,8 @@
/**
* Activity Action: Perform assist action.
* <p>
- * Input: {@link #EXTRA_ASSIST_PACKAGE}, {@link #EXTRA_ASSIST_CONTEXT},
- * {@link #EXTRA_ASSIST_SERVICES_PACKAGES}, and {@link #EXTRA_ASSIST_SERVICES_CONTEXTS} can
- * provide additional optional contextual information about where the user was when they
+ * Input: {@link #EXTRA_ASSIST_PACKAGE}, {@link #EXTRA_ASSIST_CONTEXT}, can provide
+ * additional optional contextual information about where the user was when they
* requested the assist.
* Output: nothing.
*/
@@ -1165,52 +1164,31 @@
/**
* Activity Action: Perform voice assist action.
* <p>
- * Input: {@link #EXTRA_ASSIST_PACKAGE}, {@link #EXTRA_ASSIST_CONTEXT},
- * {@link #EXTRA_ASSIST_SERVICES_PACKAGES}, and {@link #EXTRA_ASSIST_SERVICES_CONTEXTS} can
- * provide additional optional contextual information about where the user was when they
+ * Input: {@link #EXTRA_ASSIST_PACKAGE}, {@link #EXTRA_ASSIST_CONTEXT}, can provide
+ * additional optional contextual information about where the user was when they
* requested the voice assist.
* Output: nothing.
+ * @hide
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
/**
- * An optional field on {@link #ACTION_ASSIST} and {@link #ACTION_VOICE_ASSIST}
- * containing the name of the current foreground application package at the time
- * the assist was invoked.
+ * An optional field on {@link #ACTION_ASSIST} containing the name of the current foreground
+ * application package at the time the assist was invoked.
*/
public static final String EXTRA_ASSIST_PACKAGE
= "android.intent.extra.ASSIST_PACKAGE";
/**
- * An optional field on {@link #ACTION_ASSIST} and {@link #ACTION_VOICE_ASSIST}
- * containing additional contextual information supplied by the current
- * foreground app at the time of the assist request. This is a {@link Bundle} of
- * additional data.
+ * An optional field on {@link #ACTION_ASSIST} and containing additional contextual
+ * information supplied by the current foreground app at the time of the assist request.
+ * This is a {@link Bundle} of additional data.
*/
public static final String EXTRA_ASSIST_CONTEXT
= "android.intent.extra.ASSIST_CONTEXT";
/**
- * An optional field on {@link #ACTION_ASSIST} and {@link #ACTION_VOICE_ASSIST}
- * containing the application package names of foreground services at the time
- * of the assist request. This is an array of {@link String}s, with one entry
- * per service.
- */
- public static final String EXTRA_ASSIST_SERVICES_PACKAGES
- = "android.intent.extra.ASSIST_SERVICES_PACKAGES";
-
- /**
- * An optional field on {@link #ACTION_ASSIST} and {@link #ACTION_VOICE_ASSIST}
- * containing additional contextual information supplied by the current
- * foreground services at the time of the assist request. This is an array
- * of {@link Bundle}s of additional data, with one {@link Bundle} per service.
- */
- public static final String EXTRA_ASSIST_SERVICES_CONTEXTS
- = "android.intent.extra.ASSIST_SERVICES_CONTEXTS";
-
-
- /**
* Activity Action: List all available applications
* <p>Input: Nothing.
* <p>Output: nothing.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 2b0c896..acd4ffa 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -234,6 +234,12 @@
out List<ComponentName> outActivities, String packageName);
/**
+ * Report the set of 'Home' activity candidates, plus (if any) which of them
+ * is the current "always use this one" setting.
+ */
+ ComponentName getHomeActivities(out List<ResolveInfo> outHomeCandidates);
+
+ /**
* As per {@link android.content.pm.PackageManager#setComponentEnabledSetting}.
*/
void setComponentEnabledSetting(in ComponentName componentName,
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d58b14c..9203af9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1196,6 +1196,13 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports device policy enforcement via device admins.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports WiFi (802.11) networking.
*/
@SdkConstant(SdkConstantType.FEATURE)
@@ -3027,6 +3034,13 @@
List<ComponentName> outActivities, String packageName);
/**
+ * Ask for the set of available 'home' activities and the current explicit
+ * default, if any.
+ * @hide
+ */
+ public abstract ComponentName getHomeActivities(List<ResolveInfo> outActivities);
+
+ /**
* Set the enabled setting for a package component (activity, receiver, service, provider).
* This setting will override any enabled state which may have been set by the component in its
* manifest.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 6760f49..2e25177 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1441,18 +1441,29 @@
*/
boolean required = true; // Optional <uses-permission> not supported
+ int maxSdkVersion = 0;
+ TypedValue val = sa.peekValue(
+ com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
+ if (val != null) {
+ if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
+ maxSdkVersion = val.data;
+ }
+ }
+
sa.recycle();
- if (name != null) {
- int index = pkg.requestedPermissions.indexOf(name);
- if (index == -1) {
- pkg.requestedPermissions.add(name.intern());
- pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
- } else {
- if (pkg.requestedPermissionsRequired.get(index) != required) {
- outError[0] = "conflicting <uses-permission> entries";
- mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return false;
+ if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) {
+ if (name != null) {
+ int index = pkg.requestedPermissions.indexOf(name);
+ if (index == -1) {
+ pkg.requestedPermissions.add(name.intern());
+ pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
+ } else {
+ if (pkg.requestedPermissionsRequired.get(index) != required) {
+ outError[0] = "conflicting <uses-permission> entries";
+ mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+ return false;
+ }
}
}
}
@@ -3015,11 +3026,6 @@
s.info.flags = 0;
if (sa.getBoolean(
- com.android.internal.R.styleable.AndroidManifestService_provideAssistData,
- false)) {
- s.info.flags |= ServiceInfo.FLAG_PROVIDE_ASSIST_DATA;
- }
- if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestService_stopWithTask,
false)) {
s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 3dc8717..796c2a4 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -49,14 +49,6 @@
public static final int FLAG_ISOLATED_PROCESS = 0x0002;
/**
- * Bit in {@link #flags}: If set,
- * {@link android.app.Service#onProvideAssistData(android.os.Bundle)} will
- * be called on the service when it is running in the foreground. Set from
- * the {@link android.R.attr#provideAssistData} attribute.
- */
- public static final int FLAG_PROVIDE_ASSIST_DATA = 0x0004;
-
- /**
* Bit in {@link #flags}: If set, a single instance of the service will
* run for all users on the device. Set from the
* {@link android.R.attr#singleUser} attribute.
diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java
index 2a0d9b9..5e107f2 100644
--- a/core/java/android/database/MatrixCursor.java
+++ b/core/java/android/database/MatrixCursor.java
@@ -186,7 +186,7 @@
* column value at a time. This follows the same ordering as the column
* names specified at cursor construction time.
* <li>Column and value pairs can be offered for possible inclusion using
- * {@link #offer(String, Object)}. If the cursor includes the given column,
+ * {@link #add(String, Object)}. If the cursor includes the given column,
* the value will be set for that column, otherwise the value is ignored.
* This approach is useful when matching data to a custom projection.
* </ul>
@@ -227,7 +227,7 @@
*
* @return this builder to support chaining
*/
- public RowBuilder offer(String columnName, Object value) {
+ public RowBuilder add(String columnName, Object value) {
for (int i = 0; i < columnNames.length; i++) {
if (columnName.equals(columnNames[i])) {
data[(row * columnCount) + i] = value;
diff --git a/core/java/android/hardware/ConsumerIrManager.java b/core/java/android/hardware/ConsumerIrManager.java
new file mode 100644
index 0000000..77087814
--- /dev/null
+++ b/core/java/android/hardware/ConsumerIrManager.java
@@ -0,0 +1,156 @@
+/*
+ * 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.hardware;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * Class that operates consumer infrared on the device.
+ *
+ * <p>
+ * To obtain an instance of the system infrared transmitter, call
+ * {@link android.content.Context#getSystemService(java.lang.String)
+ * Context.getSystemService()} with
+ * {@link android.content.Context#CONSUMER_IR_SERVICE} as the argument.
+ * </p>
+ */
+public final class ConsumerIrManager {
+ private static final String TAG = "ConsumerIr";
+
+ private final String mPackageName;
+ private final IConsumerIrService mService;
+
+ /**
+ * @hide to prevent subclassing from outside of the framework
+ */
+ public ConsumerIrManager(Context context) {
+ mPackageName = context.getPackageName();
+ mService = IConsumerIrService.Stub.asInterface(
+ ServiceManager.getService(Context.CONSUMER_IR_SERVICE));
+ }
+
+ /**
+ * Check whether the device has an infrared emitter.
+ *
+ * @return true if the device has an infrared emitter, else false.
+ */
+ public boolean hasIrEmitter() {
+ if (mService == null) {
+ Log.w(TAG, "no consumer ir service.");
+ return false;
+ }
+
+ try {
+ return mService.hasIrEmitter();
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
+
+ /**
+ * Tansmit and infrared pattern
+ * <p>
+ * This method is synchronous; when it returns the pattern has
+ * been transmitted. Only patterns shorter than 2 seconds will
+ * be transmitted.
+ * </p>
+ *
+ * @param carrierFrequency The IR carrier frequency in Hertz.
+ * @param pattern The alternating on/off pattern in microseconds to transmit.
+ */
+ public void transmit(int carrierFrequency, int[] pattern) {
+ if (mService == null) {
+ Log.w(TAG, "failed to transmit; no consumer ir service.");
+ return;
+ }
+
+ try {
+ mService.transmit(mPackageName, carrierFrequency, pattern);
+ } catch (RemoteException e) {
+ Log.w(TAG, "failed to transmit.", e);
+ }
+ }
+
+ /**
+ * Represents a range of carrier frequencies (inclusive) on which the
+ * infrared transmitter can transmit
+ */
+ public final class CarrierFrequencyRange {
+ private final int mMinFrequency;
+ private final int mMaxFrequency;
+
+ /**
+ * Create a segment of a carrier frequency range.
+ *
+ * @param min The minimum transmittable frequency in this range segment.
+ * @param max The maximum transmittable frequency in this range segment.
+ */
+ public CarrierFrequencyRange(int min, int max) {
+ mMinFrequency = min;
+ mMaxFrequency = max;
+ }
+
+ /**
+ * Get the minimum (inclusive) frequency in this range segment.
+ */
+ public int getMinFrequency() {
+ return mMinFrequency;
+ }
+
+ /**
+ * Get the maximum (inclusive) frequency in this range segment.
+ */
+ public int getMaxFrequency() {
+ return mMaxFrequency;
+ }
+ };
+
+ /**
+ * Query the infrared transmitter's supported carrier frequencies
+ *
+ * @return an array of
+ * {@link android.hardware.ConsumerIrManager.CarrierFrequencyRange}
+ * objects representing the ranges that the transmitter can support, or
+ * null if there was an error communicating with the Consumer IR Service.
+ */
+ public CarrierFrequencyRange[] getCarrierFrequencies() {
+ if (mService == null) {
+ Log.w(TAG, "no consumer ir service.");
+ return null;
+ }
+
+ try {
+ int[] freqs = mService.getCarrierFrequencies();
+ if (freqs.length % 2 != 0) {
+ Log.w(TAG, "consumer ir service returned an uneven number of frequencies.");
+ return null;
+ }
+ CarrierFrequencyRange[] range = new CarrierFrequencyRange[freqs.length / 2];
+
+ for (int i = 0; i < freqs.length; i += 2) {
+ range[i / 2] = new CarrierFrequencyRange(freqs[i], freqs[i+1]);
+ }
+ return range;
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
+}
diff --git a/core/res/res/values-land/refs.xml b/core/java/android/hardware/IConsumerIrService.aidl
similarity index 72%
copy from core/res/res/values-land/refs.xml
copy to core/java/android/hardware/IConsumerIrService.aidl
index cda38cf..c79bd19 100644
--- a/core/res/res/values-land/refs.xml
+++ b/core/java/android/hardware/IConsumerIrService.aidl
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+/**
* Copyright (c) 2013, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,8 +12,15 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
-*/
--->
-<resources>
- <item type="string" name="transient_navigation_confirmation">@string/transient_navigation_confirmation_long</item>
-</resources>
\ No newline at end of file
+ */
+
+package android.hardware;
+
+/** {@hide} */
+interface IConsumerIrService
+{
+ boolean hasIrEmitter();
+ void transmit(String packageName, int carrierFrequency, in int[] pattern);
+ int[] getCarrierFrequencies();
+}
+
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index a4a56d7..0c13b0f 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -17,6 +17,8 @@
package android.hardware.camera2;
import android.view.Surface;
+import android.os.Handler;
+import android.util.Log;
import java.lang.AutoCloseable;
import java.util.List;
@@ -87,6 +89,16 @@
public static final int TEMPLATE_VIDEO_SNAPSHOT = 4;
/**
+ * Create a request suitable for zero shutter lag still capture. This means
+ * means maximizing image quality without compromising preview frame rate.
+ * AE/AWB/AF should be on auto mode.
+ *
+ * @see #createCaptureRequest
+ * @hide
+ */
+ public static final int TEMPLATE_ZERO_SHUTTER_LAG = 5;
+
+ /**
* A basic template for direct application control of capture
* parameters. All automatic control is disabled (auto-exposure, auto-white
* balance, auto-focus), and post-processing parameters are set to preview
@@ -95,8 +107,29 @@
* application depending on the intended use case.
*
* @see #createCaptureRequest
+ * @hide
*/
- public static final int TEMPLATE_MANUAL = 5;
+ public static final int TEMPLATE_MANUAL = 6;
+
+ /**
+ * Get the ID of this camera device.
+ *
+ * <p>This matches the ID given to {@link CameraManager#openCamera} to instantiate this
+ * this camera device.</p>
+ *
+ * <p>This ID can be used to query the camera device's {@link
+ * CameraProperties fixed properties} with {@link
+ * CameraManager#getCameraProperties}.</p>
+ *
+ * <p>This method can be called even if the device has been closed or has encountered
+ * a serious error.</p>
+ *
+ * @return the ID for this camera device
+ *
+ * @see CameraManager#getCameraProperties
+ * @see CameraManager#getDeviceIdList
+ */
+ public String getId();
/**
* Get the static properties for this camera. These are identical to the
@@ -109,6 +142,7 @@
* @see CameraManager#getCameraProperties
*/
public CameraProperties getProperties() throws CameraAccessException;
+
/**
* <p>Set up a new output set of Surfaces for the camera device.</p>
*
@@ -177,10 +211,16 @@
* if the format is user-visible, it must be one of android.scaler.availableFormats;
* and the size must be one of android.scaler.available[Processed|Jpeg]Sizes).</p>
*
- * <p>To change the configuration after requests have been submitted to the
- * device, the camera device must be idle. To idle the device, stop any
- * repeating requests with {@link #stopRepeating stopRepeating}, and then
- * call {@link #waitUntilIdle waitUntilIdle}.</p>
+ * <p>To change the output, the camera device must be idle. The device is considered
+ * to be idle once all in-flight and pending capture requests have been processed,
+ * and all output image buffers from the captures have been sent to their destination
+ * Surfaces.</p>
+ *
+ * <p>To reach an idle state without cancelling any submitted captures, first
+ * stop any repeating request/burst with {@link #stopRepeating}, and then
+ * wait for the {@link CameraDeviceListener#onCameraIdle} callback to be
+ * called. To idle as fast as possible, use {@link #flush} and wait for the
+ * idle callback.</p>
*
* <p>Using larger resolution outputs, or more outputs, can result in slower
* output rate from the device.</p>
@@ -193,19 +233,25 @@
* @throws CameraAccessException if the camera device is no longer connected
* @throws IllegalStateException if the camera device is not idle, or has
* encountered a fatal error
+ *
+ * @see CameraDeviceListener#onCameraIdle
+ * @see #stopRepeating
+ * @see #flush
*/
public void configureOutputs(List<Surface> outputs) throws CameraAccessException;
/**
- * <p>Create a {@link CaptureRequest} initialized with template for a target
- * use case. The settings are chosen to be the best options for the specific
- * camera device, so it is not recommended to reuse the same request for a
- * different camera device; create a request for that device and override
- * the settings as desired, instead.</p>
+ * <p>Create a {@link CaptureRequest.Builder} for new capture requests,
+ * initialized with template for a target use case. The settings are chosen
+ * to be the best options for the specific camera device, so it is not
+ * recommended to reuse the same request for a different camera device;
+ * create a builder specific for that device and template and override the
+ * settings as desired, instead.</p>
*
* @param templateType An enumeration selecting the use case for this
* request; one of the CameraDevice.TEMPLATE_ values.
- * @return a filled-in CaptureRequest, except for output streams
+ * @return a builder for a capture request, initialized with default
+ * settings for that template, and no output streams
*
* @throws IllegalArgumentException if the templateType is not in the list
* of supported templates.
@@ -219,7 +265,7 @@
* @see #TEMPLATE_VIDEO_SNAPSHOT
* @see #TEMPLATE_MANUAL
*/
- public CaptureRequest createCaptureRequest(int templateType)
+ public CaptureRequest.Builder createCaptureRequest(int templateType)
throws CameraAccessException;
/**
@@ -229,7 +275,10 @@
* including sensor, lens, flash, and post-processing settings.</p>
*
* <p>Each request will produce one {@link CaptureResult} and produce new
- * frames for one or more target Surfaces, as defined by the request's .</p>
+ * frames for one or more target Surfaces, set with the CaptureRequest
+ * builder's {@link CaptureRequest.Builder#addTarget} method. The target
+ * surfaces must be configured as active outputs with
+ * {@link #configureOutputs} before calling this method.</p>
*
* <p>Multiple requests can be in progress at once. They are processed in
* first-in, first-out order, with minimal delays between each
@@ -242,27 +291,36 @@
* @param listener The callback object to notify once this request has been
* processed. If null, no metadata will be produced for this capture,
* although image data will still be produced.
+ * @param handler the handler on which the listener should be invoked, or
+ * {@code null} to use the current thread's {@link android.os.Looper
+ * looper}.
*
* @throws CameraAccessException if the camera device is no longer connected
* @throws IllegalStateException if the camera device has been closed or the
* device has encountered a fatal error.
+ * @throws IllegalArgumentException If the request targets Surfaces not
+ * currently configured as outputs. Or if the handler is null, the listener
+ * is not null, and the calling thread has no looper.
*
* @see #captureBurst
* @see #setRepeatingRequest
* @see #setRepeatingBurst
*/
- public void capture(CaptureRequest request, CaptureListener listener)
+ public void capture(CaptureRequest request, CaptureListener listener, Handler handler)
throws CameraAccessException;
/**
- * <p>Submit a list of requests to be captured in sequence as a burst. The
+ * Submit a list of requests to be captured in sequence as a burst. The
* burst will be captured in the minimum amount of time possible, and will
* not be interleaved with requests submitted by other capture or repeat
- * calls.</p>
+ * calls.
*
* <p>The requests will be captured in order, each capture producing one
- * {@link CaptureResult} and frames for one or more
- * target {@link android.view.Surface surfaces}.</p>
+ * {@link CaptureResult} and image buffers for one or more target
+ * {@link android.view.Surface surfaces}. The target surfaces for each
+ * request (set with {@link CaptureRequest.Builder#addTarget}) must be
+ * configured as active outputs with {@link #configureOutputs} before
+ * calling this method.</p>
*
* <p>The main difference between this method and simply calling
* {@link #capture} repeatedly is that this method guarantees that no
@@ -273,29 +331,38 @@
* requests in the burst has been processed. If null, no metadata will be
* produced for any requests in this burst, although image data will still
* be produced.
+ * @param handler the handler on which the listener should be invoked, or
+ * {@code null} to use the current thread's {@link android.os.Looper
+ * looper}.
*
* @throws CameraAccessException if the camera device is no longer connected
* @throws IllegalStateException if the camera device has been closed or the
* device has encountered a fatal error.
+ * @throws IllegalArgumentException If the requests target Surfaces not
+ * currently configured as outputs. Or if the handler is null, the listener
+ * is not null, and the calling thread has no looper.
*
* @see #capture
* @see #setRepeatingRequest
* @see #setRepeatingBurst
*/
- public void captureBurst(List<CaptureRequest> requests,
- CaptureListener listener) throws CameraAccessException;
+ public void captureBurst(List<CaptureRequest> requests, CaptureListener listener,
+ Handler handler) throws CameraAccessException;
/**
- * <p>Request endlessly repeating capture of images by this
- * CameraDevice.</p>
+ * Request endlessly repeating capture of images by this CameraDevice.
*
- * <p>With this method, the CameraDevice will continually capture
- * images using the settings in the provided {@link
- * CaptureRequest}, at the maximum rate possible.</p>
+ * <p>With this method, the CameraDevice will continually capture images
+ * using the settings in the provided {@link CaptureRequest}, at the maximum
+ * rate possible.</p>
+ *
+ * <p>Repeating requests are a simple way for an application to maintain a
+ * preview or other continuous stream of frames, without having to
+ * continually submit identical requests through {@link #capture}.</p>
*
* <p>Repeat requests have lower priority than those submitted
* through {@link #capture} or {@link #captureBurst}, so if
- * capture() is called when a repeating request is active, the
+ * {@link #capture} is called when a repeating request is active, the
* capture request will be processed before any further repeating
* requests are processed.<p>
*
@@ -306,20 +373,27 @@
* <p>To stop the repeating capture, call {@link #stopRepeating}. Calling
* {@link #flush} will also clear the request.</p>
*
- * <p>Calling repeat will replace a burst set up by {@link
- * #setRepeatingBurst}, although any in-progress burst will be
- * completed before the new repeat request will be used.</p>
+ * <p>Calling this method will replace any earlier repeating request or
+ * burst set up by this method or {@link #setRepeatingBurst}, although any
+ * in-progress burst will be completed before the new repeat request will be
+ * used.</p>
*
* @param request the request to repeat indefinitely
* @param listener The callback object to notify every time the
* request finishes processing. If null, no metadata will be
* produced for this stream of requests, although image data will
* still be produced.
+ * @param handler the handler on which the listener should be invoked, or
+ * {@code null} to use the current thread's {@link android.os.Looper
+ * looper}.
*
* @throws CameraAccessException if the camera device is no longer
* connected
* @throws IllegalStateException if the camera device has been closed or the
* device has encountered a fatal error.
+ * @throws IllegalArgumentException If the requests reference Surfaces not
+ * currently configured as outputs. Or if the handler is null, the listener
+ * is not null, and the calling thread has no looper.
*
* @see #capture
* @see #captureBurst
@@ -327,8 +401,8 @@
* @see #stopRepeating
* @see #flush
*/
- public void setRepeatingRequest(CaptureRequest request, CaptureListener listener)
- throws CameraAccessException;
+ public void setRepeatingRequest(CaptureRequest request, CaptureListener listener,
+ Handler handler) throws CameraAccessException;
/**
* <p>Request endlessly repeating capture of a sequence of images by this
@@ -347,26 +421,33 @@
*
* <p>Repeating burst requests are a simple way for an application to
* maintain a preview or other continuous stream of frames where each
- * request is different in a predicatable way, without having to submit
- * requests through {@link #capture} at video rates.</p>
+ * request is different in a predicatable way, without having to continually
+ * submit requests through {@link #captureBurst} .</p>
*
* <p>To stop the repeating capture, call {@link #stopRepeating}. Any
* ongoing burst will still be completed, however. Calling
* {@link #flush} will also clear the request.</p>
*
- * <p>Calling repeatBurst will replace a repeating request set up by
- * {@link #setRepeatingRequest}, although any in-progress capture will be completed
- * before the new repeat burst will be used.</p>
+ * <p>Calling this method will replace a previously-set repeating request or
+ * burst set up by this method or {@link #setRepeatingRequest}, although any
+ * in-progress burst will be completed before the new repeat burst will be
+ * used.</p>
*
* @param requests the list of requests to cycle through indefinitely
* @param listener The callback object to notify each time one of the
* requests in the repeating bursts has finished processing. If null, no
* metadata will be produced for this stream of requests, although image
* data will still be produced.
+ * @param handler the handler on which the listener should be invoked, or
+ * {@code null} to use the current thread's {@link android.os.Looper
+ * looper}.
*
* @throws CameraAccessException if the camera device is no longer connected
* @throws IllegalStateException if the camera device has been closed or the
* device has encountered a fatal error.
+ * @throws IllegalArgumentException If the requests reference Surfaces not
+ * currently configured as outputs. Or if the handler is null, the listener
+ * is not null, and the calling thread has no looper.
*
* @see #capture
* @see #captureBurst
@@ -374,8 +455,8 @@
* @see #stopRepeating
* @see #flush
*/
- public void setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener)
- throws CameraAccessException;
+ public void setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
+ Handler handler) throws CameraAccessException;
/**
* <p>Cancel any ongoing repeating capture set by either
@@ -385,8 +466,9 @@
*
* <p>Any currently in-flight captures will still complete, as will any
* burst that is mid-capture. To ensure that the device has finished
- * processing all of its capture requests and is in idle state, use the
- * {@link #waitUntilIdle waitUntilIdle} method.</p>
+ * processing all of its capture requests and is in idle state, wait for the
+ * {@link CameraDeviceListener#onCameraIdle} callback after calling this
+ * method..</p>
*
* @throws CameraAccessException if the camera device is no longer connected
* @throws IllegalStateException if the camera device has been closed or the
@@ -394,7 +476,7 @@
*
* @see #setRepeatingRequest
* @see #setRepeatingBurst
- * @see #waitUntilIdle
+ * @see CameraDeviceListener#onCameraIdle
*
* @throws CameraAccessException if the camera device is no longer connected
* @throws IllegalStateException if the camera device has been closed, the
@@ -429,16 +511,27 @@
public void waitUntilIdle() throws CameraAccessException;
/**
- * Set the error listener object to call when an asynchronous error
- * occurs. The errors reported here are only device-wide errors; errors
- * about individual requests or frames are reported through
- * {@link CaptureListener#onCaptureFailed}.
+ * Set the listener object to call when an asynchronous device event occurs,
+ * such as errors or idle notifications.
*
- * @param listener the ErrorListener to send asynchronous error
- * notifications to. Setting this to null will stop notifications about
- * asynchronous errors.
+ * <p>The events reported here are device-wide; notifications about
+ * individual capture requests or capture results are reported through
+ * {@link CaptureListener}.</p>
+ *
+ * <p>If the camera device is idle when the listener is set, then the
+ * {@link CameraDeviceListener#onCameraIdle} method will be immediately called,
+ * even if the device has never been active before.
+ * </p>
+ *
+ * @param listener the CameraDeviceListener to send device-level event
+ * notifications to. Setting this to null will stop notifications.
+ * @param handler the handler on which the listener should be invoked, or
+ * {@code null} to use the current thread's {@link android.os.Looper looper}.
+ *
+ * @throws IllegalArgumentException if handler is null, the listener is
+ * not null, and the calling thread has no looper
*/
- public void setErrorListener(ErrorListener listener);
+ public void setDeviceListener(CameraDeviceListener listener, Handler handler);
/**
* Flush all captures currently pending and in-progress as fast as
@@ -446,7 +539,7 @@
*
* <p>The camera device will discard all of its current work as fast as
* possible. Some in-flight captures may complete successfully and call
- * {@link CaptureListener#onCaptureComplete}, while others will trigger
+ * {@link CaptureListener#onCaptureCompleted}, while others will trigger
* their {@link CaptureListener#onCaptureFailed} callbacks. If a repeating
* request or a repeating burst is set, it will be cleared by the flush.</p>
*
@@ -483,14 +576,60 @@
// TODO: We should decide on the behavior of in-flight requests should be on close.
/**
- * A listener for receiving metadata about completed image captures. The
- * metadata includes, among other things, the final capture settings and the
- * state of the control algorithms.
+ * <p>A listener for tracking the progress of a {@link CaptureRequest}
+ * submitted to the camera device.</p>
+ *
+ * <p>This listener is called when a request triggers a capture to start,
+ * and when the capture is complete. In case on an error capturing an image,
+ * the error method is triggered instead of the completion method.</p>
+ *
+ * @see #capture
+ * @see #captureBurst
+ * @see #setRepeatingRequest
+ * @see #setRepeatingBurst
+ *
*/
- public interface CaptureListener {
+ public static abstract class CaptureListener {
+
/**
- * <p>Called when a capture request has been processed by a
- * {@link CameraDevice}.</p>
+ * This method is called when the camera device has started capturing
+ * the output image for the request, at the beginning of image exposure.
+ *
+ * <p>This callback is invoked right as the capture of a frame begins,
+ * so it is the most appropriate time for playing a shutter sound,
+ * or triggering UI indicators of capture.</p>
+ *
+ * <p>The request that is being used for this capture is provided, along
+ * with the actual timestamp for the start of exposure. This timestamp
+ * matches the timestamp that will be included in
+ * {@link CaptureResult#SENSOR_TIMESTAMP the result timestamp field},
+ * and in the buffers sent to each output Surface. These buffer
+ * timestamps are accessible through, for example,
+ * {@link android.media.Image#getTimestamp() Image.getTimestamp()} or
+ * {@link android.graphics.SurfaceTexture#getTimestamp()}.</p>
+ *
+ * <p>For the simplest way to play a shutter sound camera shutter or a
+ * video recording start/stop sound, see the
+ * {@link android.media.MediaActionSound} class.</p>
+ *
+ * <p>The default implementation of this method does nothing.</p>
+ *
+ * @param camera the CameraDevice sending the callback
+ * @param request the request for the capture that just begun
+ * @param timestamp the timestamp at start of capture, in nanoseconds.
+ *
+ * @see android.media.MediaActionSound
+ */
+ public void onCaptureStarted(CameraDevice camera,
+ CaptureRequest request, long timestamp) {
+ // default empty implementation
+ }
+
+ /**
+ * This method is called when an image capture has completed and the
+ * result metadata is available.
+ *
+ * <p>The default implementation of this method does nothing.</p>
*
* @param camera The CameraDevice sending the callback.
* @param request The request that was given to the CameraDevice
@@ -503,14 +642,21 @@
* @see #setRepeatingRequest
* @see #setRepeatingBurst
*/
- public void onCaptureComplete(CameraDevice camera,
- CaptureRequest request, CaptureResult result);
+ public void onCaptureCompleted(CameraDevice camera,
+ CaptureRequest request, CaptureResult result) {
+ // default empty implementation
+ }
/**
- * <p>Called instead of onCaptureComplete when the camera device failed
- * to produce a CaptureResult for the request. Other requests are
- * unaffected, and some or all image buffers from the capture may have
- * been pushed to their respective output streams.</p>
+ * This method is called instead of {@link #onCaptureCompleted} when the
+ * camera device failed to produce a {@link CaptureResult} for the
+ * request.
+ *
+ * <p>Other requests are unaffected, and some or all image buffers from
+ * the capture may have been pushed to their respective output
+ * streams.</p>
+ *
+ * <p>The default implementation of this method does nothing.</p>
*
* @param camera The CameraDevice sending the callback.
* @param request The request that was given to the CameraDevice
@@ -521,62 +667,129 @@
* @see #setRepeatingBurst
*/
public void onCaptureFailed(CameraDevice camera,
- CaptureRequest request);
+ CaptureRequest request) {
+ // default empty implementation
+ }
}
/**
- * <p>A listener for asynchronous errors from the camera device. Errors
- * about specific {@link CaptureRequest CaptureRequests} are sent through
- * the capture {@link CaptureListener#onCaptureFailed listener}
- * interface. Errors reported through this listener affect the device as a
- * whole.</p>
+ * A listener for notifications about the state of a camera
+ * device.
+ *
+ * <p>These events include notifications about the device becoming idle (
+ * allowing for {@link #configureOutputs} to be called), about device
+ * disconnection, and about unexpected device errors.</p>
+ *
+ * <p>Events about the progress of specific {@link CaptureRequest
+ * CaptureRequests} are provided through a {@link CaptureListener} given to
+ * the {@link #capture}, {@link #captureBurst}, {@link
+ * #setRepeatingRequest}, or {@link #setRepeatingBurst} methods.
+ *
+ * @see #setDeviceListener
*/
- public interface ErrorListener {
+ public static abstract class CameraDeviceListener {
+
/**
- * <p>This camera device has been disconnected by the camera
- * service. Any attempt to call methods on this CameraDevice will throw
- * a {@link CameraAccessException}. The disconnection could be due to a
+ * An error code that can be reported by {@link #onCameraError}
+ * indicating that the camera device has encountered a fatal error.
+ *
+ * <p>The camera device needs to be re-opened to be used again.</p>
+ *
+ * @see #onCameraDeviceError
+ */
+ public static final int ERROR_CAMERA_DEVICE = 1;
+
+ /**
+ * An error code that can be reported by {@link #onCameraError}
+ * indicating that the camera service has encountered a fatal error.
+ *
+ * <p>The Android device may need to be shut down and restarted to restore
+ * camera function, or there may be a persistent hardware problem.</p>
+ *
+ * @see #onCameraDeviceError
+ */
+ public static final int ERROR_CAMERA_SERVICE = 2;
+
+ /**
+ * The method called when a camera device has finished processing all
+ * submitted capture requests and has reached an idle state.
+ *
+ * <p>An idle camera device can have its outputs changed by calling
+ * {@link CameraDevice#configureOutputs}.</p>
+ *
+ * <p>To idle and reconfigure outputs without cancelling any submitted
+ * capture requests, the application needs to clear its repeating
+ * request/burst, if set, with {@link CameraDevice#stopRepeating}, and
+ * then wait for this callback to be called before calling {@link
+ * CameraDevice#configureOutputs}.</p>
+ *
+ * <p>To idle and reconfigure a camera device as fast as possible, the
+ * {@link CameraDevice#flush} method can be used, which will discard all
+ * pending and in-progess capture requests. Once the {@link
+ * CameraDevice#flush} method is called, the application must wait for
+ * this callback to fire before calling {@link
+ * CameraDevice#configureOutputs}.</p>
+ *
+ * <p>The default implementation of this method does nothing.</p>
+ *
+ * @param camera the camera device that has become idle
+ *
+ * @see CameraDevice#configureOutputs
+ * @see CameraDevice#stopRepeating
+ * @see CameraDevice#flush
+ */
+ public void onCameraIdle(CameraDevice camera) {
+ // Default empty implementation
+ }
+
+ /**
+ * The method called when a camera device is no longer available for
+ * use.
+ *
+ * <p>Any attempt to call methods on this CameraDevice will throw a
+ * {@link CameraAccessException}. The disconnection could be due to a
* change in security policy or permissions; the physical disconnection
* of a removable camera device; or the camera being needed for a
* higher-priority use case.</p>
*
- * <p>There may still be capture completion or camera stream listeners
- * that will be called after this error is received.</p>
+ * <p>There may still be capture listener callbacks that are called
+ * after this method is called, or new image buffers that are delivered
+ * to active outputs.</p>
+ *
+ * <p>The default implementation logs a notice to the system log
+ * about the disconnection.</p>
+ *
+ * @param camera the device that has been disconnected
*/
- public static final int DEVICE_DISCONNECTED = 1;
+ public void onCameraDisconnected(CameraDevice camera) {
+ Log.i("CameraListener",
+ String.format("Camera device %s disconnected", camera.getId()));
+ }
/**
- * <p>The camera device has encountered a fatal error. Any attempt to
- * call methods on this CameraDevice will throw a
- * {@link java.lang.IllegalStateException}.</p>
+ * The method called when a camera device has encountered a serious error.
+ *
+ * <p>This indicates a failure of the camera device or camera service in
+ * some way. Any attempt to call methods on this CameraDevice in the
+ * future will throw a {@link java.lang.IllegalStateException}.</p>
*
* <p>There may still be capture completion or camera stream listeners
* that will be called after this error is received.</p>
*
- * <p>The application needs to re-open the camera device to use it
- * again.</p>
- */
- public static final int DEVICE_ERROR = 2;
-
- /**
- * <p>The camera service has encountered a fatal error. Any attempt to
- * call methods on this CameraDevice in the future will throw a
- * {@link java.lang.IllegalStateException}.</p>
- *
- * <p>There may still be capture completion or camera stream listeners
- * that will be called after this error is received.</p>
- *
- * <p>The device may need to be shut down and restarted to restore
- * camera function, or there may be a persistent hardware problem.</p>
- */
- public static final int SERVICE_ERROR = 3;
-
- /**
- * The method to call when a camera device has encountered an error.
+ * <p>The default implementation logs an error to the system log about
+ * the camera failure.</p>
*
* @param camera The device reporting the error
- * @param error The error code, one of the ErrorListener.ERROR_ values.
+ * @param error The error code, one of the
+ * {@code CameraDeviceListener.ERROR_*} values.
+ *
+ * @see #ERROR_CAMERA_DEVICE
+ * @see #ERROR_CAMERA_SERVICE
*/
- public void onCameraDeviceError(CameraDevice camera, int error);
+ public void onCameraError(CameraDevice camera, int error) {
+ Log.e("CameraListener",
+ String.format("Camera device %s has encountered an error: %d",
+ camera.getId(), error));
+ }
}
}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 8903b4a..4ad9259 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -20,17 +20,19 @@
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
import android.hardware.IProCameraUser;
+import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.hardware.camera2.utils.CameraRuntimeException;
import android.hardware.camera2.utils.BinderHolder;
import android.os.IBinder;
+import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
+import android.util.ArrayMap;
import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
/**
* <p>An interface for iterating, listing, and connecting to
@@ -55,7 +57,10 @@
private final ICameraService mCameraService;
private ArrayList<String> mDeviceIdList;
- private HashSet<CameraListener> mListenerSet = new HashSet<CameraListener>();
+
+ private ArrayMap<AvailabilityListener, Handler> mListenerMap =
+ new ArrayMap<AvailabilityListener, Handler>();
+
private final Context mContext;
private final Object mLock = new Object();
@@ -85,14 +90,16 @@
}
/**
- * <p>Return the list of currently connected camera devices by
- * identifier. Non-removable cameras use integers starting at 0 for their
+ * Return the list of currently connected camera devices by
+ * identifier.
+ *
+ * <p>Non-removable cameras use integers starting at 0 for their
* identifiers, while removable cameras have a unique identifier for each
* individual device, even if they are the same model.</p>
*
* @return The list of currently connected camera devices.
*/
- public String[] getDeviceIdList() throws CameraAccessException {
+ public String[] getCameraIdList() throws CameraAccessException {
synchronized (mLock) {
try {
return getOrCreateDeviceIdListLocked().toArray(new String[0]);
@@ -107,13 +114,25 @@
/**
* Register a listener to be notified about camera device availability.
*
- * Registering a listener more than once has no effect.
+ * <p>Registering the same listener again will replace the handler with the
+ * new one provided.</p>
*
* @param listener The new listener to send camera availability notices to
+ * @param handler The handler on which the listener should be invoked, or
+ * {@code null} to use the current thread's {@link android.os.Looper looper}.
*/
- public void registerCameraListener(CameraListener listener) {
+ public void addAvailabilityListener(AvailabilityListener listener, Handler handler) {
+ if (handler == null) {
+ Looper looper = Looper.myLooper();
+ if (looper == null) {
+ throw new IllegalArgumentException(
+ "No handler given, and current thread has no looper!");
+ }
+ handler = new Handler(looper);
+ }
+
synchronized (mLock) {
- mListenerSet.add(listener);
+ mListenerMap.put(listener, handler);
}
}
@@ -121,13 +140,13 @@
* Remove a previously-added listener; the listener will no longer receive
* connection and disconnection callbacks.
*
- * Removing a listener that isn't registered has no effect.
+ * <p>Removing a listener that isn't registered has no effect.</p>
*
* @param listener The listener to remove from the notification list
*/
- public void unregisterCameraListener(CameraListener listener) {
+ public void removeAvailabilityListener(AvailabilityListener listener) {
synchronized (mLock) {
- mListenerSet.remove(listener);
+ mListenerMap.remove(listener);
}
}
@@ -144,7 +163,7 @@
* @throws SecurityException if the application does not have permission to
* access the camera
*
- * @see #getDeviceIdList
+ * @see #getCameraIdList
* @see android.app.admin.DevicePolicyManager#setCameraDisabled
*/
public CameraProperties getCameraProperties(String cameraId)
@@ -160,14 +179,14 @@
// TODO: implement and call a service function to get the capabilities on C++ side
// TODO: get properties from service
- return new CameraProperties();
+ return new CameraProperties(new CameraMetadataNative());
}
/**
* Open a connection to a camera with the given ID. Use
- * {@link #getDeviceIdList} to get the list of available camera
+ * {@link #getCameraIdList} to get the list of available camera
* devices. Note that even if an id is listed, open may fail if the device
- * is disconnected between the calls to {@link #getDeviceIdList} and
+ * is disconnected between the calls to {@link #getCameraIdList} and
* {@link #openCamera}.
*
* @param cameraId The unique identifier of the camera device to open
@@ -179,7 +198,7 @@
* @throws SecurityException if the application does not have permission to
* access the camera
*
- * @see #getDeviceIdList
+ * @see #getCameraIdList
* @see android.app.admin.DevicePolicyManager#setCameraDisabled
*/
public CameraDevice openCamera(String cameraId) throws CameraAccessException {
@@ -218,29 +237,43 @@
}
/**
- * Interface for listening to cameras becoming available or unavailable.
- * Cameras become available when they are no longer in use, or when a new
+ * Interface for listening to camera devices becoming available or
+ * unavailable.
+ *
+ * <p>Cameras become available when they are no longer in use, or when a new
* removable camera is connected. They become unavailable when some
* application or service starts using a camera, or when a removable camera
- * is disconnected.
+ * is disconnected.</p>
+ *
+ * @see addAvailabilityListener
*/
- public interface CameraListener {
+ public static abstract class AvailabilityListener {
+
/**
* A new camera has become available to use.
*
+ * <p>The default implementation of this method does nothing.</p>
+ *
* @param cameraId The unique identifier of the new camera.
*/
- public void onCameraAvailable(String cameraId);
+ public void onCameraAvailable(String cameraId) {
+ // default empty implementation
+ }
/**
- * A previously-available camera has become unavailable for use. If an
- * application had an active CameraDevice instance for the
- * now-disconnected camera, that application will receive a {@link
- * CameraDevice.ErrorListener#DEVICE_DISCONNECTED disconnection error}.
+ * A previously-available camera has become unavailable for use.
+ *
+ * <p>If an application had an active CameraDevice instance for the
+ * now-disconnected camera, that application will receive a
+ * {@link CameraDevice.CameraDeviceListener#onCameraDisconnected disconnection error}.</p>
+ *
+ * <p>The default implementation of this method does nothing.</p>
*
* @param cameraId The unique identifier of the disconnected camera.
*/
- public void onCameraUnavailable(String cameraId);
+ public void onCameraUnavailable(String cameraId) {
+ // default empty implementation
+ }
}
private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException {
@@ -285,7 +318,7 @@
public static final int STATUS_NOT_AVAILABLE = 0x80000000;
// Camera ID -> Status map
- private final HashMap<String, Integer> mDeviceStatus = new HashMap<String, Integer>();
+ private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>();
private static final String TAG = "CameraServiceListener";
@@ -322,7 +355,7 @@
Log.v(TAG,
String.format("Camera id %d has status changed to 0x%x", cameraId, status));
- String id = String.valueOf(cameraId);
+ final String id = String.valueOf(cameraId);
if (!validStatus(status)) {
Log.e(TAG, String.format("Ignoring invalid device %d status 0x%x", cameraId,
@@ -332,7 +365,7 @@
Integer oldStatus = mDeviceStatus.put(id, status);
- if (oldStatus == status) {
+ if (oldStatus != null && oldStatus == status) {
Log.v(TAG, String.format(
"Device status changed to 0x%x, which is what it already was",
status));
@@ -363,11 +396,24 @@
return;
}
- for (CameraListener listener : mListenerSet) {
+ final int listenerCount = mListenerMap.size();
+ for (int i = 0; i < listenerCount; i++) {
+ Handler handler = mListenerMap.valueAt(i);
+ final AvailabilityListener listener = mListenerMap.keyAt(i);
if (isAvailable(status)) {
- listener.onCameraAvailable(id);
+ handler.post(
+ new Runnable() {
+ public void run() {
+ listener.onCameraAvailable(id);
+ }
+ });
} else {
- listener.onCameraUnavailable(id);
+ handler.post(
+ new Runnable() {
+ public void run() {
+ listener.onCameraUnavailable(id);
+ }
+ });
}
} // for
} // synchronized
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 70d777f..7f4ba4f 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -16,427 +16,103 @@
package android.hardware.camera2;
-import android.hardware.camera2.impl.MetadataMarshalClass;
-import android.hardware.camera2.impl.MetadataMarshalRect;
-import android.hardware.camera2.impl.MetadataMarshalSize;
-import android.hardware.camera2.impl.MetadataMarshalString;
-import android.os.Parcelable;
-import android.os.Parcel;
-import android.util.Log;
+import android.hardware.camera2.impl.CameraMetadataNative;
-import java.lang.reflect.Array;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
+import java.lang.reflect.Field;
import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Collections;
+import java.util.List;
/**
* The base class for camera controls and information.
*
+ * <p>
* This class defines the basic key/value map used for querying for camera
* characteristics or capture results, and for setting camera request
* parameters.
+ * </p>
+ *
+ * <p>
+ * All instances of CameraMetadata are immutable. The list of keys with {@link #getKeys()}
+ * never changes, nor do the values returned by any key with {@link #get} throughout
+ * the lifetime of the object.
+ * </p>
*
* @see CameraDevice
* @see CameraManager
* @see CameraProperties
**/
-public class CameraMetadata implements Parcelable, AutoCloseable {
-
- public CameraMetadata() {
- mMetadataMap = new HashMap<Key<?>, Object>();
-
- mMetadataPtr = nativeAllocate();
- if (mMetadataPtr == 0) {
- throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
- }
- }
-
- public static final Parcelable.Creator<CameraMetadata> CREATOR =
- new Parcelable.Creator<CameraMetadata>() {
- @Override
- public CameraMetadata createFromParcel(Parcel in) {
- CameraMetadata metadata = new CameraMetadata();
- metadata.readFromParcel(in);
- return metadata;
- }
-
- @Override
- public CameraMetadata[] newArray(int size) {
- return new CameraMetadata[size];
- }
- };
-
- private static final String TAG = "CameraMetadataJV";
+public abstract class CameraMetadata {
/**
- * Set a camera metadata field to a value. The field definitions can be
- * found in {@link CameraProperties}, {@link CaptureResult}, and
- * {@link CaptureRequest}.
- *
- * @param key The metadata field to write.
- * @param value The value to set the field to, which must be of a matching
- * type to the key.
+ * @hide
*/
- public <T> void set(Key<T> key, T value) {
- int tag = key.getTag();
-
- if (value == null) {
- writeValues(tag, null);
- return;
- }
-
- int nativeType = getNativeType(tag);
-
- int size = packSingle(value, null, key.mType, nativeType, /* sizeOnly */true);
-
- // TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
- byte[] values = new byte[size];
-
- ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
- packSingle(value, buffer, key.mType, nativeType, /*sizeOnly*/false);
-
- writeValues(tag, values);
+ protected CameraMetadata() {
}
/**
- * Get a camera metadata field value. The field definitions can be
+ * Get a camera metadata field value.
+ *
+ * <p>The field definitions can be
* found in {@link CameraProperties}, {@link CaptureResult}, and
- * {@link CaptureRequest}.
+ * {@link CaptureRequest}.</p>
+ *
+ * <p>Querying the value for the same key more than once will return a value
+ * which is equal to the previous queried value.</p>
*
* @throws IllegalArgumentException if the key was not valid
*
* @param key The metadata field to read.
* @return The value of that key, or {@code null} if the field is not set.
*/
- @SuppressWarnings("unchecked")
- public <T> T get(Key<T> key) {
- int tag = key.getTag();
- byte[] values = readValues(tag);
- if (values == null) {
- return null;
- }
+ public abstract <T> T get(Key<T> key);
- int nativeType = getNativeType(tag);
-
- ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
- return unpackSingle(buffer, key.mType, nativeType);
+ /**
+ * Returns a list of the keys contained in this map.
+ *
+ * <p>The list returned is not modifiable, so any attempts to modify it will throw
+ * a {@code UnsupportedOperationException}.</p>
+ *
+ * <p>All values retrieved by a key from this list with {@link #get} are guaranteed to be
+ * non-{@code null}. Each key is only listed once in the list. The order of the keys
+ * is undefined.</p>
+ *
+ * @return List of the keys contained in this map.
+ */
+ public List<Key<?>> getKeys() {
+ return Collections.unmodifiableList(getKeysStatic(this.getClass(), this));
}
- // Keep up-to-date with camera_metadata.h
/**
- * @hide
+ * Return a list of all the Key<?> that are declared as a field inside of the class
+ * {@code type}.
+ *
+ * <p>
+ * Optionally, if {@code instance} is not null, then filter out any keys with null values.
+ * </p>
*/
- public static final int TYPE_BYTE = 0;
- /**
- * @hide
- */
- public static final int TYPE_INT32 = 1;
- /**
- * @hide
- */
- public static final int TYPE_FLOAT = 2;
- /**
- * @hide
- */
- public static final int TYPE_INT64 = 3;
- /**
- * @hide
- */
- public static final int TYPE_DOUBLE = 4;
- /**
- * @hide
- */
- public static final int TYPE_RATIONAL = 5;
- /**
- * @hide
- */
- public static final int NUM_TYPES = 6;
+ /*package*/ static ArrayList<Key<?>> getKeysStatic(Class<? extends CameraMetadata> type,
+ CameraMetadata instance) {
+ ArrayList<Key<?>> keyList = new ArrayList<Key<?>>();
- private static int getTypeSize(int nativeType) {
- switch(nativeType) {
- case TYPE_BYTE:
- return 1;
- case TYPE_INT32:
- case TYPE_FLOAT:
- return 4;
- case TYPE_INT64:
- case TYPE_DOUBLE:
- case TYPE_RATIONAL:
- return 8;
- }
-
- throw new UnsupportedOperationException("Unknown type, can't get size "
- + nativeType);
- }
-
- private static Class<?> getExpectedType(int nativeType) {
- switch(nativeType) {
- case TYPE_BYTE:
- return Byte.TYPE;
- case TYPE_INT32:
- return Integer.TYPE;
- case TYPE_FLOAT:
- return Float.TYPE;
- case TYPE_INT64:
- return Long.TYPE;
- case TYPE_DOUBLE:
- return Double.TYPE;
- case TYPE_RATIONAL:
- return Rational.class;
- }
-
- throw new UnsupportedOperationException("Unknown type, can't map to Java type "
- + nativeType);
- }
-
- @SuppressWarnings("unchecked")
- private static <T> int packSingleNative(T value, ByteBuffer buffer, Class<T> type,
- int nativeType, boolean sizeOnly) {
-
- if (!sizeOnly) {
- /**
- * Rewrite types when the native type doesn't match the managed type
- * - Boolean -> Byte
- * - Integer -> Byte
- */
-
- if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
- // Since a boolean can't be cast to byte, and we don't want to use putBoolean
- boolean asBool = (Boolean) value;
- byte asByte = (byte) (asBool ? 1 : 0);
- value = (T) (Byte) asByte;
- } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
- int asInt = (Integer) value;
- byte asByte = (byte) asInt;
- value = (T) (Byte) asByte;
- } else if (type != getExpectedType(nativeType)) {
- throw new UnsupportedOperationException("Tried to pack a type of " + type +
- " but we expected the type to be " + getExpectedType(nativeType));
+ Field[] fields = type.getDeclaredFields();
+ for (Field field : fields) {
+ if (field.getDeclaringClass().isAssignableFrom(Key.class)) {
+ Key<?> key;
+ try {
+ key = (Key<?>) field.get(instance);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("Can't get IllegalAccessException", e);
+ } catch (IllegalArgumentException e) {
+ throw new AssertionError("Can't get IllegalArgumentException", e);
+ }
+ if (instance == null || instance.get(key) != null) {
+ keyList.add(key);
+ }
}
-
- if (nativeType == TYPE_BYTE) {
- buffer.put((Byte) value);
- } else if (nativeType == TYPE_INT32) {
- buffer.putInt((Integer) value);
- } else if (nativeType == TYPE_FLOAT) {
- buffer.putFloat((Float) value);
- } else if (nativeType == TYPE_INT64) {
- buffer.putLong((Long) value);
- } else if (nativeType == TYPE_DOUBLE) {
- buffer.putDouble((Double) value);
- } else if (nativeType == TYPE_RATIONAL) {
- Rational r = (Rational) value;
- buffer.putInt(r.getNumerator());
- buffer.putInt(r.getDenominator());
- }
-
}
- return getTypeSize(nativeType);
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- private static <T> int packSingle(T value, ByteBuffer buffer, Class<T> type, int nativeType,
- boolean sizeOnly) {
-
- int size = 0;
-
- if (type.isPrimitive() || type == Rational.class) {
- size = packSingleNative(value, buffer, type, nativeType, sizeOnly);
- } else if (type.isEnum()) {
- size = packEnum((Enum)value, buffer, (Class<Enum>)type, nativeType, sizeOnly);
- } else if (type.isArray()) {
- size = packArray(value, buffer, type, nativeType, sizeOnly);
- } else {
- size = packClass(value, buffer, type, nativeType, sizeOnly);
- }
-
- return size;
- }
-
- private static <T extends Enum<T>> int packEnum(T value, ByteBuffer buffer, Class<T> type,
- int nativeType, boolean sizeOnly) {
-
- // TODO: add support for enums with their own values.
- return packSingleNative(getEnumValue(value), buffer, Integer.TYPE, nativeType, sizeOnly);
- }
-
- @SuppressWarnings("unchecked")
- private static <T> int packClass(T value, ByteBuffer buffer, Class<T> type, int nativeType,
- boolean sizeOnly) {
-
- MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
- if (marshaler == null) {
- throw new IllegalArgumentException(String.format("Unknown Key type: %s", type));
- }
-
- return marshaler.marshal(value, buffer, nativeType, sizeOnly);
- }
-
- private static <T> int packArray(T value, ByteBuffer buffer, Class<T> type, int nativeType,
- boolean sizeOnly) {
-
- int size = 0;
- int arrayLength = Array.getLength(value);
-
- @SuppressWarnings("unchecked")
- Class<Object> componentType = (Class<Object>)type.getComponentType();
-
- for (int i = 0; i < arrayLength; ++i) {
- size += packSingle(Array.get(value, i), buffer, componentType, nativeType, sizeOnly);
- }
-
- return size;
- }
-
- @SuppressWarnings("unchecked")
- private static <T> T unpackSingleNative(ByteBuffer buffer, Class<T> type, int nativeType) {
-
- T val;
-
- if (nativeType == TYPE_BYTE) {
- val = (T) (Byte) buffer.get();
- } else if (nativeType == TYPE_INT32) {
- val = (T) (Integer) buffer.getInt();
- } else if (nativeType == TYPE_FLOAT) {
- val = (T) (Float) buffer.getFloat();
- } else if (nativeType == TYPE_INT64) {
- val = (T) (Long) buffer.getLong();
- } else if (nativeType == TYPE_DOUBLE) {
- val = (T) (Double) buffer.getDouble();
- } else if (nativeType == TYPE_RATIONAL) {
- val = (T) new Rational(buffer.getInt(), buffer.getInt());
- } else {
- throw new UnsupportedOperationException("Unknown type, can't unpack a native type "
- + nativeType);
- }
-
- /**
- * Rewrite types when the native type doesn't match the managed type
- * - Byte -> Boolean
- * - Byte -> Integer
- */
-
- if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
- // Since a boolean can't be cast to byte, and we don't want to use getBoolean
- byte asByte = (Byte) val;
- boolean asBool = asByte != 0;
- val = (T) (Boolean) asBool;
- } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
- byte asByte = (Byte) val;
- int asInt = asByte;
- val = (T) (Integer) asInt;
- } else if (type != getExpectedType(nativeType)) {
- throw new UnsupportedOperationException("Tried to unpack a type of " + type +
- " but we expected the type to be " + getExpectedType(nativeType));
- }
-
- return val;
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- private static <T> T unpackSingle(ByteBuffer buffer, Class<T> type, int nativeType) {
-
- if (type.isPrimitive() || type == Rational.class) {
- return unpackSingleNative(buffer, type, nativeType);
- }
-
- if (type.isEnum()) {
- return (T) unpackEnum(buffer, (Class<Enum>)type, nativeType);
- }
-
- if (type.isArray()) {
- return unpackArray(buffer, type, nativeType);
- }
-
- T instance = unpackClass(buffer, type, nativeType);
-
- return instance;
- }
-
- private static <T extends Enum<T>> T unpackEnum(ByteBuffer buffer, Class<T> type,
- int nativeType) {
- int ordinal = unpackSingleNative(buffer, Integer.TYPE, nativeType);
- return getEnumFromValue(type, ordinal);
- }
-
- private static <T> T unpackClass(ByteBuffer buffer, Class<T> type, int nativeType) {
-
- MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
- if (marshaler == null) {
- throw new IllegalArgumentException("Unknown class type: " + type);
- }
-
- return marshaler.unmarshal(buffer, nativeType);
- }
-
- @SuppressWarnings("unchecked")
- private static <T> T unpackArray(ByteBuffer buffer, Class<T> type, int nativeType) {
-
- Class<?> componentType = type.getComponentType();
- Object array;
-
- int elementSize = getTypeSize(nativeType);
-
- MetadataMarshalClass<?> marshaler = getMarshaler(componentType, nativeType);
- if (marshaler != null) {
- elementSize = marshaler.getNativeSize(nativeType);
- }
-
- if (elementSize != MetadataMarshalClass.NATIVE_SIZE_DYNAMIC) {
- int remaining = buffer.remaining();
- int arraySize = remaining / elementSize;
-
- Log.v(TAG,
- String.format(
- "Attempting to unpack array (count = %d, element size = %d, bytes " +
- "remaining = %d) for type %s",
- arraySize, elementSize, remaining, type));
-
- array = Array.newInstance(componentType, arraySize);
- for (int i = 0; i < arraySize; ++i) {
- Object elem = unpackSingle(buffer, componentType, nativeType);
- Array.set(array, i, elem);
- }
- } else {
- // Dynamic size, use an array list.
- ArrayList<Object> arrayList = new ArrayList<Object>();
-
- int primitiveSize = getTypeSize(nativeType);
- while (buffer.remaining() >= primitiveSize) {
- Object elem = unpackSingle(buffer, componentType, nativeType);
- arrayList.add(elem);
- }
-
- array = arrayList.toArray((T[]) Array.newInstance(componentType, 0));
- }
-
- if (buffer.remaining() != 0) {
- Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
- + type);
- }
-
- return (T) array;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- nativeWriteToParcel(dest);
- }
-
- /**
- * Expand this object from a Parcel.
- * @param in The Parcel from which the object should be read
- */
- public void readFromParcel(Parcel in) {
- nativeReadFromParcel(in);
+ return keyList;
}
public static class Key<T> {
@@ -444,8 +120,9 @@
private boolean mHasTag;
private int mTag;
private final Class<T> mType;
+ private final String mName;
- /*
+ /**
* @hide
*/
public Key(String name, Class<T> type) {
@@ -483,8 +160,6 @@
return mName.equals(lhs.mName);
}
- private final String mName;
-
/**
* <p>
* Get the tag corresponding to this key. This enables insertion into the
@@ -499,267 +174,20 @@
*/
public final int getTag() {
if (!mHasTag) {
- mTag = CameraMetadata.getTag(mName);
+ mTag = CameraMetadataNative.getTag(mName);
mHasTag = true;
}
return mTag;
}
- }
- private final Map<Key<?>, Object> mMetadataMap;
-
- private long mMetadataPtr; // native CameraMetadata*
-
- private native long nativeAllocate();
- private native synchronized void nativeWriteToParcel(Parcel dest);
- private native synchronized void nativeReadFromParcel(Parcel source);
- private native synchronized void nativeSwap(CameraMetadata other) throws NullPointerException;
- private native synchronized void nativeClose();
- private native synchronized boolean nativeIsEmpty();
- private native synchronized int nativeGetEntryCount();
-
- private native synchronized byte[] nativeReadValues(int tag);
- private native synchronized void nativeWriteValues(int tag, byte[] src);
-
- private static native int nativeGetTagFromKey(String keyName)
- throws IllegalArgumentException;
- private static native int nativeGetTypeFromTag(int tag)
- throws IllegalArgumentException;
- private static native void nativeClassInit();
-
- /**
- * <p>Perform a 0-copy swap of the internal metadata with another object.</p>
- *
- * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p>
- *
- * @param other Metadata to swap with
- * @throws NullPointerException if other was null
- * @hide
- */
- public void swap(CameraMetadata other) {
- nativeSwap(other);
- }
-
- /**
- * @hide
- */
- public int getEntryCount() {
- return nativeGetEntryCount();
- }
-
- /**
- * Does this metadata contain at least 1 entry?
- *
- * @hide
- */
- public boolean isEmpty() {
- return nativeIsEmpty();
- }
-
- /**
- * <p>Closes this object, and releases all native resources associated with it.</p>
- *
- * <p>Calling any other public method after this will result in an IllegalStateException
- * being thrown.</p>
- */
- @Override
- public void close() throws Exception {
- // this sets mMetadataPtr to 0
- nativeClose();
- mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
- }
-
- /**
- * Whether or not {@link #close} has already been called (at least once) on this object.
- * @hide
- */
- public boolean isClosed() {
- synchronized (this) {
- return mMetadataPtr == 0;
+ /**
+ * @hide
+ */
+ public final Class<T> getType() {
+ return mType;
}
}
- /**
- * Convert a key string into the equivalent native tag.
- *
- * @throws IllegalArgumentException if the key was not recognized
- * @throws NullPointerException if the key was null
- *
- * @hide
- */
- public static int getTag(String key) {
- return nativeGetTagFromKey(key);
- }
-
- /**
- * Get the underlying native type for a tag.
- *
- * @param tag An integer tag, see e.g. {@link #getTag}
- * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE}
- *
- * @hide
- */
- public static int getNativeType(int tag) {
- return nativeGetTypeFromTag(tag);
- }
-
- /**
- * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing
- * the entry if src was null.</p>
- *
- * <p>An empty array can be passed in to update the entry to 0 elements.</p>
- *
- * @param tag An integer tag, see e.g. {@link #getTag}
- * @param src An array of bytes, or null to erase the entry
- *
- * @hide
- */
- public void writeValues(int tag, byte[] src) {
- nativeWriteValues(tag, src);
- }
-
- /**
- * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize
- * the data properly.</p>
- *
- * <p>An empty array can be returned to denote an existing entry with 0 elements.</p>
- *
- * @param tag An integer tag, see e.g. {@link #getTag}
- *
- * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise.
- * @hide
- */
- public byte[] readValues(int tag) {
- // TODO: Optimization. Native code returns a ByteBuffer instead.
- return nativeReadValues(tag);
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- close();
- } finally {
- super.finalize();
- }
- }
-
- private static final HashMap<Class<? extends Enum>, int[]> sEnumValues =
- new HashMap<Class<? extends Enum>, int[]>();
- /**
- * Register a non-sequential set of values to be used with the pack/unpack functions.
- * This enables get/set to correctly marshal the enum into a value that is C-compatible.
- *
- * @param enumType The class for an enum
- * @param values A list of values mapping to the ordinals of the enum
- *
- * @hide
- */
- public static <T extends Enum<T>> void registerEnumValues(Class<T> enumType, int[] values) {
- if (enumType.getEnumConstants().length != values.length) {
- throw new IllegalArgumentException(
- "Expected values array to be the same size as the enumTypes values "
- + values.length + " for type " + enumType);
- }
-
- Log.v(TAG, "Registered enum values for type " + enumType + " values");
-
- sEnumValues.put(enumType, values);
- }
-
- /**
- * Get the numeric value from an enum. This is usually the same as the ordinal value for
- * enums that have fully sequential values, although for C-style enums the range of values
- * may not map 1:1.
- *
- * @param enumValue Enum instance
- * @return Int guaranteed to be ABI-compatible with the C enum equivalent
- */
- private static <T extends Enum<T>> int getEnumValue(T enumValue) {
- int[] values;
- values = sEnumValues.get(enumValue.getClass());
-
- int ordinal = enumValue.ordinal();
- if (values != null) {
- return values[ordinal];
- }
-
- return ordinal;
- }
-
- /**
- * Finds the enum corresponding to it's numeric value. Opposite of {@link #getEnumValue} method.
- *
- * @param enumType Class of the enum we want to find
- * @param value The numeric value of the enum
- * @return An instance of the enum
- */
- private static <T extends Enum<T>> T getEnumFromValue(Class<T> enumType, int value) {
- int ordinal;
-
- int[] registeredValues = sEnumValues.get(enumType);
- if (registeredValues != null) {
- ordinal = -1;
-
- for (int i = 0; i < registeredValues.length; ++i) {
- if (registeredValues[i] == value) {
- ordinal = i;
- break;
- }
- }
- } else {
- ordinal = value;
- }
-
- T[] values = enumType.getEnumConstants();
-
- if (ordinal < 0 || ordinal >= values.length) {
- throw new IllegalArgumentException(
- String.format(
- "Argument 'value' (%d) was not a valid enum value for type %s "
- + "(registered? %b)",
- value,
- enumType, (registeredValues != null)));
- }
-
- return values[ordinal];
- }
-
- static HashMap<Class<?>, MetadataMarshalClass<?>> sMarshalerMap = new
- HashMap<Class<?>, MetadataMarshalClass<?>>();
-
- private static <T> void registerMarshaler(MetadataMarshalClass<T> marshaler) {
- sMarshalerMap.put(marshaler.getMarshalingClass(), marshaler);
- }
-
- @SuppressWarnings("unchecked")
- private static <T> MetadataMarshalClass<T> getMarshaler(Class<T> type, int nativeType) {
- MetadataMarshalClass<T> marshaler = (MetadataMarshalClass<T>) sMarshalerMap.get(type);
-
- if (marshaler != null && !marshaler.isNativeTypeSupported(nativeType)) {
- throw new UnsupportedOperationException("Unsupported type " + nativeType +
- " to be marshalled to/from a " + type);
- }
-
- return marshaler;
- }
-
- /**
- * We use a class initializer to allow the native code to cache some field offsets
- */
- static {
- System.loadLibrary("media_jni");
- nativeClassInit();
-
- Log.v(TAG, "Shall register metadata marshalers");
-
- // load built-in marshallers
- registerMarshaler(new MetadataMarshalRect());
- registerMarshaler(new MetadataMarshalSize());
- registerMarshaler(new MetadataMarshalString());
-
- Log.v(TAG, "Registered metadata marshalers");
- }
-
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* The enum values below this point are generated from metadata
* definitions in /system/media/camera/docs. Do not modify by hand or
@@ -1512,6 +940,20 @@
public static final int STATISTICS_FACE_DETECT_MODE_FULL = 2;
//
+ // Enumeration values for CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
+ //
+
+ /**
+ * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
+ */
+ public static final int STATISTICS_LENS_SHADING_MAP_MODE_OFF = 0;
+
+ /**
+ * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
+ */
+ public static final int STATISTICS_LENS_SHADING_MAP_MODE_ON = 1;
+
+ //
// Enumeration values for CaptureRequest#TONEMAP_MODE
//
@@ -1757,6 +1199,11 @@
*/
public static final int LENS_STATE_STATIONARY = 0;
+ /**
+ * @see CaptureResult#LENS_STATE
+ */
+ public static final int LENS_STATE_MOVING = 1;
+
//
// Enumeration values for CaptureResult#STATISTICS_SCENE_FLICKER
//
diff --git a/core/java/android/hardware/camera2/CameraProperties.java b/core/java/android/hardware/camera2/CameraProperties.java
index ebbdd88..58a1ee3 100644
--- a/core/java/android/hardware/camera2/CameraProperties.java
+++ b/core/java/android/hardware/camera2/CameraProperties.java
@@ -16,6 +16,11 @@
package android.hardware.camera2;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+import java.util.Collections;
+import java.util.List;
+
/**
* <p>The properties describing a
* {@link CameraDevice CameraDevice}.</p>
@@ -29,6 +34,92 @@
*/
public final class CameraProperties extends CameraMetadata {
+ private final CameraMetadataNative mProperties;
+ private List<Key<?>> mAvailableRequestKeys;
+ private List<Key<?>> mAvailableResultKeys;
+
+ /**
+ * Takes ownership of the passed-in properties object
+ * @hide
+ */
+ public CameraProperties(CameraMetadataNative properties) {
+ mProperties = properties;
+ }
+
+ @Override
+ public <T> T get(Key<T> key) {
+ return mProperties.get(key);
+ }
+
+ /**
+ * Returns the list of keys supported by this {@link CameraDevice} for querying
+ * with a {@link CaptureRequest}.
+ *
+ * <p>The list returned is not modifiable, so any attempts to modify it will throw
+ * a {@code UnsupportedOperationException}.</p>
+ *
+ * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+ *
+ * <p>Note that there is no {@code getAvailableCameraPropertiesKeys()} -- use
+ * {@link #getKeys()} instead.</p>
+ *
+ * @return List of keys supported by this CameraDevice for CaptureRequests.
+ */
+ public List<Key<?>> getAvailableCaptureRequestKeys() {
+ if (mAvailableRequestKeys == null) {
+ mAvailableRequestKeys = getAvailableKeyList(CaptureRequest.class);
+ }
+ return mAvailableRequestKeys;
+ }
+
+ /**
+ * Returns the list of keys supported by this {@link CameraDevice} for querying
+ * with a {@link CaptureResult}.
+ *
+ * <p>The list returned is not modifiable, so any attempts to modify it will throw
+ * a {@code UnsupportedOperationException}.</p>
+ *
+ * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+ *
+ * <p>Note that there is no {@code getAvailableCameraPropertiesKeys()} -- use
+ * {@link #getKeys()} instead.</p>
+ *
+ * @return List of keys supported by this CameraDevice for CaptureResults.
+ */
+ public List<Key<?>> getAvailableCaptureResultKeys() {
+ if (mAvailableResultKeys == null) {
+ mAvailableResultKeys = getAvailableKeyList(CaptureResult.class);
+ }
+ return mAvailableResultKeys;
+ }
+
+ /**
+ * Returns the list of keys supported by this {@link CameraDevice} by metadataClass.
+ *
+ * <p>The list returned is not modifiable, so any attempts to modify it will throw
+ * a {@code UnsupportedOperationException}.</p>
+ *
+ * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+ *
+ * @param metadataClass The subclass of CameraMetadata that you want to get the keys for.
+ *
+ * @return List of keys supported by this CameraDevice for metadataClass.
+ *
+ * @throws IllegalArgumentException if metadataClass is not a subclass of CameraMetadata
+ */
+ private <T extends CameraMetadata> List<Key<?>> getAvailableKeyList(Class<T> metadataClass) {
+
+ if (metadataClass.equals(CameraMetadata.class)) {
+ throw new AssertionError(
+ "metadataClass must be a strict subclass of CameraMetadata");
+ } else if (!CameraMetadata.class.isAssignableFrom(metadataClass)) {
+ throw new AssertionError(
+ "metadataClass must be a subclass of CameraMetadata");
+ }
+
+ return Collections.unmodifiableList(getKeysStatic(metadataClass, /*instance*/null));
+ }
+
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* The key entries below this point are generated from metadata
* definitions in /system/media/camera/docs. Do not modify by hand or
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 7735146a..3ec5ca0 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -16,6 +16,7 @@
package android.hardware.camera2;
+import android.hardware.camera2.impl.CameraMetadataNative;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.Surface;
@@ -24,13 +25,16 @@
/**
- * <p>All the settings required to capture a single image from the image sensor.</p>
+ * <p>An immutable package of settings and outputs needed to capture a single
+ * image from the camera device.</p>
*
* <p>Contains the configuration for the capture hardware (sensor, lens, flash),
- * the processing pipeline, the control algorithms, and the output buffers.</p>
+ * the processing pipeline, the control algorithms, and the output buffers. Also
+ * contains the list of target Surfaces to send image data to for this
+ * capture.</p>
*
- * <p>CaptureRequests can be created by calling
- * {@link CameraDevice#createCaptureRequest}</p>
+ * <p>CaptureRequests can be created by using a {@link Builder} instance,
+ * obtained by calling {@link CameraDevice#createCaptureRequest}</p>
*
* <p>CaptureRequests are given to {@link CameraDevice#capture} or
* {@link CameraDevice#setRepeatingRequest} to capture images from a camera.</p>
@@ -38,7 +42,8 @@
* <p>Each request can specify a different subset of target Surfaces for the
* camera to send the captured data to. All the surfaces used in a request must
* be part of the surface list given to the last call to
- * {@link CameraDevice#configureOutputs}.</p>
+ * {@link CameraDevice#configureOutputs}, when the request is submitted to the
+ * camera device.</p>
*
* <p>For example, a request meant for repeating preview might only include the
* Surface for the preview SurfaceView or SurfaceTexture, while a
@@ -47,64 +52,43 @@
*
* @see CameraDevice#capture
* @see CameraDevice#setRepeatingRequest
- * @see CameraDevice#createRequest
+ * @see CameraDevice#createCaptureRequest
*/
public final class CaptureRequest extends CameraMetadata implements Parcelable {
- private final Object mLock = new Object();
- private final HashSet<Surface> mSurfaceSet = new HashSet<Surface>();
+ private final HashSet<Surface> mSurfaceSet;
+ private final CameraMetadataNative mSettings;
+
private Object mUserTag;
/**
+ * Construct empty request
* @hide
*/
public CaptureRequest() {
+ mSettings = new CameraMetadataNative();
+ mSurfaceSet = new HashSet<Surface>();
}
/**
- * <p>Add a surface to the list of targets for this request</p>
- *
- * <p>The Surface added must be one of the surfaces included in the last
- * call to {@link CameraDevice#configureOutputs}.</p>
- *
- * <p>Adding a target more than once has no effect.</p>
- *
- * @param outputTarget Surface to use as an output target for this request
+ * Clone from source capture request
*/
- public void addTarget(Surface outputTarget) {
- synchronized (mLock) {
- mSurfaceSet.add(outputTarget);
- }
+ private CaptureRequest(CaptureRequest source) {
+ mSettings = new CameraMetadataNative(source.mSettings);
+ mSurfaceSet = (HashSet<Surface>) source.mSurfaceSet.clone();
}
/**
- * <p>Remove a surface from the list of targets for this request.</p>
- *
- * <p>Removing a target that is not currently added has no effect.</p>
- *
- * @param outputTarget Surface to use as an output target for this request
+ * Take ownership of passed-in settings
*/
- public void removeTarget(Surface outputTarget) {
- synchronized (mLock) {
- mSurfaceSet.remove(outputTarget);
- }
+ private CaptureRequest(CameraMetadataNative settings) {
+ mSettings = settings;
+ mSurfaceSet = new HashSet<Surface>();
}
- /**
- * Set a tag for this request.
- *
- * <p>This tag is not used for anything by the camera device, but can be
- * used by an application to easily identify a CaptureRequest when it is
- * returned by
- * {@link CameraDevice.CaptureListener#onCaptureComplete CaptureListener.onCaptureComplete}
- *
- * @param tag an arbitrary Object to store with this request
- * @see #getTag
- */
- public void setTag(Object tag) {
- synchronized (mLock) {
- mUserTag = tag;
- }
+ @Override
+ public <T> T get(Key<T> key) {
+ return mSettings.get(key);
}
/**
@@ -113,17 +97,15 @@
* <p>This tag is not used for anything by the camera device, but can be
* used by an application to easily identify a CaptureRequest when it is
* returned by
- * {@link CameraDevice.CaptureListener#onCaptureComplete CaptureListener.onCaptureComplete}
+ * {@link CameraDevice.CaptureListener#onCaptureCompleted CaptureListener.onCaptureCompleted}
* </p>
*
* @return the last tag Object set on this request, or {@code null} if
* no tag has been set.
- * @see #setTag
+ * @see Builder#setTag
*/
public Object getTag() {
- synchronized (mLock) {
- return mUserTag;
- }
+ return mUserTag;
}
public static final Parcelable.Creator<CaptureRequest> CREATOR =
@@ -132,6 +114,7 @@
public CaptureRequest createFromParcel(Parcel in) {
CaptureRequest request = new CaptureRequest();
request.readFromParcel(in);
+
return request;
}
@@ -143,35 +126,152 @@
/**
* Expand this object from a Parcel.
+ * Hidden since this breaks the immutability of CaptureRequest, but is
+ * needed to receive CaptureRequests with aidl.
+ *
* @param in The parcel from which the object should be read
+ * @hide
*/
- @Override
public void readFromParcel(Parcel in) {
- synchronized (mLock) {
- super.readFromParcel(in);
+ mSettings.readFromParcel(in);
- mSurfaceSet.clear();
+ mSurfaceSet.clear();
- Parcelable[] parcelableArray = in.readParcelableArray(Surface.class.getClassLoader());
+ Parcelable[] parcelableArray = in.readParcelableArray(Surface.class.getClassLoader());
- if (parcelableArray == null) {
- return;
- }
+ if (parcelableArray == null) {
+ return;
+ }
- for (Parcelable p : parcelableArray) {
- Surface s = (Surface) p;
- mSurfaceSet.add(s);
- }
+ for (Parcelable p : parcelableArray) {
+ Surface s = (Surface) p;
+ mSurfaceSet.add(s);
}
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
- synchronized (mLock) {
- super.writeToParcel(dest, flags);
+ public int describeContents() {
+ return 0;
+ }
- dest.writeParcelableArray(mSurfaceSet.toArray(new Surface[mSurfaceSet.size()]), flags);
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ mSettings.writeToParcel(dest, flags);
+ dest.writeParcelableArray(mSurfaceSet.toArray(new Surface[mSurfaceSet.size()]), flags);
+ }
+
+ /**
+ * A builder for capture requests.
+ *
+ * <p>To obtain a builder instance, use the
+ * {@link CameraDevice#createCaptureRequest} method, which initializes the
+ * request fields to one of the templates defined in {@link CameraDevice}.
+ *
+ * @see CameraDevice#createCaptureRequest
+ * @see #TEMPLATE_PREVIEW
+ * @see #TEMPLATE_RECORD
+ * @see #TEMPLATE_STILL_CAPTURE
+ * @see #TEMPLATE_VIDEO_SNAPSHOT
+ * @see #TEMPLATE_MANUAL
+ */
+ public final static class Builder {
+
+ private final CaptureRequest mRequest;
+
+ /**
+ * Initialize the builder using the template; the request takes
+ * ownership of the template.
+ *
+ * @hide
+ */
+ public Builder(CameraMetadataNative template) {
+ mRequest = new CaptureRequest(template);
}
+
+ /**
+ * <p>Add a surface to the list of targets for this request</p>
+ *
+ * <p>The Surface added must be one of the surfaces included in the most
+ * recent call to {@link CameraDevice#configureOutputs}, when the
+ * request is given to the camera device.</p>
+ *
+ * <p>Adding a target more than once has no effect.</p>
+ *
+ * @param outputTarget Surface to use as an output target for this request
+ */
+ public void addTarget(Surface outputTarget) {
+ mRequest.mSurfaceSet.add(outputTarget);
+ }
+
+ /**
+ * <p>Remove a surface from the list of targets for this request.</p>
+ *
+ * <p>Removing a target that is not currently added has no effect.</p>
+ *
+ * @param outputTarget Surface to use as an output target for this request
+ */
+ public void removeTarget(Surface outputTarget) {
+ mRequest.mSurfaceSet.remove(outputTarget);
+ }
+
+ /**
+ * Set a capture request field to a value. The field definitions can be
+ * found in {@link CaptureRequest}.
+ *
+ * @param key The metadata field to write.
+ * @param value The value to set the field to, which must be of a matching
+ * type to the key.
+ */
+ public <T> void set(Key<T> key, T value) {
+ mRequest.mSettings.set(key, value);
+ }
+
+ /**
+ * Get a capture request field value. The field definitions can be
+ * found in {@link CaptureRequest}.
+ *
+ * @throws IllegalArgumentException if the key was not valid
+ *
+ * @param key The metadata field to read.
+ * @return The value of that key, or {@code null} if the field is not set.
+ */
+ public <T> T get(Key<T> key) {
+ return mRequest.mSettings.get(key);
+ }
+
+ /**
+ * Set a tag for this request.
+ *
+ * <p>This tag is not used for anything by the camera device, but can be
+ * used by an application to easily identify a CaptureRequest when it is
+ * returned by
+ * {@link CameraDevice.CaptureListener#onCaptureCompleted CaptureListener.onCaptureCompleted}
+ *
+ * @param tag an arbitrary Object to store with this request
+ * @see CaptureRequest#getTag
+ */
+ public void setTag(Object tag) {
+ mRequest.mUserTag = tag;
+ }
+
+ /**
+ * Build a request using the current target Surfaces and settings.
+ *
+ * @return A new capture request instance, ready for submission to the
+ * camera device.
+ */
+ public CaptureRequest build() {
+ return new CaptureRequest(mRequest);
+ }
+
+
+ /**
+ * @hide
+ */
+ public boolean isEmpty() {
+ return mRequest.mSettings.isEmpty();
+ }
+
}
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
@@ -857,6 +957,22 @@
/**
* <p>
+ * Whether the HAL needs to output the lens
+ * shading map in output result metadata
+ * </p>
+ * <p>
+ * When set to ON,
+ * android.statistics.lensShadingMap must be provided in
+ * the output result metdata.
+ * </p>
+ * @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
+ * @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
+ */
+ public static final Key<Integer> STATISTICS_LENS_SHADING_MAP_MODE =
+ new Key<Integer>("android.statistics.lensShadingMapMode", int.class);
+
+ /**
+ * <p>
* Table mapping blue input values to output
* values
* </p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index bd151a2..377e78a 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -18,6 +18,7 @@
import android.graphics.Point;
import android.graphics.Rect;
+import android.hardware.camera2.impl.CameraMetadataNative;
/**
* <p>The results of a single image capture from the image sensor.</p>
@@ -34,93 +35,20 @@
*
*/
public final class CaptureResult extends CameraMetadata {
+
+ private final CameraMetadataNative mResults;
+
/**
+ * Takes ownership of the passed-in properties object
* @hide
*/
- public CaptureResult() {
+ public CaptureResult(CameraMetadataNative results) {
+ mResults = results;
}
- /**
- * Describes a face detected in an image.
- */
- public static class Face {
-
- /**
- * <p>Bounds of the face. A rectangle relative to the sensor's
- * {@link CameraProperties#SENSOR_INFO_ACTIVE_ARRAY_SIZE}, with (0,0)
- * representing the top-left corner of the active array rectangle.</p>
- */
- public Rect getBounds() {
- return mBounds;
- }
-
- /** <p>The confidence level for the detection of the face. The range is 1 to
- * 100. 100 is the highest confidence.</p>
- *
- * <p>Depending on the device, even very low-confidence faces may be
- * listed, so applications should filter out faces with low confidence,
- * depending on the use case. For a typical point-and-shoot camera
- * application that wishes to display rectangles around detected faces,
- * filtering out faces with confidence less than 50 is recommended.</p>
- *
- */
- public int getScore() {
- return mScore;
- }
-
- /**
- * An unique id per face while the face is visible to the tracker. If
- * the face leaves the field-of-view and comes back, it will get a new
- * id. This is an optional field, may not be supported on all devices.
- * If not supported, id will always be set to -1. The optional fields
- * are supported as a set. Either they are all valid, or none of them
- * are.
- */
- public int getId() {
- return mId;
- }
-
- /**
- * The coordinates of the center of the left eye. The coordinates are in
- * the same space as the ones for {@link #getBounds}. This is an
- * optional field, may not be supported on all devices. If not
- * supported, the value will always be set to null. The optional fields
- * are supported as a set. Either they are all valid, or none of them
- * are.
- */
- public Point getLeftEye() {
- return mLeftEye;
- }
-
- /**
- * The coordinates of the center of the right eye. The coordinates are
- * in the same space as the ones for {@link #getBounds}.This is an
- * optional field, may not be supported on all devices. If not
- * supported, the value will always be set to null. The optional fields
- * are supported as a set. Either they are all valid, or none of them
- * are.
- */
- public Point getRightEye() {
- return mRightEye;
- }
-
- /**
- * The coordinates of the center of the mouth. The coordinates are in
- * the same space as the ones for {@link #getBounds}. This is an optional
- * field, may not be supported on all devices. If not supported, the
- * value will always be set to null. The optional fields are supported
- * as a set. Either they are all valid, or none of them are.
- */
- public Point getMouth() {
- return mMouth;
- }
-
- private Rect mBounds;
- private int mScore;
- private int mId;
- private Point mLeftEye;
- private Point mRightEye;
- private Point mMouth;
+ @Override
+ public <T> T get(Key<T> key) {
+ return mResults.get(key);
}
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
@@ -576,6 +504,7 @@
* Current lens status
* </p>
* @see #LENS_STATE_STATIONARY
+ * @see #LENS_STATE_MOVING
*/
public static final Key<Integer> LENS_STATE =
new Key<Integer>("android.lens.state", int.class);
@@ -991,4 +920,19 @@
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
+
+ /**
+ * <p>
+ * List of the {@link Face Faces} detected through camera face detection
+ * in this result.
+ * </p>
+ * <p>
+ * Only available if {@link #STATISTICS_FACE_DETECT_MODE} {@code !=}
+ * {@link CameraMetadata#STATISTICS_FACE_DETECT_MODE_OFF OFF}.
+ * </p>
+ *
+ * @see Face
+ */
+ public static final Key<Face[]> STATISTICS_FACES =
+ new Key<Face[]>("android.statistics.faces", Face[].class);
}
diff --git a/core/java/android/hardware/camera2/Face.java b/core/java/android/hardware/camera2/Face.java
new file mode 100644
index 0000000..6bfc535
--- /dev/null
+++ b/core/java/android/hardware/camera2/Face.java
@@ -0,0 +1,252 @@
+/*
+ * 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.hardware.camera2;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+
+/**
+ * Describes a face detected in an image.
+ */
+public final class Face {
+
+ /**
+ * The ID is {@code -1} when the optional set of fields is unsupported.
+ *
+ * @see Face#Face(Rect, int)
+ * @see #getId()
+ */
+ public static final int ID_UNSUPPORTED = -1;
+
+ /**
+ * The minimum possible value for the confidence level.
+ *
+ * @see #getScore()
+ */
+ public static final int SCORE_MIN = 1;
+
+ /**
+ * The maximum possible value for the confidence level.
+ *
+ * @see #getScore()
+ */
+ public static final int SCORE_MAX = 100;
+
+ private final Rect mBounds;
+ private final int mScore;
+ private final int mId;
+ private final Point mLeftEye;
+ private final Point mRightEye;
+ private final Point mMouth;
+
+ /**
+ * Create a new face with all fields set.
+ *
+ * <p>The id, leftEyePosition, rightEyePosition, and mouthPosition are considered optional.
+ * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and
+ * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition,
+ * rightEyePosition, and mouthPosition may be independently null or not-null.</p>
+ *
+ * @param bounds Bounds of the face.
+ * @param score Confidence level between {@value #SCORE_MIN}-{@value #SCORE_MAX}.
+ * @param id A unique ID per face visible to the tracker.
+ * @param leftEyePosition The position of the left eye.
+ * @param rightEyePosition The position of the right eye.
+ * @param mouthPosition The position of the mouth.
+ *
+ * @throws IllegalArgumentException
+ * if bounds is {@code null},
+ * or if the confidence is not in the range of
+ * {@value #SCORE_MIN}-{@value #SCORE_MAX},
+ * or if id is {@value #ID_UNSUPPORTED} and
+ * leftEyePosition/rightEyePosition/mouthPosition aren't all null,
+ * or else if id is negative.
+ *
+ * @hide
+ */
+ public Face(Rect bounds, int score, int id,
+ Point leftEyePosition, Point rightEyePosition, Point mouthPosition) {
+ checkNotNull("bounds", bounds);
+ if (score < SCORE_MIN || score > SCORE_MAX) {
+ throw new IllegalArgumentException("Confidence out of range");
+ } else if (id < 0 && id != ID_UNSUPPORTED) {
+ throw new IllegalArgumentException("Id out of range");
+ }
+ if (id == ID_UNSUPPORTED) {
+ checkNull("leftEyePosition", leftEyePosition);
+ checkNull("rightEyePosition", rightEyePosition);
+ checkNull("mouthPosition", mouthPosition);
+ }
+
+ mBounds = bounds;
+ mScore = score;
+ mId = id;
+ mLeftEye = leftEyePosition;
+ mRightEye = rightEyePosition;
+ mMouth = mouthPosition;
+ }
+
+ /**
+ * Create a new face without the optional fields.
+ *
+ * <p>The id, leftEyePosition, rightEyePosition, and mouthPosition are considered optional.
+ * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and
+ * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition,
+ * rightEyePosition, and mouthPosition may be independently null or not-null.</p>
+ *
+ * @param bounds Bounds of the face.
+ * @param score Confidence level between {@value #SCORE_MIN}-{@value #SCORE_MAX}.
+ *
+ * @throws IllegalArgumentException
+ * if bounds is {@code null},
+ * or if the confidence is not in the range of
+ * {@value #SCORE_MIN}-{@value #SCORE_MAX}.
+ *
+ * @hide
+ */
+ public Face(Rect bounds, int score) {
+ this(bounds, score, ID_UNSUPPORTED,
+ /*leftEyePosition*/null, /*rightEyePosition*/null, /*mouthPosition*/null);
+ }
+
+ /**
+ * Bounds of the face.
+ *
+ * <p>A rectangle relative to the sensor's
+ * {@link CameraProperties#SENSOR_INFO_ACTIVE_ARRAY_SIZE}, with (0,0)
+ * representing the top-left corner of the active array rectangle.</p>
+ *
+ * <p>There is no constraints on the the Rectangle value other than it
+ * is not-{@code null}.</p>
+ */
+ public Rect getBounds() {
+ return mBounds;
+ }
+
+ /**
+ * The confidence level for the detection of the face.
+ *
+ * <p>The range is {@value #SCORE_MIN} to {@value #SCORE_MAX}.
+ * {@value #SCORE_MAX} is the highest confidence.</p>
+ *
+ * <p>Depending on the device, even very low-confidence faces may be
+ * listed, so applications should filter out faces with low confidence,
+ * depending on the use case. For a typical point-and-shoot camera
+ * application that wishes to display rectangles around detected faces,
+ * filtering out faces with confidence less than half of {@value #SCORE_MAX}
+ * is recommended.</p>
+ *
+ * @see #SCORE_MAX
+ * @see #SCORE_MIN
+ */
+ public int getScore() {
+ return mScore;
+ }
+
+ /**
+ * An unique id per face while the face is visible to the tracker.
+ *
+ * <p>
+ * If the face leaves the field-of-view and comes back, it will get a new
+ * id.</p>
+ *
+ * <p>This is an optional field, may not be supported on all devices.
+ * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and
+ * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition,
+ * rightEyePosition, and mouthPosition may be independently null or not-null.</p>
+ *
+ * <p>This value will either be {@value #ID_UNSUPPORTED} or
+ * otherwise greater than {@code 0}.</p>
+ *
+ * @see #ID_UNSUPPORTED
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * The coordinates of the center of the left eye.
+ *
+ * <p>The coordinates are in
+ * the same space as the ones for {@link #getBounds}. This is an
+ * optional field, may not be supported on all devices. If not
+ * supported, the value will always be set to null.
+ * This value will always be null only if {@link #getId()} returns
+ * {@value #ID_UNSUPPORTED}.</p>
+ *
+ * @return The left eye position, or {@code null} if unknown.
+ */
+ public Point getLeftEyePosition() {
+ return mLeftEye;
+ }
+
+ /**
+ * The coordinates of the center of the right eye.
+ *
+ * <p>The coordinates are
+ * in the same space as the ones for {@link #getBounds}.This is an
+ * optional field, may not be supported on all devices. If not
+ * supported, the value will always be set to null.
+ * This value will always be null only if {@link #getId()} returns
+ * {@value #ID_UNSUPPORTED}.</p>
+ *
+ * @return The right eye position, or {@code null} if unknown.
+ */
+ public Point getRightEyePosition() {
+ return mRightEye;
+ }
+
+ /**
+ * The coordinates of the center of the mouth.
+ *
+ * <p>The coordinates are in
+ * the same space as the ones for {@link #getBounds}. This is an optional
+ * field, may not be supported on all devices. If not
+ * supported, the value will always be set to null.
+ * This value will always be null only if {@link #getId()} returns
+ * {@value #ID_UNSUPPORTED}.</p> them are.
+ * </p>
+ *
+ * @return The mouth position, or {@code null} if unknown.
+ */
+ public Point getMouthPosition() {
+ return mMouth;
+ }
+
+ /**
+ * Represent the Face as a string for debugging purposes.
+ */
+ @Override
+ public String toString() {
+ return String.format("{ bounds: %s, score: %s, id: %d, " +
+ "leftEyePosition: %s, rightEyePosition: %s, mouthPosition: %s }",
+ mBounds, mScore, mId, mLeftEye, mRightEye, mMouth);
+ }
+
+ private static void checkNotNull(String name, Object obj) {
+ if (obj == null) {
+ throw new IllegalArgumentException(name + " was required, but it was null");
+ }
+ }
+
+ private static void checkNull(String name, Object obj) {
+ if (obj != null) {
+ throw new IllegalArgumentException(name + " was required to be null, but it wasn't");
+ }
+ }
+}
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index 4172238..4054a92 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -16,7 +16,7 @@
package android.hardware.camera2;
-import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.impl.CameraMetadataNative;
/** @hide */
interface ICameraDeviceCallbacks
@@ -26,5 +26,5 @@
*/
oneway void notifyCallback(int msgType, int ext1, int ext2);
- oneway void onResultReceived(int frameId, in CameraMetadata result);
+ oneway void onResultReceived(int frameId, in CameraMetadataNative result);
}
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
index b1724de..1936963 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -17,7 +17,7 @@
package android.hardware.camera2;
import android.view.Surface;
-import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.CaptureRequest;
/** @hide */
@@ -40,9 +40,9 @@
// non-negative value is the stream ID. negative value is status_t
int createStream(int width, int height, int format, in Surface surface);
- int createDefaultRequest(int templateId, out CameraMetadata request);
+ int createDefaultRequest(int templateId, out CameraMetadataNative request);
- int getCameraInfo(out CameraMetadata info);
+ int getCameraInfo(out CameraMetadataNative info);
int waitUntilIdle();
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 86a073f..995555a 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -29,6 +29,8 @@
import android.hardware.camera2.utils.CameraRuntimeException;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.util.SparseArray;
import android.view.Surface;
@@ -40,7 +42,7 @@
import java.util.Stack;
/**
- * HAL2.1+ implementation of CameraDevice Use CameraManager#open to instantiate
+ * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
*/
public class CameraDevice implements android.hardware.camera2.CameraDevice {
@@ -53,10 +55,11 @@
private final Object mLock = new Object();
private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
- // XX: Make this a WeakReference<CaptureListener> ?
- // TODO: Convert to SparseIntArray
- private final HashMap<Integer, CaptureListenerHolder> mCaptureListenerMap =
- new HashMap<Integer, CaptureListenerHolder>();
+ private CameraDeviceListener mDeviceListener;
+ private Handler mDeviceHandler;
+
+ private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
+ new SparseArray<CaptureListenerHolder>();
private final Stack<Integer> mRepeatingRequestIdStack = new Stack<Integer>();
// Map stream IDs to Surfaces
@@ -80,10 +83,14 @@
}
@Override
+ public String getId() {
+ return mCameraId;
+ }
+
+ @Override
public CameraProperties getProperties() throws CameraAccessException {
- CameraProperties properties = new CameraProperties();
- CameraMetadata info = new CameraMetadata();
+ CameraMetadataNative info = new CameraMetadataNative();
try {
mRemoteDevice.getCameraInfo(/*out*/info);
@@ -94,7 +101,7 @@
return null;
}
- properties.swap(info);
+ CameraProperties properties = new CameraProperties(info);
return properties;
}
@@ -149,11 +156,11 @@
}
@Override
- public CaptureRequest createCaptureRequest(int templateType) throws CameraAccessException {
-
+ public CaptureRequest.Builder createCaptureRequest(int templateType)
+ throws CameraAccessException {
synchronized (mLock) {
- CameraMetadata templatedRequest = new CameraMetadata();
+ CameraMetadataNative templatedRequest = new CameraMetadataNative();
try {
mRemoteDevice.createDefaultRequest(templateType, /* out */templatedRequest);
@@ -164,23 +171,22 @@
return null;
}
- CaptureRequest request = new CaptureRequest();
- request.swap(templatedRequest);
+ CaptureRequest.Builder builder =
+ new CaptureRequest.Builder(templatedRequest);
- return request;
-
+ return builder;
}
}
@Override
- public void capture(CaptureRequest request, CaptureListener listener)
+ public void capture(CaptureRequest request, CaptureListener listener, Handler handler)
throws CameraAccessException {
- submitCaptureRequest(request, listener, /*streaming*/false);
+ submitCaptureRequest(request, listener, handler, /*streaming*/false);
}
@Override
- public void captureBurst(List<CaptureRequest> requests, CaptureListener listener)
- throws CameraAccessException {
+ public void captureBurst(List<CaptureRequest> requests, CaptureListener listener,
+ Handler handler) throws CameraAccessException {
if (requests.isEmpty()) {
Log.w(TAG, "Capture burst request list is empty, do nothing!");
return;
@@ -191,7 +197,18 @@
}
private void submitCaptureRequest(CaptureRequest request, CaptureListener listener,
- boolean repeating) throws CameraAccessException {
+ Handler handler, boolean repeating) throws CameraAccessException {
+
+ // Need a valid handler, or current thread needs to have a looper, if
+ // listener is valid
+ if (handler == null && listener != null) {
+ Looper looper = Looper.myLooper();
+ if (looper == null) {
+ throw new IllegalArgumentException(
+ "No handler given, and current thread has no looper!");
+ }
+ handler = new Handler(looper);
+ }
synchronized (mLock) {
@@ -205,9 +222,10 @@
// impossible
return;
}
-
- mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
- repeating));
+ if (listener != null) {
+ mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
+ handler, repeating));
+ }
if (repeating) {
mRepeatingRequestIdStack.add(requestId);
@@ -217,14 +235,14 @@
}
@Override
- public void setRepeatingRequest(CaptureRequest request, CaptureListener listener)
- throws CameraAccessException {
- submitCaptureRequest(request, listener, /*streaming*/true);
+ public void setRepeatingRequest(CaptureRequest request, CaptureListener listener,
+ Handler handler) throws CameraAccessException {
+ submitCaptureRequest(request, listener, handler, /*streaming*/true);
}
@Override
- public void setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener)
- throws CameraAccessException {
+ public void setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
+ Handler handler) throws CameraAccessException {
if (requests.isEmpty()) {
Log.w(TAG, "Set Repeating burst request list is empty, do nothing!");
return;
@@ -274,9 +292,11 @@
}
@Override
- public void setErrorListener(ErrorListener listener) {
- // TODO Auto-generated method stub
-
+ public void setDeviceListener(CameraDeviceListener listener, Handler handler) {
+ synchronized (mLock) {
+ mDeviceListener = listener;
+ mDeviceHandler = handler;
+ }
}
@Override
@@ -332,9 +352,16 @@
private final boolean mRepeating;
private final CaptureListener mListener;
private final CaptureRequest mRequest;
+ private final Handler mHandler;
- CaptureListenerHolder(CaptureListener listener, CaptureRequest request, boolean repeating) {
+ CaptureListenerHolder(CaptureListener listener, CaptureRequest request, Handler handler,
+ boolean repeating) {
+ if (listener == null || handler == null) {
+ throw new UnsupportedOperationException(
+ "Must have a valid handler and a valid listener");
+ }
mRepeating = repeating;
+ mHandler = handler;
mRequest = request;
mListener = listener;
}
@@ -350,6 +377,11 @@
public CaptureRequest getRequest() {
return mRequest;
}
+
+ public Handler getHandler() {
+ return mHandler;
+ }
+
}
// TODO: unit tests
@@ -370,11 +402,12 @@
}
@Override
- public void onResultReceived(int requestId, CameraMetadata result) throws RemoteException {
+ public void onResultReceived(int requestId, CameraMetadataNative result)
+ throws RemoteException {
if (DEBUG) {
Log.d(TAG, "Received result for id " + requestId);
}
- CaptureListenerHolder holder;
+ final CaptureListenerHolder holder;
synchronized (mLock) {
// TODO: move this whole map into this class to make it more testable,
@@ -393,18 +426,22 @@
}
}
+ // Check if we have a listener for this
if (holder == null) {
- Log.e(TAG, "Result had no listener holder associated with it, dropping result");
return;
}
- CaptureResult resultAsCapture = new CaptureResult();
- resultAsCapture.swap(result);
+ final CaptureResult resultAsCapture = new CaptureResult(result);
- if (holder.getListener() != null) {
- holder.getListener().onCaptureComplete(CameraDevice.this, holder.getRequest(),
- resultAsCapture);
- }
+ holder.getHandler().post(
+ new Runnable() {
+ public void run() {
+ holder.getListener().onCaptureCompleted(
+ CameraDevice.this,
+ holder.getRequest(),
+ resultAsCapture);
+ }
+ });
}
}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.aidl b/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl
similarity index 89%
rename from core/java/android/hardware/camera2/CameraMetadata.aidl
rename to core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl
index 71dd471..4a89129 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.aidl
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.hardware.camera2.impl;
/** @hide */
-parcelable CameraMetadata;
+parcelable CameraMetadataNative;
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
new file mode 100644
index 0000000..c13438a
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -0,0 +1,668 @@
+/*
+ * 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.hardware.camera2.impl;
+
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.Rational;
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.util.Log;
+
+import java.lang.reflect.Array;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Implementation of camera metadata marshal/unmarshal across Binder to
+ * the camera service
+ */
+public class CameraMetadataNative extends CameraMetadata implements Parcelable {
+
+ private static final String TAG = "CameraMetadataJV";
+
+ public CameraMetadataNative() {
+ super();
+ mMetadataPtr = nativeAllocate();
+ if (mMetadataPtr == 0) {
+ throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
+ }
+ }
+
+ /**
+ * Copy constructor - clone metadata
+ */
+ public CameraMetadataNative(CameraMetadataNative other) {
+ super();
+ mMetadataPtr = nativeAllocateCopy(other);
+ if (mMetadataPtr == 0) {
+ throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
+ }
+ }
+
+ public static final Parcelable.Creator<CameraMetadataNative> CREATOR =
+ new Parcelable.Creator<CameraMetadataNative>() {
+ @Override
+ public CameraMetadataNative createFromParcel(Parcel in) {
+ CameraMetadataNative metadata = new CameraMetadataNative();
+ metadata.readFromParcel(in);
+ return metadata;
+ }
+
+ @Override
+ public CameraMetadataNative[] newArray(int size) {
+ return new CameraMetadataNative[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ nativeWriteToParcel(dest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T get(Key<T> key) {
+ int tag = key.getTag();
+ byte[] values = readValues(tag);
+ if (values == null) {
+ return null;
+ }
+
+ int nativeType = getNativeType(tag);
+
+ ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
+ return unpackSingle(buffer, key.getType(), nativeType);
+ }
+
+ public void readFromParcel(Parcel in) {
+ nativeReadFromParcel(in);
+ }
+
+ /**
+ * Set a camera metadata field to a value. The field definitions can be
+ * found in {@link CameraProperties}, {@link CaptureResult}, and
+ * {@link CaptureRequest}.
+ *
+ * @param key The metadata field to write.
+ * @param value The value to set the field to, which must be of a matching
+ * type to the key.
+ */
+ public <T> void set(Key<T> key, T value) {
+ int tag = key.getTag();
+
+ if (value == null) {
+ writeValues(tag, null);
+ return;
+ }
+
+ int nativeType = getNativeType(tag);
+
+ int size = packSingle(value, null, key.getType(), nativeType, /* sizeOnly */true);
+
+ // TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
+ byte[] values = new byte[size];
+
+ ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
+ packSingle(value, buffer, key.getType(), nativeType, /*sizeOnly*/false);
+
+ writeValues(tag, values);
+ }
+
+ // Keep up-to-date with camera_metadata.h
+ /**
+ * @hide
+ */
+ public static final int TYPE_BYTE = 0;
+ /**
+ * @hide
+ */
+ public static final int TYPE_INT32 = 1;
+ /**
+ * @hide
+ */
+ public static final int TYPE_FLOAT = 2;
+ /**
+ * @hide
+ */
+ public static final int TYPE_INT64 = 3;
+ /**
+ * @hide
+ */
+ public static final int TYPE_DOUBLE = 4;
+ /**
+ * @hide
+ */
+ public static final int TYPE_RATIONAL = 5;
+ /**
+ * @hide
+ */
+ public static final int NUM_TYPES = 6;
+
+ private void close() {
+ // this sets mMetadataPtr to 0
+ nativeClose();
+ mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
+ }
+
+ private static int getTypeSize(int nativeType) {
+ switch(nativeType) {
+ case TYPE_BYTE:
+ return 1;
+ case TYPE_INT32:
+ case TYPE_FLOAT:
+ return 4;
+ case TYPE_INT64:
+ case TYPE_DOUBLE:
+ case TYPE_RATIONAL:
+ return 8;
+ }
+
+ throw new UnsupportedOperationException("Unknown type, can't get size "
+ + nativeType);
+ }
+
+ private static Class<?> getExpectedType(int nativeType) {
+ switch(nativeType) {
+ case TYPE_BYTE:
+ return Byte.TYPE;
+ case TYPE_INT32:
+ return Integer.TYPE;
+ case TYPE_FLOAT:
+ return Float.TYPE;
+ case TYPE_INT64:
+ return Long.TYPE;
+ case TYPE_DOUBLE:
+ return Double.TYPE;
+ case TYPE_RATIONAL:
+ return Rational.class;
+ }
+
+ throw new UnsupportedOperationException("Unknown type, can't map to Java type "
+ + nativeType);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> int packSingleNative(T value, ByteBuffer buffer, Class<T> type,
+ int nativeType, boolean sizeOnly) {
+
+ if (!sizeOnly) {
+ /**
+ * Rewrite types when the native type doesn't match the managed type
+ * - Boolean -> Byte
+ * - Integer -> Byte
+ */
+
+ if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
+ // Since a boolean can't be cast to byte, and we don't want to use putBoolean
+ boolean asBool = (Boolean) value;
+ byte asByte = (byte) (asBool ? 1 : 0);
+ value = (T) (Byte) asByte;
+ } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
+ int asInt = (Integer) value;
+ byte asByte = (byte) asInt;
+ value = (T) (Byte) asByte;
+ } else if (type != getExpectedType(nativeType)) {
+ throw new UnsupportedOperationException("Tried to pack a type of " + type +
+ " but we expected the type to be " + getExpectedType(nativeType));
+ }
+
+ if (nativeType == TYPE_BYTE) {
+ buffer.put((Byte) value);
+ } else if (nativeType == TYPE_INT32) {
+ buffer.putInt((Integer) value);
+ } else if (nativeType == TYPE_FLOAT) {
+ buffer.putFloat((Float) value);
+ } else if (nativeType == TYPE_INT64) {
+ buffer.putLong((Long) value);
+ } else if (nativeType == TYPE_DOUBLE) {
+ buffer.putDouble((Double) value);
+ } else if (nativeType == TYPE_RATIONAL) {
+ Rational r = (Rational) value;
+ buffer.putInt(r.getNumerator());
+ buffer.putInt(r.getDenominator());
+ }
+
+ }
+
+ return getTypeSize(nativeType);
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ private static <T> int packSingle(T value, ByteBuffer buffer, Class<T> type, int nativeType,
+ boolean sizeOnly) {
+
+ int size = 0;
+
+ if (type.isPrimitive() || type == Rational.class) {
+ size = packSingleNative(value, buffer, type, nativeType, sizeOnly);
+ } else if (type.isEnum()) {
+ size = packEnum((Enum)value, buffer, (Class<Enum>)type, nativeType, sizeOnly);
+ } else if (type.isArray()) {
+ size = packArray(value, buffer, type, nativeType, sizeOnly);
+ } else {
+ size = packClass(value, buffer, type, nativeType, sizeOnly);
+ }
+
+ return size;
+ }
+
+ private static <T extends Enum<T>> int packEnum(T value, ByteBuffer buffer, Class<T> type,
+ int nativeType, boolean sizeOnly) {
+
+ // TODO: add support for enums with their own values.
+ return packSingleNative(getEnumValue(value), buffer, Integer.TYPE, nativeType, sizeOnly);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> int packClass(T value, ByteBuffer buffer, Class<T> type, int nativeType,
+ boolean sizeOnly) {
+
+ MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
+ if (marshaler == null) {
+ throw new IllegalArgumentException(String.format("Unknown Key type: %s", type));
+ }
+
+ return marshaler.marshal(value, buffer, nativeType, sizeOnly);
+ }
+
+ private static <T> int packArray(T value, ByteBuffer buffer, Class<T> type, int nativeType,
+ boolean sizeOnly) {
+
+ int size = 0;
+ int arrayLength = Array.getLength(value);
+
+ @SuppressWarnings("unchecked")
+ Class<Object> componentType = (Class<Object>)type.getComponentType();
+
+ for (int i = 0; i < arrayLength; ++i) {
+ size += packSingle(Array.get(value, i), buffer, componentType, nativeType, sizeOnly);
+ }
+
+ return size;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> T unpackSingleNative(ByteBuffer buffer, Class<T> type, int nativeType) {
+
+ T val;
+
+ if (nativeType == TYPE_BYTE) {
+ val = (T) (Byte) buffer.get();
+ } else if (nativeType == TYPE_INT32) {
+ val = (T) (Integer) buffer.getInt();
+ } else if (nativeType == TYPE_FLOAT) {
+ val = (T) (Float) buffer.getFloat();
+ } else if (nativeType == TYPE_INT64) {
+ val = (T) (Long) buffer.getLong();
+ } else if (nativeType == TYPE_DOUBLE) {
+ val = (T) (Double) buffer.getDouble();
+ } else if (nativeType == TYPE_RATIONAL) {
+ val = (T) new Rational(buffer.getInt(), buffer.getInt());
+ } else {
+ throw new UnsupportedOperationException("Unknown type, can't unpack a native type "
+ + nativeType);
+ }
+
+ /**
+ * Rewrite types when the native type doesn't match the managed type
+ * - Byte -> Boolean
+ * - Byte -> Integer
+ */
+
+ if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
+ // Since a boolean can't be cast to byte, and we don't want to use getBoolean
+ byte asByte = (Byte) val;
+ boolean asBool = asByte != 0;
+ val = (T) (Boolean) asBool;
+ } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
+ byte asByte = (Byte) val;
+ int asInt = asByte;
+ val = (T) (Integer) asInt;
+ } else if (type != getExpectedType(nativeType)) {
+ throw new UnsupportedOperationException("Tried to unpack a type of " + type +
+ " but we expected the type to be " + getExpectedType(nativeType));
+ }
+
+ return val;
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ private static <T> T unpackSingle(ByteBuffer buffer, Class<T> type, int nativeType) {
+
+ if (type.isPrimitive() || type == Rational.class) {
+ return unpackSingleNative(buffer, type, nativeType);
+ }
+
+ if (type.isEnum()) {
+ return (T) unpackEnum(buffer, (Class<Enum>)type, nativeType);
+ }
+
+ if (type.isArray()) {
+ return unpackArray(buffer, type, nativeType);
+ }
+
+ T instance = unpackClass(buffer, type, nativeType);
+
+ return instance;
+ }
+
+ private static <T extends Enum<T>> T unpackEnum(ByteBuffer buffer, Class<T> type,
+ int nativeType) {
+ int ordinal = unpackSingleNative(buffer, Integer.TYPE, nativeType);
+ return getEnumFromValue(type, ordinal);
+ }
+
+ private static <T> T unpackClass(ByteBuffer buffer, Class<T> type, int nativeType) {
+
+ MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
+ if (marshaler == null) {
+ throw new IllegalArgumentException("Unknown class type: " + type);
+ }
+
+ return marshaler.unmarshal(buffer, nativeType);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> T unpackArray(ByteBuffer buffer, Class<T> type, int nativeType) {
+
+ Class<?> componentType = type.getComponentType();
+ Object array;
+
+ int elementSize = getTypeSize(nativeType);
+
+ MetadataMarshalClass<?> marshaler = getMarshaler(componentType, nativeType);
+ if (marshaler != null) {
+ elementSize = marshaler.getNativeSize(nativeType);
+ }
+
+ if (elementSize != MetadataMarshalClass.NATIVE_SIZE_DYNAMIC) {
+ int remaining = buffer.remaining();
+ int arraySize = remaining / elementSize;
+
+ Log.v(TAG,
+ String.format(
+ "Attempting to unpack array (count = %d, element size = %d, bytes " +
+ "remaining = %d) for type %s",
+ arraySize, elementSize, remaining, type));
+
+ array = Array.newInstance(componentType, arraySize);
+ for (int i = 0; i < arraySize; ++i) {
+ Object elem = unpackSingle(buffer, componentType, nativeType);
+ Array.set(array, i, elem);
+ }
+ } else {
+ // Dynamic size, use an array list.
+ ArrayList<Object> arrayList = new ArrayList<Object>();
+
+ int primitiveSize = getTypeSize(nativeType);
+ while (buffer.remaining() >= primitiveSize) {
+ Object elem = unpackSingle(buffer, componentType, nativeType);
+ arrayList.add(elem);
+ }
+
+ array = arrayList.toArray((T[]) Array.newInstance(componentType, 0));
+ }
+
+ if (buffer.remaining() != 0) {
+ Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
+ + type);
+ }
+
+ return (T) array;
+ }
+
+ private long mMetadataPtr; // native CameraMetadata*
+
+ private native long nativeAllocate();
+ private native long nativeAllocateCopy(CameraMetadataNative other)
+ throws NullPointerException;
+
+ private native synchronized void nativeWriteToParcel(Parcel dest);
+ private native synchronized void nativeReadFromParcel(Parcel source);
+ private native synchronized void nativeSwap(CameraMetadataNative other)
+ throws NullPointerException;
+ private native synchronized void nativeClose();
+ private native synchronized boolean nativeIsEmpty();
+ private native synchronized int nativeGetEntryCount();
+
+ private native synchronized byte[] nativeReadValues(int tag);
+ private native synchronized void nativeWriteValues(int tag, byte[] src);
+
+ private static native int nativeGetTagFromKey(String keyName)
+ throws IllegalArgumentException;
+ private static native int nativeGetTypeFromTag(int tag)
+ throws IllegalArgumentException;
+ private static native void nativeClassInit();
+
+ /**
+ * <p>Perform a 0-copy swap of the internal metadata with another object.</p>
+ *
+ * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p>
+ *
+ * @param other Metadata to swap with
+ * @throws NullPointerException if other was null
+ * @hide
+ */
+ public void swap(CameraMetadataNative other) {
+ nativeSwap(other);
+ }
+
+ /**
+ * @hide
+ */
+ public int getEntryCount() {
+ return nativeGetEntryCount();
+ }
+
+ /**
+ * Does this metadata contain at least 1 entry?
+ *
+ * @hide
+ */
+ public boolean isEmpty() {
+ return nativeIsEmpty();
+ }
+
+ /**
+ * Convert a key string into the equivalent native tag.
+ *
+ * @throws IllegalArgumentException if the key was not recognized
+ * @throws NullPointerException if the key was null
+ *
+ * @hide
+ */
+ public static int getTag(String key) {
+ return nativeGetTagFromKey(key);
+ }
+
+ /**
+ * Get the underlying native type for a tag.
+ *
+ * @param tag An integer tag, see e.g. {@link #getTag}
+ * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE}
+ *
+ * @hide
+ */
+ public static int getNativeType(int tag) {
+ return nativeGetTypeFromTag(tag);
+ }
+
+ /**
+ * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing
+ * the entry if src was null.</p>
+ *
+ * <p>An empty array can be passed in to update the entry to 0 elements.</p>
+ *
+ * @param tag An integer tag, see e.g. {@link #getTag}
+ * @param src An array of bytes, or null to erase the entry
+ *
+ * @hide
+ */
+ public void writeValues(int tag, byte[] src) {
+ nativeWriteValues(tag, src);
+ }
+
+ /**
+ * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize
+ * the data properly.</p>
+ *
+ * <p>An empty array can be returned to denote an existing entry with 0 elements.</p>
+ *
+ * @param tag An integer tag, see e.g. {@link #getTag}
+ *
+ * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise.
+ * @hide
+ */
+ public byte[] readValues(int tag) {
+ // TODO: Optimization. Native code returns a ByteBuffer instead.
+ return nativeReadValues(tag);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private static final HashMap<Class<? extends Enum>, int[]> sEnumValues =
+ new HashMap<Class<? extends Enum>, int[]>();
+ /**
+ * Register a non-sequential set of values to be used with the pack/unpack functions.
+ * This enables get/set to correctly marshal the enum into a value that is C-compatible.
+ *
+ * @param enumType The class for an enum
+ * @param values A list of values mapping to the ordinals of the enum
+ *
+ * @hide
+ */
+ public static <T extends Enum<T>> void registerEnumValues(Class<T> enumType, int[] values) {
+ if (enumType.getEnumConstants().length != values.length) {
+ throw new IllegalArgumentException(
+ "Expected values array to be the same size as the enumTypes values "
+ + values.length + " for type " + enumType);
+ }
+
+ Log.v(TAG, "Registered enum values for type " + enumType + " values");
+
+ sEnumValues.put(enumType, values);
+ }
+
+ /**
+ * Get the numeric value from an enum. This is usually the same as the ordinal value for
+ * enums that have fully sequential values, although for C-style enums the range of values
+ * may not map 1:1.
+ *
+ * @param enumValue Enum instance
+ * @return Int guaranteed to be ABI-compatible with the C enum equivalent
+ */
+ private static <T extends Enum<T>> int getEnumValue(T enumValue) {
+ int[] values;
+ values = sEnumValues.get(enumValue.getClass());
+
+ int ordinal = enumValue.ordinal();
+ if (values != null) {
+ return values[ordinal];
+ }
+
+ return ordinal;
+ }
+
+ /**
+ * Finds the enum corresponding to it's numeric value. Opposite of {@link #getEnumValue} method.
+ *
+ * @param enumType Class of the enum we want to find
+ * @param value The numeric value of the enum
+ * @return An instance of the enum
+ */
+ private static <T extends Enum<T>> T getEnumFromValue(Class<T> enumType, int value) {
+ int ordinal;
+
+ int[] registeredValues = sEnumValues.get(enumType);
+ if (registeredValues != null) {
+ ordinal = -1;
+
+ for (int i = 0; i < registeredValues.length; ++i) {
+ if (registeredValues[i] == value) {
+ ordinal = i;
+ break;
+ }
+ }
+ } else {
+ ordinal = value;
+ }
+
+ T[] values = enumType.getEnumConstants();
+
+ if (ordinal < 0 || ordinal >= values.length) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Argument 'value' (%d) was not a valid enum value for type %s "
+ + "(registered? %b)",
+ value,
+ enumType, (registeredValues != null)));
+ }
+
+ return values[ordinal];
+ }
+
+ static HashMap<Class<?>, MetadataMarshalClass<?>> sMarshalerMap = new
+ HashMap<Class<?>, MetadataMarshalClass<?>>();
+
+ private static <T> void registerMarshaler(MetadataMarshalClass<T> marshaler) {
+ sMarshalerMap.put(marshaler.getMarshalingClass(), marshaler);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> MetadataMarshalClass<T> getMarshaler(Class<T> type, int nativeType) {
+ MetadataMarshalClass<T> marshaler = (MetadataMarshalClass<T>) sMarshalerMap.get(type);
+
+ if (marshaler != null && !marshaler.isNativeTypeSupported(nativeType)) {
+ throw new UnsupportedOperationException("Unsupported type " + nativeType +
+ " to be marshalled to/from a " + type);
+ }
+
+ return marshaler;
+ }
+
+ /**
+ * We use a class initializer to allow the native code to cache some field offsets
+ */
+ static {
+ System.loadLibrary("media_jni");
+ nativeClassInit();
+
+ Log.v(TAG, "Shall register metadata marshalers");
+
+ // load built-in marshallers
+ registerMarshaler(new MetadataMarshalRect());
+ registerMarshaler(new MetadataMarshalSize());
+ registerMarshaler(new MetadataMarshalString());
+
+ Log.v(TAG, "Registered metadata marshalers");
+ }
+
+}
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java b/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
index a934d75..6d224ef 100644
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
@@ -26,7 +26,7 @@
* @param value the value of type T that we wish to write into the byte buffer
* @param buffer the byte buffer into which the marshalled object will be written
* @param nativeType the native type, e.g.
- * {@link android.hardware.camera2.CameraMetadata#TYPE_BYTE TYPE_BYTE}.
+ * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
* Guaranteed to be one for which isNativeTypeSupported returns true.
* @param sizeOnly if this is true, don't write to the byte buffer. calculate the size only.
* @return the size that needs to be written to the byte buffer
@@ -37,7 +37,7 @@
* Unmarshal a new object instance from the byte buffer.
* @param buffer the byte buffer, from which we will read the object
* @param nativeType the native type, e.g.
- * {@link android.hardware.camera2.CameraMetadata#TYPE_BYTE TYPE_BYTE}.
+ * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
* Guaranteed to be one for which isNativeTypeSupported returns true.
* @return a new instance of type T read from the byte buffer
*/
@@ -50,7 +50,7 @@
* will are likely to only support one type.
*
* @param nativeType the native type, e.g.
- * {@link android.hardware.camera2.CameraMetadata#TYPE_BYTE TYPE_BYTE}
+ * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
* @return true if it supports, false otherwise
*/
boolean isNativeTypeSupported(int nativeType);
@@ -60,7 +60,7 @@
/**
* How many bytes T will take up if marshalled to/from nativeType
* @param nativeType the native type, e.g.
- * {@link android.hardware.camera2.CameraMetadata#TYPE_BYTE TYPE_BYTE}
+ * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
* @return a size in bytes, or NATIVE_SIZE_DYNAMIC if the size is dynamic
*/
int getNativeSize(int nativeType);
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java b/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
index 384223c..ab72c4f 100644
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
@@ -16,7 +16,6 @@
package android.hardware.camera2.impl;
import android.graphics.Rect;
-import android.hardware.camera2.CameraMetadata;
import java.nio.ByteBuffer;
@@ -58,7 +57,7 @@
@Override
public boolean isNativeTypeSupported(int nativeType) {
- return nativeType == CameraMetadata.TYPE_INT32;
+ return nativeType == CameraMetadataNative.TYPE_INT32;
}
@Override
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java b/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
index 793bba7..e8143e0 100644
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
@@ -15,7 +15,6 @@
*/
package android.hardware.camera2.impl;
-import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.Size;
import java.nio.ByteBuffer;
@@ -51,7 +50,7 @@
@Override
public boolean isNativeTypeSupported(int nativeType) {
- return nativeType == CameraMetadata.TYPE_INT32;
+ return nativeType == CameraMetadataNative.TYPE_INT32;
}
@Override
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalString.java b/core/java/android/hardware/camera2/impl/MetadataMarshalString.java
index 50b3347..b61b8d3 100644
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalString.java
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalString.java
@@ -15,8 +15,6 @@
*/
package android.hardware.camera2.impl;
-import android.hardware.camera2.CameraMetadata;
-
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
@@ -71,7 +69,7 @@
@Override
public boolean isNativeTypeSupported(int nativeType) {
- return nativeType == CameraMetadata.TYPE_BYTE;
+ return nativeType == CameraMetadataNative.TYPE_BYTE;
}
@Override
diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
index 2c05c58..d0b3ec4 100644
--- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
+++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
@@ -19,6 +19,7 @@
import static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
+import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
import android.os.DeadObjectException;
@@ -50,6 +51,7 @@
public static final int EBUSY = -16;
public static final int ENODEV = -19;
public static final int EOPNOTSUPP = -95;
+ public static final int EDQUOT = -122;
private static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
@@ -83,6 +85,9 @@
case EBUSY:
UncheckedThrow.throwAnyException(new CameraRuntimeException(
CAMERA_IN_USE));
+ case EDQUOT:
+ UncheckedThrow.throwAnyException(new CameraRuntimeException(
+ MAX_CAMERAS_IN_USE));
case ENODEV:
UncheckedThrow.throwAnyException(new CameraRuntimeException(
CAMERA_DISCONNECTED));
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7f82ce3..9319d4a 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1650,6 +1650,11 @@
* the text. This is called whether or not the input method has requested
* extracted text updates, although if so it will not receive this call
* if the extracted text has changed as well.
+ *
+ * <p>Be careful about changing the text in reaction to this call with
+ * methods such as setComposingText, commitText or
+ * deleteSurroundingText. If the cursor moves as a result, this method
+ * will be called again, which may result in an infinite loop.
*
* <p>The default implementation takes care of updating the cursor in
* the extract text, if it is being shown.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4cf38b6..c78a973 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1476,4 +1476,20 @@
} catch (RemoteException e) {
}
}
+
+ /**
+ * Set the value for enabling/disabling airplane mode
+ *
+ * @param enable whether to enable airplane mode or not
+ *
+ * <p>This method requires the call to hold the permission
+ * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
+ * @hide
+ */
+ public void setAirplaneMode(boolean enable) {
+ try {
+ mService.setAirplaneMode(enable);
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index a6f10ec..c1da2e3 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -93,12 +93,6 @@
String[] getTetheredIfaces();
- /**
- * Return list of interface pairs that are actively tethered. Even indexes are
- * remote interface, and odd indexes are corresponding local interfaces.
- */
- String[] getTetheredIfacePairs();
-
String[] getTetheringErroredIfaces();
String[] getTetherableUsbRegexs();
@@ -156,4 +150,6 @@
LinkQualityInfo[] getAllLinkQualityInfo();
void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url);
+
+ void setAirplaneMode(boolean enable);
}
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java
index 76aea9f..648a4b3 100644
--- a/core/java/android/net/ProxyProperties.java
+++ b/core/java/android/net/ProxyProperties.java
@@ -38,7 +38,7 @@
private String mPacFileUrl;
public static final String LOCAL_EXCL_LIST = "";
- public static final int LOCAL_PORT = 8182;
+ public static final int LOCAL_PORT = -1;
public static final String LOCAL_HOST = "localhost";
public ProxyProperties(String host, int port, String exclList) {
@@ -54,6 +54,14 @@
mPacFileUrl = pacFileUrl;
}
+ // Only used in PacManager after Local Proxy is bound.
+ public ProxyProperties(String pacFileUrl, int localProxyPort) {
+ mHost = LOCAL_HOST;
+ mPort = localProxyPort;
+ setExclusionList(LOCAL_EXCL_LIST);
+ mPacFileUrl = pacFileUrl;
+ }
+
private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) {
mHost = host;
mPort = port;
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 2a18900..486e75a 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -227,9 +227,9 @@
/**
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
* <p>
- * Setting this flag enables polling for Kovio technology.
+ * Setting this flag enables polling for NfcBarcode technology.
*/
- public static final int FLAG_READER_KOVIO = 0x10;
+ public static final int FLAG_READER_NFC_BARCODE = 0x10;
/**
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 41c6603..40a3612 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -22,6 +22,7 @@
import android.content.pm.ServiceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
@@ -80,10 +81,15 @@
final boolean mRequiresDeviceUnlock;
/**
+ * The id of the service banner specified in XML.
+ */
+ final int mBannerResourceId;
+
+ /**
* @hide
*/
public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
- ArrayList<AidGroup> aidGroups, boolean requiresUnlock) {
+ ArrayList<AidGroup> aidGroups, boolean requiresUnlock, int bannerResource) {
this.mService = info;
this.mDescription = description;
this.mAidGroups = aidGroups;
@@ -95,6 +101,7 @@
this.mCategoryToGroup.put(aidGroup.category, aidGroup);
this.mAids.addAll(aidGroup.aids);
}
+ this.mBannerResourceId = bannerResource;
}
public ApduServiceInfo(PackageManager pm, ResolveInfo info, boolean onHost)
@@ -105,12 +112,8 @@
if (onHost) {
parser = si.loadXmlMetaData(pm, HostApduService.SERVICE_META_DATA);
if (parser == null) {
- Log.d(TAG, "Didn't find service meta-data, trying legacy.");
- parser = si.loadXmlMetaData(pm, HostApduService.OLD_SERVICE_META_DATA);
- if (parser == null) {
- throw new XmlPullParserException("No " + HostApduService.SERVICE_META_DATA +
- " meta-data");
- }
+ throw new XmlPullParserException("No " + HostApduService.SERVICE_META_DATA +
+ " meta-data");
}
} else {
parser = si.loadXmlMetaData(pm, OffHostApduService.SERVICE_META_DATA);
@@ -145,6 +148,9 @@
mRequiresDeviceUnlock = sa.getBoolean(
com.android.internal.R.styleable.HostApduService_requireDeviceUnlock,
false);
+ mBannerResourceId = sa.getResourceId(
+ com.android.internal.R.styleable.HostApduService_apduServiceBanner, -1);
+ sa.recycle();
} else {
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.OffHostApduService);
@@ -152,6 +158,9 @@
mDescription = sa.getString(
com.android.internal.R.styleable.OffHostApduService_description);
mRequiresDeviceUnlock = false;
+ mBannerResourceId = sa.getResourceId(
+ com.android.internal.R.styleable.HostApduService_apduServiceBanner, -1);
+ sa.recycle();
}
mAidGroups = new ArrayList<AidGroup>();
@@ -187,6 +196,7 @@
} else {
currentGroup = new AidGroup(groupCategory, groupDescription);
}
+ groupAttrs.recycle();
} else if (eventType == XmlPullParser.END_TAG && "aid-group".equals(tagName) &&
currentGroup != null) {
if (currentGroup.aids.size() > 0) {
@@ -210,6 +220,7 @@
} else {
Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
}
+ a.recycle();
}
}
} catch (NameNotFoundException e) {
@@ -252,6 +263,21 @@
return mService.loadIcon(pm);
}
+ public Drawable loadBanner(PackageManager pm) {
+ Resources res;
+ try {
+ res = pm.getResourcesForApplication(mService.serviceInfo.packageName);
+ Drawable banner = res.getDrawable(mBannerResourceId);
+ return banner;
+ } catch (NotFoundException e) {
+ Log.e(TAG, "Could not load banner.");
+ return null;
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not load banner.");
+ return null;
+ }
+ }
+
static boolean isValidAid(String aid) {
if (aid == null)
return false;
@@ -306,6 +332,7 @@
dest.writeTypedList(mAidGroups);
}
dest.writeInt(mRequiresDeviceUnlock ? 1 : 0);
+ dest.writeInt(mBannerResourceId);
};
public static final Parcelable.Creator<ApduServiceInfo> CREATOR =
@@ -321,7 +348,8 @@
source.readTypedList(aidGroups, AidGroup.CREATOR);
}
boolean requiresUnlock = (source.readInt() != 0) ? true : false;
- return new ApduServiceInfo(info, onHost, description, aidGroups, requiresUnlock);
+ int bannerResource = source.readInt();
+ return new ApduServiceInfo(info, onHost, description, aidGroups, requiresUnlock, bannerResource);
}
@Override
diff --git a/core/java/android/nfc/cardemulation/CardEmulationManager.java b/core/java/android/nfc/cardemulation/CardEmulationManager.java
deleted file mode 100644
index 124ea1c..0000000
--- a/core/java/android/nfc/cardemulation/CardEmulationManager.java
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.nfc.cardemulation;
-
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.app.ActivityThread;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.nfc.INfcCardEmulation;
-import android.nfc.NfcAdapter;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * TODO Remove when calling .apks are upgraded
- * @hide
- */
-public final class CardEmulationManager {
- static final String TAG = "CardEmulationManager";
-
- /**
- * Activity action: ask the user to change the default
- * card emulation service for a certain category. This will
- * show a dialog that asks the user whether he wants to
- * replace the current default service with the service
- * identified with the ComponentName specified in
- * {@link #EXTRA_SERVICE_COMPONENT}, for the category
- * specified in {@link #EXTRA_CATEGORY}
- */
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_CHANGE_DEFAULT =
- "android.nfc.cardemulation.ACTION_CHANGE_DEFAULT";
-
- /**
- * The category extra for {@link #ACTION_CHANGE_DEFAULT}
- *
- * @see #ACTION_CHANGE_DEFAULT
- */
- public static final String EXTRA_CATEGORY = "category";
-
- /**
- * The ComponentName object passed in as a parcelable
- * extra for {@link #ACTION_CHANGE_DEFAULT}
- *
- * @see #ACTION_CHANGE_DEFAULT
- */
- public static final String EXTRA_SERVICE_COMPONENT = "component";
-
- /**
- * The payment category can be used to indicate that an AID
- * represents a payment application.
- */
- public static final String CATEGORY_PAYMENT = "payment";
-
- /**
- * If an AID group does not contain a category, or the
- * specified category is not defined by the platform version
- * that is parsing the AID group, all AIDs in the group will
- * automatically be categorized under the {@link #CATEGORY_OTHER}
- * category.
- */
- public static final String CATEGORY_OTHER = "other";
-
- /**
- * Return value for {@link #getSelectionModeForCategory(String)}.
- *
- * <p>In this mode, the user has set a default service for this
- * AID category. If a remote reader selects any of the AIDs
- * that the default service has registered in this category,
- * that service will automatically be bound to to handle
- * the transaction.
- *
- * <p>There are still cases where a service that is
- * not the default for a category can selected:
- * <p>
- * If a remote reader selects an AID in this category
- * that is not handled by the default service, and there is a set
- * of other services {S} that do handle this AID, the
- * user is asked if he wants to use any of the services in
- * {S} instead.
- * <p>
- * As a special case, if the size of {S} is one, containing a single service X,
- * and all AIDs X has registered in this category are not
- * registered by any other service, then X will be
- * selected automatically without asking the user.
- * <p>Example:
- * <ul>
- * <li>Service A registers AIDs "1", "2" and "3" in the category
- * <li>Service B registers AIDs "3" and "4" in the category
- * <li>Service C registers AIDs "5" and "6" in the category
- * </ul>
- * In this case, the following will happen when service A
- * is the default:
- * <ul>
- * <li>Reader selects AID "1", "2" or "3": service A is invoked automatically
- * <li>Reader selects AID "4": the user is asked to confirm he
- * wants to use service B, because its AIDs overlap with service A.
- * <li>Reader selects AID "5" or "6": service C is invoked automatically,
- * because all AIDs it has asked for are only registered by C,
- * and there is no overlap.
- * </ul>
- *
- */
- public static final int SELECTION_MODE_PREFER_DEFAULT = 0;
-
- /**
- * Return value for {@link #getSelectionModeForCategory(String)}.
- *
- * <p>In this mode, whenever an AID of this category is selected,
- * the user is asked which service he wants to use to handle
- * the transaction, even if there is only one matching service.
- */
- public static final int SELECTION_MODE_ALWAYS_ASK = 1;
-
- /**
- * Return value for {@link #getSelectionModeForCategory(String)}.
- *
- * <p>In this mode, the user will only be asked to select a service
- * if the selected AID has been registered by multiple applications.
- */
- public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2;
-
- static boolean sIsInitialized = false;
- static HashMap<Context, CardEmulationManager> sCardEmuManagers = new HashMap();
- static INfcCardEmulation sService;
-
- final Context mContext;
-
- private CardEmulationManager(Context context, INfcCardEmulation service) {
- mContext = context.getApplicationContext();
- sService = service;
- }
-
- public static synchronized CardEmulationManager getInstance(NfcAdapter adapter) {
- if (adapter == null) throw new NullPointerException("NfcAdapter is null");
- Context context = adapter.getContext();
- if (context == null) {
- Log.e(TAG, "NfcAdapter context is null.");
- throw new UnsupportedOperationException();
- }
- if (!sIsInitialized) {
- IPackageManager pm = ActivityThread.getPackageManager();
- if (pm == null) {
- Log.e(TAG, "Cannot get PackageManager");
- throw new UnsupportedOperationException();
- }
- try {
- if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
- Log.e(TAG, "This device does not support card emulation");
- throw new UnsupportedOperationException();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "PackageManager query failed.");
- throw new UnsupportedOperationException();
- }
- sIsInitialized = true;
- }
- CardEmulationManager manager = sCardEmuManagers.get(context);
- if (manager == null) {
- // Get card emu service
- INfcCardEmulation service = adapter.getCardEmulationService();
- manager = new CardEmulationManager(context, service);
- sCardEmuManagers.put(context, manager);
- }
- return manager;
- }
-
- /**
- * Allows an application to query whether a service is currently
- * the default service to handle a card emulation category.
- *
- * <p>Note that if {@link #getSelectionModeForCategory(String)}
- * returns {@link #SELECTION_MODE_ALWAYS_ASK}, this method will always
- * return false.
- *
- * @param service The ComponentName of the service
- * @param category The category
- * @return whether service is currently the default service for the category.
- */
- public boolean isDefaultServiceForCategory(ComponentName service, String category) {
- try {
- return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service, category);
- } catch (RemoteException e) {
- // Try one more time
- recoverService();
- if (sService == null) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return false;
- }
- try {
- return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service,
- category);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return false;
- }
- }
- }
-
- /**
- *
- * Allows an application to query whether a service is currently
- * the default handler for a specified ISO7816-4 Application ID.
- *
- * @param service The ComponentName of the service
- * @param aid The ISO7816-4 Application ID
- * @return
- */
- public boolean isDefaultServiceForAid(ComponentName service, String aid) {
- try {
- return sService.isDefaultServiceForAid(UserHandle.myUserId(), service, aid);
- } catch (RemoteException e) {
- // Try one more time
- recoverService();
- if (sService == null) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return false;
- }
- try {
- return sService.isDefaultServiceForAid(UserHandle.myUserId(), service, aid);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to reach CardEmulationService.");
- return false;
- }
- }
- }
-
- /**
- * Returns the application selection mode for the passed in category.
- * Valid return values are:
- * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default
- * application for this category, which will be preferred.
- * <p>{@link #SELECTION_MODE_ALWAYS_ASK} the user has requested to be asked
- * every time what app he would like to use in this category.
- * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked
- * to pick a service if there is a conflict.
- * @param category The category, for example {@link #CATEGORY_PAYMENT}
- * @return
- */
- public int getSelectionModeForCategory(String category) {
- if (CATEGORY_PAYMENT.equals(category)) {
- String defaultComponent = Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
- if (defaultComponent != null) {
- return SELECTION_MODE_PREFER_DEFAULT;
- } else {
- return SELECTION_MODE_ALWAYS_ASK;
- }
- } else {
- // All other categories are in "only ask if conflict" mode
- return SELECTION_MODE_ASK_IF_CONFLICT;
- }
- }
-
- /**
- * @hide
- */
- public boolean setDefaultServiceForCategory(ComponentName service, String category) {
- try {
- return sService.setDefaultServiceForCategory(UserHandle.myUserId(), service, category);
- } catch (RemoteException e) {
- // Try one more time
- recoverService();
- if (sService == null) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return false;
- }
- try {
- return sService.setDefaultServiceForCategory(UserHandle.myUserId(), service,
- category);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to reach CardEmulationService.");
- return false;
- }
- }
- }
-
- /**
- * @hide
- */
- public boolean setDefaultForNextTap(ComponentName service) {
- try {
- return sService.setDefaultForNextTap(UserHandle.myUserId(), service);
- } catch (RemoteException e) {
- // Try one more time
- recoverService();
- if (sService == null) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return false;
- }
- try {
- return sService.setDefaultForNextTap(UserHandle.myUserId(), service);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to reach CardEmulationService.");
- return false;
- }
- }
- }
- /**
- * @hide
- */
- public List<ApduServiceInfo> getServices(String category) {
- try {
- return sService.getServices(UserHandle.myUserId(), category);
- } catch (RemoteException e) {
- // Try one more time
- recoverService();
- if (sService == null) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return null;
- }
- try {
- return sService.getServices(UserHandle.myUserId(), category);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to reach CardEmulationService.");
- return null;
- }
- }
- }
-
- void recoverService() {
- NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
- sService = adapter.getCardEmulationService();
- }
-}
diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/core/java/android/nfc/cardemulation/HostApduService.java
index 174acc0..e2c3ca6 100644
--- a/core/java/android/nfc/cardemulation/HostApduService.java
+++ b/core/java/android/nfc/cardemulation/HostApduService.java
@@ -50,23 +50,6 @@
"android.nfc.cardemulation.host_apdu_service";
/**
- * The {@link Intent} that must be declared as handled by the service.
- * TODO Remove
- * @hide
- */
- public static final String OLD_SERVICE_INTERFACE =
- "android.nfc.HostApduService";
-
- /**
- * The name of the meta-data element that contains
- * more information about this service.
- *
- * TODO Remove
- * @hide
- */
- public static final String OLD_SERVICE_META_DATA = "android.nfc.HostApduService";
-
- /**
* Reason for {@link #onDeactivated(int)}.
* Indicates deactivation was due to the NFC link
* being lost.
@@ -282,37 +265,7 @@
* @return a byte-array containing the response APDU, or null if no
* response APDU can be sent at this point.
*/
- public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
- // TODO make this abstract
- return processCommandApdu(commandApdu, 0);
- }
-
- /**
- * <p>This method will be called when a command APDU has been received
- * from a remote device. A response APDU can be provided directly
- * by returning a byte-array in this method. Note that in general
- * response APDUs must be sent as quickly as possible, given the fact
- * that the user is likely holding his device over an NFC reader
- * when this method is called.
- *
- * <p class="note">If there are multiple services that have registered for the same
- * AIDs in their meta-data entry, you will only get called if the user has
- * explicitly selected your service, either as a default or just for the next tap.
- *
- * <p class="note">This method is running on the main thread of your application.
- * If you cannot return a response APDU immediately, return null
- * and use the {@link #sendResponseApdu(byte[])} method later.
- *
- * @deprecated use {@link #processCommandApdu(byte[], Bundle)}
- * @param commandApdu
- * @param flags
- * @return a byte-array containing the response APDU, or null if no
- * response APDU can be sent at this point.
- * @hide
- */
- public byte[] processCommandApdu(byte[] commandApdu, int flags) {
- return null;
- }
+ public abstract byte[] processCommandApdu(byte[] commandApdu, Bundle extras);
/**
* This method will be called in two possible scenarios:
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 8f68fc1..0c718f4 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -236,40 +236,40 @@
return dalvikSharedClean + nativeSharedClean + otherSharedClean;
}
- /* @hide */
+ /** @hide */
public int getOtherPss(int which) {
return otherStats[which*NUM_CATEGORIES + offsetPss];
}
- /* @hide */
+ /** @hide */
public int getOtherSwappablePss(int which) {
return otherStats[which*NUM_CATEGORIES + offsetSwappablePss];
}
- /* @hide */
+ /** @hide */
public int getOtherPrivateDirty(int which) {
return otherStats[which*NUM_CATEGORIES + offsetPrivateDirty];
}
- /* @hide */
+ /** @hide */
public int getOtherSharedDirty(int which) {
return otherStats[which*NUM_CATEGORIES + offsetSharedDirty];
}
- /* @hide */
+ /** @hide */
public int getOtherPrivateClean(int which) {
return otherStats[which*NUM_CATEGORIES + offsetPrivateClean];
}
- /* @hide */
+ /** @hide */
public int getOtherSharedClean(int which) {
return otherStats[which*NUM_CATEGORIES + offsetSharedClean];
}
- /* @hide */
+ /** @hide */
public static String getOtherLabel(int which) {
switch (which) {
case 0: return "Dalvik Other";
@@ -733,7 +733,7 @@
/**
* Clears the global size of objects allocated.
- * @see #getGlobalAllocCountSize()
+ * @see #getGlobalAllocSize()
*/
public static void resetGlobalAllocSize() {
VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
@@ -1018,6 +1018,28 @@
*/
public static native long getPss(int pid, long[] outUss);
+ /** @hide */
+ public static final int MEMINFO_TOTAL = 0;
+ /** @hide */
+ public static final int MEMINFO_FREE = 1;
+ /** @hide */
+ public static final int MEMINFO_BUFFERS = 2;
+ /** @hide */
+ public static final int MEMINFO_CACHED = 3;
+ /** @hide */
+ public static final int MEMINFO_SHMEM = 4;
+ /** @hide */
+ public static final int MEMINFO_SLAB = 5;
+ /** @hide */
+ public static final int MEMINFO_COUNT = 6;
+
+ /**
+ * Retrieves /proc/meminfo. outSizes is filled with fields
+ * as defined by MEMINFO_* offsets.
+ * @hide
+ */
+ public static native void getMemInfo(long[] outSizes);
+
/**
* Establish an object allocation limit in the current thread.
* This feature was never enabled in release builds. The
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index c6e8c3e..5b36bca 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -460,7 +460,13 @@
* top-level public directory, as this convention makes no sense elsewhere.
*/
public static String DIRECTORY_DCIM = "DCIM";
-
+
+ /**
+ * Standard directory in which to place documents that have been created by
+ * the user.
+ */
+ public static String DIRECTORY_DOCUMENTS = "Documents";
+
/**
* Get a top-level public external storage directory for placing files of
* a particular type. This is where the user will typically place and
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 61e5a4b..21b8ae5 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -260,11 +260,9 @@
NetworkStats getNetworkStatsUidDetail(int uid);
/**
- * Return summary of network statistics for the requested pairs of
- * tethering interfaces. Even indexes are remote interface, and odd
- * indexes are corresponding local interfaces.
+ * Return summary of network statistics all tethering interfaces.
*/
- NetworkStats getNetworkStatsTethering(in String[] ifacePairs);
+ NetworkStats getNetworkStatsTethering();
/**
* Set quota for an interface.
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 46b0150..fec2a3e 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -228,6 +228,7 @@
private static final int EX_ILLEGAL_ARGUMENT = -3;
private static final int EX_NULL_POINTER = -4;
private static final int EX_ILLEGAL_STATE = -5;
+ private static final int EX_NETWORK_MAIN_THREAD = -6;
private static final int EX_HAS_REPLY_HEADER = -128; // special; see below
private static native int nativeDataSize(int nativePtr);
@@ -1321,6 +1322,7 @@
* <li>{@link IllegalStateException}
* <li>{@link NullPointerException}
* <li>{@link SecurityException}
+ * <li>{@link NetworkOnMainThreadException}
* </ul>
*
* @param e The Exception to be written.
@@ -1340,6 +1342,8 @@
code = EX_NULL_POINTER;
} else if (e instanceof IllegalStateException) {
code = EX_ILLEGAL_STATE;
+ } else if (e instanceof NetworkOnMainThreadException) {
+ code = EX_NETWORK_MAIN_THREAD;
}
writeInt(code);
StrictMode.clearGatheredViolations();
@@ -1455,6 +1459,8 @@
throw new NullPointerException(msg);
case EX_ILLEGAL_STATE:
throw new IllegalStateException(msg);
+ case EX_NETWORK_MAIN_THREAD:
+ throw new NetworkOnMainThreadException();
}
throw new RuntimeException("Unknown exception code: " + code
+ " msg " + msg);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 52e5f38..5e0d489 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -407,7 +407,7 @@
*/
public WakeLock newWakeLock(int levelAndFlags, String tag) {
validateWakeLockParameters(levelAndFlags, tag);
- return new WakeLock(levelAndFlags, tag, mContext.getBasePackageName());
+ return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());
}
/** @hide */
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index e66fb285..700f80d 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -39,7 +39,7 @@
}
public SystemVibrator(Context context) {
- mPackageName = context.getBasePackageName();
+ mPackageName = context.getOpPackageName();
mService = IVibratorService.Stub.asInterface(
ServiceManager.getService("vibrator"));
}
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index b79bdee..30d535b 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -97,6 +97,16 @@
}
/**
+ * Clear names from this WorkSource. Uids are left intact.
+ *
+ * <p>Useful when combining with another WorkSource that doesn't have names.
+ * @hide
+ */
+ public void clearNames() {
+ mNames = null;
+ }
+
+ /**
* Clear this WorkSource to be empty.
*/
public void clear() {
diff --git a/core/java/android/preference/TwoStatePreference.java b/core/java/android/preference/TwoStatePreference.java
index c649879..af83953 100644
--- a/core/java/android/preference/TwoStatePreference.java
+++ b/core/java/android/preference/TwoStatePreference.java
@@ -21,6 +21,7 @@
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
@@ -215,17 +216,17 @@
TextView summaryView = (TextView) view.findViewById(com.android.internal.R.id.summary);
if (summaryView != null) {
boolean useDefaultSummary = true;
- if (mChecked && mSummaryOn != null) {
+ if (mChecked && !TextUtils.isEmpty(mSummaryOn)) {
summaryView.setText(mSummaryOn);
useDefaultSummary = false;
- } else if (!mChecked && mSummaryOff != null) {
+ } else if (!mChecked && !TextUtils.isEmpty(mSummaryOff)) {
summaryView.setText(mSummaryOff);
useDefaultSummary = false;
}
if (useDefaultSummary) {
final CharSequence summary = getSummary();
- if (summary != null) {
+ if (!TextUtils.isEmpty(summary)) {
summaryView.setText(summary);
useDefaultSummary = false;
}
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index fb6bb2e..4e839c6 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -19,9 +19,11 @@
import android.print.IPrinterDiscoveryObserver;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintClient;
+import android.print.PrintJobId;
import android.print.PrinterId;
import android.print.PrintJobInfo;
import android.print.PrintAttributes;
+import android.printservice.PrintServiceInfo;
/**
* Interface for communication with the core print manager service.
@@ -30,12 +32,14 @@
*/
interface IPrintManager {
List<PrintJobInfo> getPrintJobInfos(int appId, int userId);
- PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId);
+ PrintJobInfo getPrintJobInfo(in PrintJobId printJobId, int appId, int userId);
PrintJobInfo print(String printJobName, in IPrintClient client,
in IPrintDocumentAdapter printAdapter, in PrintAttributes attributes,
int appId, int userId);
- void cancelPrintJob(int printJobId, int appId, int userId);
- void restartPrintJob(int printJobId, int appId, int userId);
+ void cancelPrintJob(in PrintJobId printJobId, int appId, int userId);
+ void restartPrintJob(in PrintJobId printJobId, int appId, int userId);
+
+ List<PrintServiceInfo> getEnabledPrintServices(int userId);
void createPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId);
void startPrinterDiscovery(in IPrinterDiscoveryObserver observer,
diff --git a/core/java/android/print/IPrintSpooler.aidl b/core/java/android/print/IPrintSpooler.aidl
index 0a77dab..291e81f 100644
--- a/core/java/android/print/IPrintSpooler.aidl
+++ b/core/java/android/print/IPrintSpooler.aidl
@@ -24,6 +24,8 @@
import android.print.IPrintSpoolerCallbacks;
import android.print.PrinterInfo;
import android.print.PrintAttributes;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
/**
* Interface for communication with the print spooler service.
@@ -33,17 +35,18 @@
* @hide
*/
oneway interface IPrintSpooler {
+ void removeObsoletePrintJobs();
+ void forgetPrintJobs(in List<PrintJobId> printJob);
void getPrintJobInfos(IPrintSpoolerCallbacks callback, in ComponentName componentName,
int state, int appId, int sequence);
- void getPrintJobInfo(int printJobId, IPrintSpoolerCallbacks callback,
+ void getPrintJobInfo(in PrintJobId printJobId, IPrintSpoolerCallbacks callback,
int appId, int sequence);
- void createPrintJob(String printJobName, in IPrintClient client,
- in IPrintDocumentAdapter printAdapter, in PrintAttributes attributes,
- IPrintSpoolerCallbacks callback, int appId, int sequence);
- void setPrintJobState(int printJobId, int status, String error,
+ void createPrintJob(in PrintJobInfo printJob, in IPrintClient client,
+ in IPrintDocumentAdapter printAdapter);
+ void setPrintJobState(in PrintJobId printJobId, int status, String stateReason,
IPrintSpoolerCallbacks callback, int sequence);
- void setPrintJobTag(int printJobId, String tag, IPrintSpoolerCallbacks callback,
+ void setPrintJobTag(in PrintJobId printJobId, String tag, IPrintSpoolerCallbacks callback,
int sequence);
- void writePrintJobData(in ParcelFileDescriptor fd, int printJobId);
+ void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId);
void setClient(IPrintSpoolerClient client);
}
diff --git a/core/java/android/print/IPrintSpoolerCallbacks.aidl b/core/java/android/print/IPrintSpoolerCallbacks.aidl
index 51b5439..45c5332 100644
--- a/core/java/android/print/IPrintSpoolerCallbacks.aidl
+++ b/core/java/android/print/IPrintSpoolerCallbacks.aidl
@@ -28,7 +28,6 @@
*/
oneway interface IPrintSpoolerCallbacks {
void onGetPrintJobInfosResult(in List<PrintJobInfo> printJob, int sequence);
- void onCreatePrintJobResult(in PrintJobInfo printJob, int sequence);
void onCancelPrintJobResult(boolean canceled, int sequence);
void onSetPrintJobStateResult(boolean success, int sequence);
void onSetPrintJobTagResult(boolean success, int sequence);
diff --git a/core/java/android/print/IPrinterDiscoveryObserver.aidl b/core/java/android/print/IPrinterDiscoveryObserver.aidl
index b558011..2be7b6b 100644
--- a/core/java/android/print/IPrinterDiscoveryObserver.aidl
+++ b/core/java/android/print/IPrinterDiscoveryObserver.aidl
@@ -18,6 +18,7 @@
import android.print.PrinterId;
import android.print.PrinterInfo;
+import android.content.pm.ParceledListSlice;
/**
* Interface for observing discovered printers by a discovery session.
@@ -25,6 +26,6 @@
* @hide
*/
oneway interface IPrinterDiscoveryObserver {
- void onPrintersAdded(in List<PrinterInfo> printers);
- void onPrintersRemoved(in List<PrinterId> printerIds);
+ void onPrintersAdded(in ParceledListSlice printers);
+ void onPrintersRemoved(in ParceledListSlice printerIds);
}
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index b1e427e..efe6b15 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -41,7 +41,7 @@
private MediaSize mMediaSize;
private Resolution mResolution;
- private Margins mMargins;
+ private Margins mMinMargins;
private int mColorMode;
@@ -52,7 +52,7 @@
private PrintAttributes(Parcel parcel) {
mMediaSize = (parcel.readInt() == 1) ? MediaSize.createFromParcel(parcel) : null;
mResolution = (parcel.readInt() == 1) ? Resolution.createFromParcel(parcel) : null;
- mMargins = (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
+ mMinMargins = (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
mColorMode = parcel.readInt();
}
@@ -97,23 +97,25 @@
}
/**
- * Gets the margins.
+ * Gets the minimal margins. If the content does not fit
+ * these margins it will be clipped.
*
* @return The margins or <code>null</code> if not set.
*/
- public Margins getMargins() {
- return mMargins;
+ public Margins getMinMargins() {
+ return mMinMargins;
}
/**
- * Sets the margins.
+ * Sets the minimal margins. If the content does not fit
+ * these margins it will be clipped.
*
* @param The margins.
*
* @hide
*/
- public void setMargins(Margins margins) {
- mMargins = margins;
+ public void setMinMargins(Margins margins) {
+ mMinMargins = margins;
}
/**
@@ -157,9 +159,9 @@
} else {
parcel.writeInt(0);
}
- if (mMargins != null) {
+ if (mMinMargins != null) {
parcel.writeInt(1);
- mMargins.writeToParcel(parcel);
+ mMinMargins.writeToParcel(parcel);
} else {
parcel.writeInt(0);
}
@@ -176,7 +178,7 @@
final int prime = 31;
int result = 1;
result = prime * result + mColorMode;
- result = prime * result + ((mMargins == null) ? 0 : mMargins.hashCode());
+ result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode());
result = prime * result + ((mMediaSize == null) ? 0 : mMediaSize.hashCode());
result = prime * result + ((mResolution == null) ? 0 : mResolution.hashCode());
return result;
@@ -197,11 +199,11 @@
if (mColorMode != other.mColorMode) {
return false;
}
- if (mMargins == null) {
- if (other.mMargins != null) {
+ if (mMinMargins == null) {
+ if (other.mMinMargins != null) {
return false;
}
- } else if (!mMargins.equals(other.mMargins)) {
+ } else if (!mMinMargins.equals(other.mMinMargins)) {
return false;
}
if (mMediaSize == null) {
@@ -226,8 +228,14 @@
StringBuilder builder = new StringBuilder();
builder.append("PrintAttributes{");
builder.append("mediaSize: ").append(mMediaSize);
+ if (mMediaSize != null) {
+ builder.append(", orientation: ").append(mMediaSize.isPortrait()
+ ? "portrait" : "landscape");
+ } else {
+ builder.append(", orientation: ").append("null");
+ }
builder.append(", resolution: ").append(mResolution);
- builder.append(", margins: ").append(mMargins);
+ builder.append(", minMargins: ").append(mMinMargins);
builder.append(", colorMode: ").append(colorModeToString(mColorMode));
builder.append("}");
return builder.toString();
@@ -237,7 +245,7 @@
public void clear() {
mMediaSize = null;
mResolution = null;
- mMargins = null;
+ mMinMargins = null;
mColorMode = 0;
}
@@ -247,7 +255,7 @@
public void copyFrom(PrintAttributes other) {
mMediaSize = other.mMediaSize;
mResolution = other.mResolution;
- mMargins = other.mMargins;
+ mMinMargins = other.mMinMargins;
mColorMode = other.mColorMode;
}
@@ -365,27 +373,208 @@
// North America
- /** North America Letter media size: 8.5" x 11" */
+ /** North America Letter media size: 8.5" x 11" (279mm x 216mm) */
public static final MediaSize NA_LETTER =
new MediaSize("NA_LETTER", "android", R.string.mediaSize_na_letter, 8500, 11000);
- /** North America Government-Letter media size: 8.0" x 10.5" */
+ /** North America Government-Letter media size: 8.0" x 10.5" (203mm x 267mm) */
public static final MediaSize NA_GOVT_LETTER =
new MediaSize("NA_GOVT_LETTER", "android",
R.string.mediaSize_na_gvrnmt_letter, 8000, 10500);
- /** North America Legal media size: 8.5" x 14" */
+ /** North America Legal media size: 8.5" x 14" (216mm x 356mm) */
public static final MediaSize NA_LEGAL =
new MediaSize("NA_LEGAL", "android", R.string.mediaSize_na_legal, 8500, 14000);
- /** North America Junior Legal media size: 8.0" x 5.0" */
+ /** North America Junior Legal media size: 8.0" x 5.0" (203mm × 127mm) */
public static final MediaSize NA_JUNIOR_LEGAL =
new MediaSize("NA_JUNIOR_LEGAL", "android",
R.string.mediaSize_na_junior_legal, 8000, 5000);
- /** North America Ledger media size: 17" x 11" */
+ /** North America Ledger media size: 17" x 11" (432mm × 279mm) */
public static final MediaSize NA_LEDGER =
new MediaSize("NA_LEDGER", "android", R.string.mediaSize_na_ledger, 17000, 11000);
- /** North America Tabloid media size: 11" x 17" */
+ /** North America Tabloid media size: 11" x 17" (279mm × 432mm) */
public static final MediaSize NA_TBLOID =
new MediaSize("NA_TABLOID", "android",
R.string.mediaSize_na_tabloid, 11000, 17000);
+ /** North America Index Card 3x5 media size: 3" x 5" (76mm x 127mm) */
+ public static final MediaSize NA_INDEX_3X5 =
+ new MediaSize("NA_INDEX_3X5", "android",
+ R.string.mediaSize_na_index_3x5, 3000, 5000);
+ /** North America Index Card 4x6 media size: 4" x 6" (102mm x 152mm) */
+ public static final MediaSize NA_INDEX_4X6 =
+ new MediaSize("NA_INDEX_4X6", "android",
+ R.string.mediaSize_na_index_4x6, 4000, 6000);
+ /** North America Index Card 5x8 media size: 5" x 8" (127mm x 203mm) */
+ public static final MediaSize NA_INDEX_5X8 =
+ new MediaSize("NA_INDEX_5X8", "android",
+ R.string.mediaSize_na_index_5x8, 5000, 8000);
+ /** North America Monarch media size: 7.25" x 10.5" (184mm x 267mm) */
+ public static final MediaSize NA_MONARCH =
+ new MediaSize("NA_MONARCH", "android",
+ R.string.mediaSize_na_monarch, 7250, 10500);
+ /** North America Quarto media size: 8" x 10" (203mm x 254mm) */
+ public static final MediaSize NA_QUARTO =
+ new MediaSize("NA_QUARTO", "android",
+ R.string.mediaSize_na_quarto, 8000, 10000);
+ /** North America Foolscap media size: 8" x 13" (203mm x 330mm) */
+ public static final MediaSize NA_FOOLSCAP =
+ new MediaSize("NA_FOOLSCAP", "android",
+ R.string.mediaSize_na_foolscap, 8000, 13000);
+
+ // Chinese
+
+ /** Chinese ROC 8K media size: 270mm x 390mm (10.629" x 15.3543") */
+ public static final MediaSize ROC_8K =
+ new MediaSize("ROC_8K", "android",
+ R.string.mediaSize_chinese_roc_8k, 10629, 15354);
+ /** Chinese ROC 16K media size: 195mm x 270mm (7.677" x 10.629") */
+ public static final MediaSize ROC_16K =
+ new MediaSize("ROC_16K", "android",
+ R.string.mediaSize_chinese_roc_16k, 7677, 10629);
+
+ /** Chinese PRC 1 media size: 102mm x 165mm (4.015" x 6.496") */
+ public static final MediaSize PRC_1 =
+ new MediaSize("PRC_1", "android",
+ R.string.mediaSize_chinese_prc_1, 4015, 6496);
+ /** Chinese PRC 2 media size: 102mm x 176mm (4.015" x 6.929") */
+ public static final MediaSize PRC_2 =
+ new MediaSize("PRC_2", "android",
+ R.string.mediaSize_chinese_prc_2, 4015, 6929);
+ /** Chinese PRC 3 media size: 125mm x 176mm (4.921" x 6.929") */
+ public static final MediaSize PRC_3 =
+ new MediaSize("PRC_3", "android",
+ R.string.mediaSize_chinese_prc_3, 4921, 6929);
+ /** Chinese PRC 4 media size: 110mm x 208mm (4.330" x 8.189") */
+ public static final MediaSize PRC_4 =
+ new MediaSize("PRC_4", "android",
+ R.string.mediaSize_chinese_prc_4, 4330, 8189);
+ /** Chinese PRC 5 media size: 110mm x 220mm (4.330" x 8.661") */
+ public static final MediaSize PRC_5 =
+ new MediaSize("PRC_5", "android",
+ R.string.mediaSize_chinese_prc_5, 4330, 8661);
+ /** Chinese PRC 6 media size: 120mm x 320mm (4.724" x 12.599") */
+ public static final MediaSize PRC_6 =
+ new MediaSize("PRC_6", "android",
+ R.string.mediaSize_chinese_prc_6, 4724, 12599);
+ /** Chinese PRC 7 media size: 160mm x 230mm (6.299" x 9.055") */
+ public static final MediaSize PRC_7 =
+ new MediaSize("PRC_7", "android",
+ R.string.mediaSize_chinese_prc_7, 6299, 9055);
+ /** Chinese PRC 8 media size: 120mm x 309mm (4.724" x 12.165") */
+ public static final MediaSize PRC_8 =
+ new MediaSize("PRC_8", "android",
+ R.string.mediaSize_chinese_prc_8, 4724, 12165);
+ /** Chinese PRC 9 media size: 229mm x 324mm (9.016" x 12.756") */
+ public static final MediaSize PRC_9 =
+ new MediaSize("PRC_9", "android",
+ R.string.mediaSize_chinese_prc_9, 9016, 12756);
+ /** Chinese PRC 10 media size: 324mm x 458mm (12.756" x 18.032") */
+ public static final MediaSize PRC_10 =
+ new MediaSize("PRC_10", "android",
+ R.string.mediaSize_chinese_prc_10, 12756, 18032);
+
+ /** Chinese PRC 16k media size: 146mm x 215mm (5.749" x 8.465") */
+ public static final MediaSize PRC_16k =
+ new MediaSize("PRC_16k", "android",
+ R.string.mediaSize_chinese_prc_16k, 5749, 8465);
+ /** Chinese Pa Kai media size: 267mm x 389mm (10.512" x 15.315") */
+ public static final MediaSize OM_PA_KAI =
+ new MediaSize("OM_PA_KAI", "android",
+ R.string.mediaSize_chinese_om_pa_kai, 10512, 15315);
+ /** Chinese Dai Pa Kai media size: 275mm x 395mm (10.827" x 15.551") */
+ public static final MediaSize OM_DAI_PA_KAI =
+ new MediaSize("OM_DAI_PA_KAI", "android",
+ R.string.mediaSize_chinese_om_dai_pa_kai, 10827, 15551);
+ /** Chinese Jurro Ku Kai media size: 198mm x 275mm (7.796" x 10.827") */
+ public static final MediaSize OM_JUURO_KU_KAI =
+ new MediaSize("OM_JUURO_KU_KAI", "android",
+ R.string.mediaSize_chinese_om_jurro_ku_kai, 7796, 10827);
+
+ // Japanese
+
+ /** Japanese JIS B10 media size: 32mm x 45mm (1.259" x 1.772") */
+ public static final MediaSize JIS_B10 =
+ new MediaSize("JIS_B10", "android",
+ R.string.mediaSize_japanese_jis_b10, 1259, 1772);
+ /** Japanese JIS B9 media size: 45mm x 64mm (1.772" x 2.52") */
+ public static final MediaSize JIS_B9 =
+ new MediaSize("JIS_B9", "android",
+ R.string.mediaSize_japanese_jis_b9, 1772, 2520);
+ /** Japanese JIS B8 media size: 64mm x 91mm (2.52" x 3.583") */
+ public static final MediaSize JIS_B8 =
+ new MediaSize("JIS_B8", "android",
+ R.string.mediaSize_japanese_jis_b8, 2520, 3583);
+ /** Japanese JIS B7 media size: 91mm x 128mm (3.583" x 5.049") */
+ public static final MediaSize JIS_B7 =
+ new MediaSize("JIS_B7", "android",
+ R.string.mediaSize_japanese_jis_b7, 3583, 5049);
+ /** Japanese JIS B6 media size: 128mm x 182mm (5.049" x 7.165") */
+ public static final MediaSize JIS_B6 =
+ new MediaSize("JIS_B6", "android",
+ R.string.mediaSize_japanese_jis_b6, 5049, 7165);
+ /** Japanese JIS B5 media size: 182mm x 257mm (7.165" x 10.118") */
+ public static final MediaSize JIS_B5 =
+ new MediaSize("JIS_B5", "android",
+ R.string.mediaSize_japanese_jis_b5, 7165, 10118);
+ /** Japanese JIS B4 media size: 257mm x 364mm (10.118" x 14.331") */
+ public static final MediaSize JIS_B4 =
+ new MediaSize("JIS_B4", "android",
+ R.string.mediaSize_japanese_jis_b4, 10118, 14331);
+ /** Japanese JIS B3 media size: 364mm x 515mm (14.331" x 20.276") */
+ public static final MediaSize JIS_B3 =
+ new MediaSize("JIS_B3", "android",
+ R.string.mediaSize_japanese_jis_b3, 14331, 20276);
+ /** Japanese JIS B2 media size: 515mm x 728mm (20.276" x 28.661") */
+ public static final MediaSize JIS_B2 =
+ new MediaSize("JIS_B2", "android",
+ R.string.mediaSize_japanese_jis_b2, 20276, 28661);
+ /** Japanese JIS B1 media size: 728mm x 1030mm (28.661" x 40.551") */
+ public static final MediaSize JIS_B1 =
+ new MediaSize("JIS_B1", "android",
+ R.string.mediaSize_japanese_jis_b1, 28661, 40551);
+ /** Japanese JIS B0 media size: 1030mm x 1456mm (40.551" x 57.323") */
+ public static final MediaSize JIS_B0 =
+ new MediaSize("JIS_B0", "android",
+ R.string.mediaSize_japanese_jis_b0, 40551, 57323);
+
+ /** Japanese JIS Exec media size: 216mm x 330mm (8.504" x 12.992") */
+ public static final MediaSize JIS_EXEC =
+ new MediaSize("JIS_EXEC", "android",
+ R.string.mediaSize_japanese_jis_exec, 8504, 12992);
+
+ /** Japanese Chou4 media size: 90mm x 205mm (3.543" x 8.071") */
+ public static final MediaSize JPN_CHOU4 =
+ new MediaSize("JPN_CHOU4", "android",
+ R.string.mediaSize_japanese_chou4, 3543, 8071);
+ /** Japanese Chou3 media size: 120mm x 235mm (4.724" x 9.252") */
+ public static final MediaSize JPN_CHOU3 =
+ new MediaSize("JPN_CHOU3", "android",
+ R.string.mediaSize_japanese_chou3, 4724, 9252);
+ /** Japanese Chou2 media size: 111.1mm x 146mm (4.374" x 5.748") */
+ public static final MediaSize JPN_CHOU2 =
+ new MediaSize("JPN_CHOU2", "android",
+ R.string.mediaSize_japanese_chou2, 4374, 5748);
+
+ /** Japanese Hagaki media size: 100mm x 148mm (3.937" x 5.827") */
+ public static final MediaSize JPN_HAGAKI =
+ new MediaSize("JPN_HAGAKI", "android",
+ R.string.mediaSize_japanese_hagaki, 3937, 5827);
+ /** Japanese Oufuku media size: 148mm x 200mm (5.827" x 7.874") */
+ public static final MediaSize JPN_OUFUKU =
+ new MediaSize("JPN_OUFUKU", "android",
+ R.string.mediaSize_japanese_oufuku, 5827, 7874);
+
+ /** Japanese Kahu media size: 240mm x 322.1mm (9.449" x 12.681") */
+ public static final MediaSize JPN_KAHU =
+ new MediaSize("JPN_KAHU", "android",
+ R.string.mediaSize_japanese_kahu, 9449, 12681);
+ /** Japanese Kaku2 media size: 240mm x 332mm (9.449" x 13.071") */
+ public static final MediaSize JPN_KAKU2 =
+ new MediaSize("JPN_KAKU2", "android",
+ R.string.mediaSize_japanese_kaku2, 9449, 13071);
+
+ /** Japanese You4 media size: 105mm x 235mm (4.134" x 9.252") */
+ public static final MediaSize JPN_YOU4 =
+ new MediaSize("JPN_YOU4", "android",
+ R.string.mediaSize_japanese_you4, 4134, 9252);
private final String mId;
/**@hide */
@@ -643,64 +832,12 @@
* This class specifies a supported resolution in dpi (dots per inch).
*/
public static final class Resolution {
- private static final String LOG_TAG = "Resolution";
-
private final String mId;
- /**@hide */
- public final String mLabel;
- /**@hide */
- public final String mPackageName;
- /**@hide */
- public final int mLabelResId;
+ private final String mLabel;
private final int mHorizontalDpi;
private final int mVerticalDpi;
/**
- * Creates a new instance. This is the preferred constructor since
- * it enables the resolution label to be shown in a localized fashion
- * on a locale change.
- *
- * @param id The unique resolution id.
- * @param packageName The name of the creating package.
- * @param labelResId The resource id of a human readable label.
- * @param horizontalDpi The horizontal resolution in dpi.
- * @param verticalDpi The vertical resolution in dpi.
- *
- * @throws IllegalArgumentException If the id is empty.
- * @throws IllegalArgumentException If the label is empty.
- * @throws IllegalArgumentException If the horizontalDpi is less than or equal to zero.
- * @throws IllegalArgumentException If the verticalDpi is less than or equal to zero.
- *
- * @hide
- */
- public Resolution(String id, String packageName, int labelResId,
- int horizontalDpi, int verticalDpi) {
- if (TextUtils.isEmpty(id)) {
- throw new IllegalArgumentException("id cannot be empty.");
- }
- if (TextUtils.isEmpty(packageName)) {
- throw new IllegalArgumentException("packageName cannot be empty.");
- }
- if (labelResId <= 0) {
- throw new IllegalArgumentException("labelResId must be greater than zero.");
- }
- if (horizontalDpi <= 0) {
- throw new IllegalArgumentException("horizontalDpi "
- + "cannot be less than or equal to zero.");
- }
- if (verticalDpi <= 0) {
- throw new IllegalArgumentException("verticalDpi"
- + " cannot be less than or equal to zero.");
- }
- mId = id;
- mPackageName = packageName;
- mLabelResId = labelResId;
- mHorizontalDpi = horizontalDpi;
- mVerticalDpi = verticalDpi;
- mLabel = null;
- }
-
- /**
* Creates a new instance.
*
* @param id The unique resolution id.
@@ -732,19 +869,6 @@
mLabel = label;
mHorizontalDpi = horizontalDpi;
mVerticalDpi = verticalDpi;
- mPackageName = null;
- mLabelResId = 0;
- }
-
- /** @hide */
- public Resolution(String id, String label, String packageName,
- int horizontalDpi, int verticalDpi, int labelResId) {
- mId = id;
- mPackageName = packageName;
- mLabelResId = labelResId;
- mHorizontalDpi = horizontalDpi;
- mVerticalDpi = verticalDpi;
- mLabel = label;
}
/**
@@ -759,22 +883,9 @@
/**
* Gets the resolution human readable label.
*
- * @param packageManager The package manager for loading the label.
* @return The human readable label.
*/
- public String getLabel(PackageManager packageManager) {
- if (!TextUtils.isEmpty(mPackageName) && mLabelResId > 0) {
- try {
- return packageManager.getResourcesForApplication(
- mPackageName).getString(mLabelResId);
- } catch (NotFoundException nfe) {
- Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
- + " from package " + mPackageName);
- } catch (NameNotFoundException nnfee) {
- Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
- + " from package " + mPackageName);
- }
- }
+ public String getLabel() {
return mLabel;
}
@@ -799,18 +910,14 @@
void writeToParcel(Parcel parcel) {
parcel.writeString(mId);
parcel.writeString(mLabel);
- parcel.writeString(mPackageName);
parcel.writeInt(mHorizontalDpi);
parcel.writeInt(mVerticalDpi);
- parcel.writeInt(mLabelResId);
}
static Resolution createFromParcel(Parcel parcel) {
return new Resolution(
parcel.readString(),
parcel.readString(),
- parcel.readString(),
- parcel.readInt(),
parcel.readInt(),
parcel.readInt());
}
@@ -851,10 +958,8 @@
builder.append("Resolution{");
builder.append("id: ").append(mId);
builder.append(", label: ").append(mLabel);
- builder.append(", packageName: ").append(mPackageName);
builder.append(", horizontalDpi: ").append(mHorizontalDpi);
builder.append(", verticalDpi: ").append(mVerticalDpi);
- builder.append(", labelResId: ").append(mLabelResId);
builder.append("}");
return builder.toString();
}
@@ -880,12 +985,6 @@
* @param bottomMils The bottom margin in mils (thousands of an inch).
*/
public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
- if (leftMils > rightMils) {
- throw new IllegalArgumentException("leftMils cannot be less than rightMils.");
- }
- if (topMils > bottomMils) {
- throw new IllegalArgumentException("topMils cannot be less than bottomMils.");
- }
mTopMils = topMils;
mLeftMils = leftMils;
mRightMils = rightMils;
@@ -1042,13 +1141,14 @@
}
/**
- * Sets the margins.
+ * Sets the minimal margins. If the content does not fit
+ * these margins it will be clipped.
*
* @param margins The margins.
* @return This builder.
*/
- public Builder setMargins(Margins margins) {
- mAttributes.setMargins(margins);
+ public Builder setMinMargins(Margins margins) {
+ mAttributes.setMinMargins(margins);
return this;
}
@@ -1074,7 +1174,7 @@
*
* @return The new instance.
*/
- public PrintAttributes create() {
+ public PrintAttributes build() {
return mAttributes;
}
}
diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java
index c81ca95..8ac34c1 100644
--- a/core/java/android/print/PrintDocumentAdapter.java
+++ b/core/java/android/print/PrintDocumentAdapter.java
@@ -20,8 +20,6 @@
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
-import java.util.List;
-
/**
* Base class that provides the content of a document to be printed.
*
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index 7a96e69..f094962 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -277,7 +277,7 @@
*
* @return The new instance.
*/
- public PrintDocumentInfo create() {
+ public PrintDocumentInfo build() {
return new PrintDocumentInfo(mPrototype);
}
}
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
index de28bd3..00ade07 100644
--- a/core/java/android/print/PrintJob.java
+++ b/core/java/android/print/PrintJob.java
@@ -16,15 +16,12 @@
package android.print;
-
/**
* This class represents a print job from the perspective of
* an application.
*/
public final class PrintJob {
- private final int mId;
-
private final PrintManager mPrintManager;
private PrintJobInfo mCachedInfo;
@@ -32,7 +29,6 @@
PrintJob(PrintJobInfo info, PrintManager printManager) {
mCachedInfo = info;
mPrintManager = printManager;
- mId = info.getId();
}
/**
@@ -40,8 +36,8 @@
*
* @return The id.
*/
- public int getId() {
- return mId;
+ public PrintJobId getId() {
+ return mCachedInfo.getId();
}
/**
@@ -58,7 +54,7 @@
if (isInImmutableState()) {
return mCachedInfo;
}
- PrintJobInfo info = mPrintManager.getPrintJobInfo(mId);
+ PrintJobInfo info = mPrintManager.getPrintJobInfo(mCachedInfo.getId());
if (info != null) {
mCachedInfo = info;
}
@@ -70,7 +66,7 @@
*/
public void cancel() {
if (!isInImmutableState()) {
- mPrintManager.cancelPrintJob(mId);
+ mPrintManager.cancelPrintJob(mCachedInfo.getId());
}
}
@@ -92,11 +88,11 @@
return false;
}
PrintJob other = (PrintJob) obj;
- return mId == other.mId;
+ return mCachedInfo.getId().equals(other.mCachedInfo.getId());
}
@Override
public int hashCode() {
- return mId;
+ return mCachedInfo.getId().hashCode();
}
}
diff --git a/core/res/res/values-land/refs.xml b/core/java/android/print/PrintJobId.aidl
similarity index 75%
rename from core/res/res/values-land/refs.xml
rename to core/java/android/print/PrintJobId.aidl
index cda38cf..759f25f 100644
--- a/core/res/res/values-land/refs.xml
+++ b/core/java/android/print/PrintJobId.aidl
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+/**
* Copyright (c) 2013, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,8 +12,8 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
-*/
--->
-<resources>
- <item type="string" name="transient_navigation_confirmation">@string/transient_navigation_confirmation_long</item>
-</resources>
\ No newline at end of file
+ */
+
+package android.print;
+
+parcelable PrintJobId;
diff --git a/core/java/android/print/PrintJobId.java b/core/java/android/print/PrintJobId.java
new file mode 100644
index 0000000..01550e2
--- /dev/null
+++ b/core/java/android/print/PrintJobId.java
@@ -0,0 +1,122 @@
+/*
+ * 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.print;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.UUID;
+
+/**
+ * This class represents the id of a print job.
+ */
+public final class PrintJobId implements Parcelable {
+ private final String mValue;
+
+ /**
+ * Creates a new instance.
+ *
+ * @hide
+ */
+ public PrintJobId() {
+ this(UUID.randomUUID().toString());
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param value The internal value.
+ *
+ * @hide
+ */
+ public PrintJobId(String value) {
+ mValue = value;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((mValue != null) ? mValue.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ PrintJobId other = (PrintJobId) obj;
+ if (!TextUtils.equals(mValue, other.mValue)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mValue);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Flattens this id to a string.
+ *
+ * @return The flattened id.
+ *
+ * @hide
+ */
+ public String flattenToString() {
+ return mValue;
+ }
+
+ /**
+ * Unflattens a print job id from a string.
+ *
+ * @string The string.
+ * @return The unflattened id, or null if the string is malformed.
+ *
+ * @hide
+ */
+ public static PrintJobId unflattenFromString(String string) {
+ return new PrintJobId(string);
+ }
+
+ public static final Parcelable.Creator<PrintJobId> CREATOR =
+ new Parcelable.Creator<PrintJobId>() {
+ @Override
+ public PrintJobId createFromParcel(Parcel parcel) {
+ return new PrintJobId(parcel.readString());
+ }
+
+ @Override
+ public PrintJobId[] newArray(int size) {
+ return new PrintJobId[size];
+ }
+ };
+}
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index b919ad6..502a9f2 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -56,8 +56,6 @@
* <p>
* Next valid states: {@link #STATE_QUEUED}
* </p>
- *
- * @hide
*/
public static final int STATE_CREATED = 1;
@@ -117,7 +115,7 @@
public static final int STATE_CANCELED = 7;
/** The unique print job id. */
- private int mId;
+ private PrintJobId mId;
/** The human readable print job label. */
private String mLabel;
@@ -178,7 +176,7 @@
}
private PrintJobInfo(Parcel parcel) {
- mId = parcel.readInt();
+ mId = parcel.readParcelable(null);
mLabel = parcel.readString();
mPrinterId = parcel.readParcelable(null);
mPrinterName = parcel.readString();
@@ -208,7 +206,7 @@
*
* @return The id.
*/
- public int getId() {
+ public PrintJobId getId() {
return mId;
}
@@ -219,7 +217,7 @@
*
* @hide
*/
- public void setId(int id) {
+ public void setId(PrintJobId id) {
this.mId = id;
}
@@ -485,7 +483,7 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeInt(mId);
+ parcel.writeParcelable(mId, flags);
parcel.writeString(mLabel);
parcel.writeParcelable(mPrinterId, flags);
parcel.writeString(mPrinterName);
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 6e32c05..5429155 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -28,6 +28,7 @@
import android.os.RemoteException;
import android.print.PrintDocumentAdapter.LayoutResultCallback;
import android.print.PrintDocumentAdapter.WriteResultCallback;
+import android.printservice.PrintServiceInfo;
import android.text.TextUtils;
import android.util.Log;
@@ -35,7 +36,6 @@
import libcore.io.IoUtils;
-import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
@@ -113,7 +113,7 @@
return new PrintManager(mContext, mService, userId, APP_ID_ANY);
}
- PrintJobInfo getPrintJobInfo(int printJobId) {
+ PrintJobInfo getPrintJobInfo(PrintJobId printJobId) {
try {
return mService.getPrintJobInfo(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
@@ -147,7 +147,7 @@
return Collections.emptyList();
}
- void cancelPrintJob(int printJobId) {
+ void cancelPrintJob(PrintJobId printJobId) {
try {
mService.cancelPrintJob(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
@@ -156,24 +156,6 @@
}
/**
- * Creates a print job for printing a file with default print attributes.
- *
- * @param printJobName A name for the new print job.
- * @param pdfFile The PDF file to print.
- * @param documentInfo Information about the printed document.
- * @param attributes The default print job attributes.
- * @return The created print job on success or null on failure.
- *
- * @see PrintJob
- */
- public PrintJob print(String printJobName, File pdfFile, PrintDocumentInfo documentInfo,
- PrintAttributes attributes) {
- PrintFileDocumentAdapter documentAdapter = new PrintFileDocumentAdapter(
- mContext, pdfFile, documentInfo);
- return print(printJobName, documentAdapter, attributes);
- }
-
- /**
* Creates a print job for printing a {@link PrintDocumentAdapter} with default print
* attributes.
*
@@ -204,6 +186,25 @@
}
/**
+ * Gets the list of enabled print services.
+ *
+ * @return The enabled service list or an empty list.
+ *
+ * @hide
+ */
+ public List<PrintServiceInfo> getEnabledPrintServices() {
+ try {
+ List<PrintServiceInfo> enabledServices = mService.getEnabledPrintServices(mUserId);
+ if (enabledServices != null) {
+ return enabledServices;
+ }
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error getting the enalbed print services", re);
+ }
+ return Collections.emptyList();
+ }
+
+ /**
* @hide
*/
public PrinterDiscoverySession createPrinterDiscoverySession() {
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index ea44c87..df51ec1 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -51,7 +51,6 @@
private int mColorModes;
private final int[] mDefaults = new int[PROPERTY_COUNT];
- private Margins mDefaultMargins = DEFAULT_MARGINS;
/**
* @hide
@@ -71,6 +70,10 @@
* @hide
*/
public void copyFrom(PrinterCapabilitiesInfo other) {
+ if (this == other) {
+ return;
+ }
+
mMinMargins = other.mMinMargins;
if (other.mMediaSizes != null) {
@@ -101,8 +104,6 @@
for (int i = 0; i < defaultCount; i++) {
mDefaults[i] = other.mDefaults[i];
}
-
- mDefaultMargins = other.mDefaultMargins;
}
/**
@@ -124,7 +125,8 @@
}
/**
- * Gets the minimal supported margins.
+ * Gets the minimal margins. These are the minimal margins
+ * the printer physically supports.
*
* @return The minimal margins.
*/
@@ -147,27 +149,29 @@
/**
* Gets the default print attributes.
*
- * @param outAttributes The attributes to populated.
+ * @return The default attributes.
*/
- public void getDefaults(PrintAttributes outAttributes) {
- outAttributes.clear();
+ public PrintAttributes getDefaults() {
+ PrintAttributes.Builder builder = new PrintAttributes.Builder();
- outAttributes.setMargins(mDefaultMargins);
+ builder.setMinMargins(mMinMargins);
final int mediaSizeIndex = mDefaults[PROPERTY_MEDIA_SIZE];
if (mediaSizeIndex >= 0) {
- outAttributes.setMediaSize(mMediaSizes.get(mediaSizeIndex));
+ builder.setMediaSize(mMediaSizes.get(mediaSizeIndex));
}
final int resolutionIndex = mDefaults[PROPERTY_RESOLUTION];
if (resolutionIndex >= 0) {
- outAttributes.setResolution(mResolutions.get(resolutionIndex));
+ builder.setResolution(mResolutions.get(resolutionIndex));
}
final int colorMode = mDefaults[PROPERTY_COLOR_MODE];
if (colorMode > 0) {
- outAttributes.setColorMode(colorMode);
+ builder.setColorMode(colorMode);
}
+
+ return builder.build();
}
private PrinterCapabilitiesInfo(Parcel parcel) {
@@ -178,7 +182,6 @@
mColorModes = parcel.readInt();
readDefaults(parcel);
- mDefaultMargins = readMargins(parcel);
}
@Override
@@ -195,7 +198,6 @@
parcel.writeInt(mColorModes);
writeDefaults(parcel);
- writeMargins(mDefaultMargins, parcel);
}
@Override
@@ -207,7 +209,6 @@
result = prime * result + ((mResolutions == null) ? 0 : mResolutions.hashCode());
result = prime * result + mColorModes;
result = prime * result + Arrays.hashCode(mDefaults);
- result = prime * result + ((mDefaultMargins == null) ? 0 : mDefaultMargins.hashCode());
return result;
}
@@ -250,13 +251,6 @@
if (!Arrays.equals(mDefaults, other.mDefaults)) {
return false;
}
- if (mDefaultMargins == null) {
- if (other.mDefaultMargins != null) {
- return false;
- }
- } else if (!mDefaultMargins.equals(other.mDefaultMargins)) {
- return false;
- }
return true;
}
@@ -279,7 +273,7 @@
while (colorModes != 0) {
final int colorMode = 1 << Integer.numberOfTrailingZeros(colorModes);
colorModes &= ~colorMode;
- if (builder.length() > 0) {
+ if (builder.length() > 1) {
builder.append(", ");
}
builder.append(PrintAttributes.colorModeToString(colorMode));
@@ -442,27 +436,25 @@
}
/**
- * Sets the minimal margins.
+ * Sets the minimal margins. These are the minimal margins
+ * the printer physically supports.
+ *
* <p>
- * <strong>Required:</strong> No
+ * <strong>Required:</strong> Yes
* </p>
*
* @param margins The margins.
- * @param defaultMargins The default margins.
* @return This builder.
*
+ * @throws IllegalArgumentException If margins are <code>null</code>.
+ *
* @see PrintAttributes.Margins
*/
- public Builder setMinMargins(Margins margins, Margins defaultMargins) {
- if (margins.getLeftMils() > defaultMargins.getLeftMils()
- || margins.getTopMils() > defaultMargins.getTopMils()
- || margins.getRightMils() < defaultMargins.getRightMils()
- || margins.getBottomMils() < defaultMargins.getBottomMils()) {
- throw new IllegalArgumentException("Default margins"
- + " cannot be outside of the min margins.");
+ public Builder setMinMargins(Margins margins) {
+ if (margins == null) {
+ throw new IllegalArgumentException("margins cannot be null");
}
mPrototype.mMinMargins = margins;
- mPrototype.mDefaultMargins = defaultMargins;
return this;
}
@@ -507,7 +499,7 @@
*
* @throws IllegalStateException If a required attribute was not specified.
*/
- public PrinterCapabilitiesInfo create() {
+ public PrinterCapabilitiesInfo build() {
if (mPrototype.mMediaSizes == null || mPrototype.mMediaSizes.isEmpty()) {
throw new IllegalStateException("No media size specified.");
}
@@ -527,10 +519,7 @@
throw new IllegalStateException("No default color mode specified.");
}
if (mPrototype.mMinMargins == null) {
- mPrototype.mMinMargins = new Margins(0, 0, 0, 0);
- }
- if (mPrototype.mDefaultMargins == null) {
- mPrototype.mDefaultMargins = mPrototype.mMinMargins;
+ throw new IllegalArgumentException("margins cannot be null");
}
return new PrinterCapabilitiesInfo(mPrototype);
}
diff --git a/core/java/android/print/PrinterDiscoverySession.java b/core/java/android/print/PrinterDiscoverySession.java
index 64249b4..c6dbc16 100644
--- a/core/java/android/print/PrinterDiscoverySession.java
+++ b/core/java/android/print/PrinterDiscoverySession.java
@@ -17,6 +17,7 @@
package android.print;
import android.content.Context;
+import android.content.pm.ParceledListSlice;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -270,20 +271,22 @@
}
@Override
- public void onPrintersAdded(List<PrinterInfo> printers) {
+ @SuppressWarnings("rawtypes")
+ public void onPrintersAdded(ParceledListSlice printers) {
PrinterDiscoverySession session = mWeakSession.get();
if (session != null) {
session.mHandler.obtainMessage(MSG_PRINTERS_ADDED,
- printers).sendToTarget();
+ printers.getList()).sendToTarget();
}
}
@Override
- public void onPrintersRemoved(List<PrinterId> printerIds) {
+ @SuppressWarnings("rawtypes")
+ public void onPrintersRemoved(ParceledListSlice printerIds) {
PrinterDiscoverySession session = mWeakSession.get();
if (session != null) {
session.mHandler.obtainMessage(MSG_PRINTERS_REMOVED,
- printerIds).sendToTarget();
+ printerIds.getList()).sendToTarget();
}
}
}
diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java
index 0ea319b..a51e28b 100644
--- a/core/java/android/print/PrinterInfo.java
+++ b/core/java/android/print/PrinterInfo.java
@@ -56,6 +56,9 @@
* @hide
*/
public void copyFrom(PrinterInfo other) {
+ if (this == other) {
+ return;
+ }
mId = other.mId;
mName = other.mName;
mStatus = other.mStatus;
@@ -293,7 +296,7 @@
*
* @return A new {@link PrinterInfo}.
*/
- public PrinterInfo create() {
+ public PrinterInfo build() {
return new PrinterInfo(mPrototype);
}
diff --git a/core/java/android/print/pdf/PrintedPdfDocument.java b/core/java/android/print/pdf/PrintedPdfDocument.java
index bee17ef..1fd4646 100644
--- a/core/java/android/print/pdf/PrintedPdfDocument.java
+++ b/core/java/android/print/pdf/PrintedPdfDocument.java
@@ -77,14 +77,14 @@
mPageSize.set(0, 0, pageWidth, pageHeight);
// Compute the content size from the attributes.
- Margins margins = attributes.getMargins();
- final int marginLeft = (int) (((float) margins.getLeftMils() /MILS_PER_INCH)
+ Margins minMargins = attributes.getMinMargins();
+ final int marginLeft = (int) (((float) minMargins.getLeftMils() /MILS_PER_INCH)
* POINTS_IN_INCH);
- final int marginTop = (int) (((float) margins.getTopMils() / MILS_PER_INCH)
+ final int marginTop = (int) (((float) minMargins.getTopMils() / MILS_PER_INCH)
* POINTS_IN_INCH);
- final int marginRight = (int) (((float) margins.getRightMils() / MILS_PER_INCH)
+ final int marginRight = (int) (((float) minMargins.getRightMils() / MILS_PER_INCH)
* POINTS_IN_INCH);
- final int marginBottom = (int) (((float) margins.getBottomMils() / MILS_PER_INCH)
+ final int marginBottom = (int) (((float) minMargins.getBottomMils() / MILS_PER_INCH)
* POINTS_IN_INCH);
mContentSize.set(mPageSize.left + marginLeft, mPageSize.top + marginTop,
mPageSize.right - marginRight, mPageSize.bottom - marginBottom);
diff --git a/core/java/android/printservice/IPrintServiceClient.aidl b/core/java/android/printservice/IPrintServiceClient.aidl
index ad3c04f..c2dfc30 100644
--- a/core/java/android/printservice/IPrintServiceClient.aidl
+++ b/core/java/android/printservice/IPrintServiceClient.aidl
@@ -20,6 +20,8 @@
import android.print.PrintJobInfo;
import android.print.PrinterId;
import android.print.PrinterInfo;
+import android.print.PrintJobId;
+import android.content.pm.ParceledListSlice;
/**
* The top-level interface from a print service to the system.
@@ -28,11 +30,11 @@
*/
interface IPrintServiceClient {
List<PrintJobInfo> getPrintJobInfos();
- PrintJobInfo getPrintJobInfo(int printJobId);
- boolean setPrintJobState(int printJobId, int state, String error);
- boolean setPrintJobTag(int printJobId, String tag);
- oneway void writePrintJobData(in ParcelFileDescriptor fd, int printJobId);
+ PrintJobInfo getPrintJobInfo(in PrintJobId printJobId);
+ boolean setPrintJobState(in PrintJobId printJobId, int state, String error);
+ boolean setPrintJobTag(in PrintJobId printJobId, String tag);
+ oneway void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId);
- void onPrintersAdded(in List<PrinterInfo> printers);
- void onPrintersRemoved(in List<PrinterId> printerIds);
+ void onPrintersAdded(in ParceledListSlice printers);
+ void onPrintersRemoved(in ParceledListSlice printerIds);
}
diff --git a/core/java/android/printservice/PrintDocument.java b/core/java/android/printservice/PrintDocument.java
index 8292cfbc..e43f2a8 100644
--- a/core/java/android/printservice/PrintDocument.java
+++ b/core/java/android/printservice/PrintDocument.java
@@ -19,6 +19,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.print.PrintDocumentInfo;
+import android.print.PrintJobId;
import android.util.Log;
import java.io.IOException;
@@ -35,13 +36,13 @@
private static final String LOG_TAG = "PrintDocument";
- private final int mPrintJobId;
+ private final PrintJobId mPrintJobId;
private final IPrintServiceClient mPrintServiceClient;
private final PrintDocumentInfo mInfo;
- PrintDocument(int printJobId, IPrintServiceClient printServiceClient,
+ PrintDocument(PrintJobId printJobId, IPrintServiceClient printServiceClient,
PrintDocumentInfo info) {
mPrintJobId = printJobId;
mPrintServiceClient = printServiceClient;
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index 4ff7f0c..2fcae6b 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -17,6 +17,7 @@
package android.printservice;
import android.os.RemoteException;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.text.TextUtils;
import android.util.Log;
@@ -52,7 +53,7 @@
*
* @return The id.
*/
- public int getId() {
+ public PrintJobId getId() {
PrintService.throwIfNotCalledOnMainThread();
return mCachedInfo.getId();
}
@@ -312,12 +313,12 @@
return false;
}
PrintJob other = (PrintJob) obj;
- return (mCachedInfo.getId() == other.mCachedInfo.getId());
+ return (mCachedInfo.getId().equals(other.mCachedInfo.getId()));
}
@Override
public int hashCode() {
- return mCachedInfo.getId();
+ return mCachedInfo.getId().hashCode();
}
private boolean isInImmutableState() {
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 0ffc40a..e5ebf77 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -20,7 +20,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -179,6 +178,14 @@
* For detailed configuration options that can be specified via the meta-data
* refer to {@link android.R.styleable#PrintService android.R.styleable.PrintService}.
* </p>
+ * <p>
+ * If you declare a settings or add a printers activity, they have to be exported,
+ * by setting the {@link android.R.attr#exported} activity attribute to <code>true
+ * </code>. Also in case you want only the system to be able to start any of these
+ * activities you can specify that they request the android.permission
+ * .START_PRINT_SERVICE_CONFIG_ACTIVITY permission by setting the
+ * {@link android.R.attr#permission} activity attribute.
+ * </p>
*/
public static final String SERVICE_META_DATA = "android.printservice";
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index b0bf3da..17cb68f 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -16,6 +16,7 @@
package android.printservice;
+import android.content.pm.ParceledListSlice;
import android.os.RemoteException;
import android.print.PrinterCapabilitiesInfo;
import android.print.PrinterId;
@@ -80,8 +81,6 @@
public abstract class PrinterDiscoverySession {
private static final String LOG_TAG = "PrinterDiscoverySession";
- private static final int MAX_ITEMS_PER_CALLBACK = 50;
-
private static int sIdCounter = 0;
private final int mId;
@@ -112,7 +111,11 @@
// If some printers were added in the method that
// created the session, send them over.
if (!mPrinters.isEmpty()) {
- sendAddedPrinters(mObserver, getPrinters());
+ try {
+ mObserver.onPrintersAdded(new ParceledListSlice<PrinterInfo>(getPrinters()));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending added printers", re);
+ }
}
}
@@ -184,7 +187,11 @@
// Send the added printers, if such.
if (addedPrinters != null) {
- sendAddedPrinters(mObserver, addedPrinters);
+ try {
+ mObserver.onPrintersAdded(new ParceledListSlice<PrinterInfo>(addedPrinters));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending added printers", re);
+ }
}
} else {
// Remember the last sent printers if needed.
@@ -203,27 +210,6 @@
}
}
- private static void sendAddedPrinters(IPrintServiceClient observer,
- List<PrinterInfo> printers) {
- try {
- final int printerCount = printers.size();
- if (printerCount <= MAX_ITEMS_PER_CALLBACK) {
- observer.onPrintersAdded(printers);
- } else {
- // Send the added printers in chunks avoiding the binder transaction limit.
- final int transactionCount = (printerCount / MAX_ITEMS_PER_CALLBACK) + 1;
- for (int i = 0; i < transactionCount; i++) {
- final int start = i * MAX_ITEMS_PER_CALLBACK;
- final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerCount);
- List<PrinterInfo> subPrinters = printers.subList(start, end);
- observer.onPrintersAdded(subPrinters);
- }
- }
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error sending added printers", re);
- }
- }
-
/**
* Removes added printers. Removing an already removed or never added
* printer has no effect. Removed printers can be added again. You can
@@ -261,7 +247,12 @@
// Send the removed printers, if such.
if (!removedPrinterIds.isEmpty()) {
- sendRemovedPrinters(mObserver, removedPrinterIds);
+ try {
+ mObserver.onPrintersRemoved(new ParceledListSlice<PrinterId>(
+ removedPrinterIds));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending removed printers", re);
+ }
}
} else {
// Remember the last sent printers if needed.
@@ -278,26 +269,6 @@
}
}
- private static void sendRemovedPrinters(IPrintServiceClient observer,
- List<PrinterId> printerIds) {
- try {
- final int printerIdCount = printerIds.size();
- if (printerIdCount <= MAX_ITEMS_PER_CALLBACK) {
- observer.onPrintersRemoved(printerIds);
- } else {
- final int transactionCount = (printerIdCount / MAX_ITEMS_PER_CALLBACK) + 1;
- for (int i = 0; i < transactionCount; i++) {
- final int start = i * MAX_ITEMS_PER_CALLBACK;
- final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerIdCount);
- List<PrinterId> subPrinterIds = printerIds.subList(start, end);
- observer.onPrintersRemoved(subPrinterIds);
- }
- }
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error sending removed printers", re);
- }
- }
-
private void sendOutOfDiscoveryPeriodPrinterChanges() {
// Noting changed since the last discovery period - nothing to do.
if (mLastSentPrinters == null || mLastSentPrinters.isEmpty()) {
@@ -319,7 +290,11 @@
// Send the added printers, if such.
if (addedPrinters != null) {
- sendAddedPrinters(mObserver, addedPrinters);
+ try {
+ mObserver.onPrintersAdded(new ParceledListSlice<PrinterInfo>(addedPrinters));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending added printers", re);
+ }
}
// Determine the removed printers.
@@ -335,7 +310,11 @@
// Send the removed printers, if such.
if (removedPrinterIds != null) {
- sendRemovedPrinters(mObserver, removedPrinterIds);
+ try {
+ mObserver.onPrintersRemoved(new ParceledListSlice<PrinterId>(removedPrinterIds));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending removed printers", re);
+ }
}
mLastSentPrinters = null;
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 9d52c83..a6f23a8 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -137,8 +137,18 @@
public static final String NUMBER = "number";
/**
- * The number presenting rules set by the network for "allowed",
- * "payphone", "restricted" or "unknown".
+ * The number presenting rules set by the network.
+ *
+ * <p>
+ * Allowed values:
+ * <ul>
+ * <li>{@link #PRESENTATION_ALLOWED}</li>
+ * <li>{@link #PRESENTATION_RESTRICTED}</li>
+ * <li>{@link #PRESENTATION_UNKNOWN}</li>
+ * <li>{@link #PRESENTATION_PAYPHONE}</li>
+ * </ul>
+ * </p>
+ *
* <P>Type: INTEGER</P>
*/
public static final String NUMBER_PRESENTATION = "presentation";
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index eaa4f78..3f33e80 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -19,6 +19,7 @@
import static android.net.TrafficStats.KB_IN_BYTES;
import static libcore.io.OsConstants.SEEK_SET;
+import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -34,16 +35,18 @@
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.OnCloseListener;
+import android.os.RemoteException;
import android.util.Log;
import com.google.android.collect.Lists;
import libcore.io.ErrnoException;
-import libcore.io.IoBridge;
import libcore.io.IoUtils;
import libcore.io.Libcore;
+import java.io.BufferedInputStream;
import java.io.FileDescriptor;
+import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
@@ -61,9 +64,9 @@
// content://com.example/root/
// content://com.example/root/sdcard/
// content://com.example/root/sdcard/recent/
+ // content://com.example/root/sdcard/search/?query=pony
// content://com.example/document/12/
// content://com.example/document/12/children/
- // content://com.example/document/12/search/?query=pony
private DocumentsContract() {
}
@@ -77,6 +80,11 @@
public static final String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT";
/**
+ * Buffer is large enough to rewind past any EXIF headers.
+ */
+ private static final int THUMBNAIL_BUFFER_SIZE = (int) (128 * KB_IN_BYTES);
+
+ /**
* Constants related to a document, including {@link Cursor} columns names
* and flags.
* <p>
@@ -166,7 +174,6 @@
* @see #FLAG_SUPPORTS_THUMBNAIL
* @see #FLAG_DIR_PREFERS_GRID
* @see #FLAG_DIR_SUPPORTS_CREATE
- * @see #FLAG_DIR_SUPPORTS_SEARCH
*/
public static final String COLUMN_FLAGS = "flags";
@@ -233,16 +240,6 @@
public static final int FLAG_DIR_SUPPORTS_CREATE = 1 << 3;
/**
- * Flag indicating that a directory supports search. Only valid when
- * {@link #COLUMN_MIME_TYPE} is {@link #MIME_TYPE_DIR}.
- *
- * @see #COLUMN_FLAGS
- * @see DocumentsProvider#querySearchDocuments(String, String,
- * String[])
- */
- public static final int FLAG_DIR_SUPPORTS_SEARCH = 1 << 4;
-
- /**
* Flag indicating that a directory prefers its contents be shown in a
* larger format grid. Usually suitable when a directory contains mostly
* pictures. Only valid when {@link #COLUMN_MIME_TYPE} is
@@ -250,7 +247,7 @@
*
* @see #COLUMN_FLAGS
*/
- public static final int FLAG_DIR_PREFERS_GRID = 1 << 5;
+ public static final int FLAG_DIR_PREFERS_GRID = 1 << 4;
/**
* Flag indicating that a directory prefers its contents be sorted by
@@ -259,7 +256,19 @@
*
* @see #COLUMN_FLAGS
*/
- public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 1 << 6;
+ public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 1 << 5;
+
+ /**
+ * Flag indicating that document titles should be hidden when viewing
+ * this directory in a larger format grid. For example, a directory
+ * containing only images may want the image thumbnails to speak for
+ * themselves. Only valid when {@link #COLUMN_MIME_TYPE} is
+ * {@link #MIME_TYPE_DIR}.
+ *
+ * @see #COLUMN_FLAGS
+ * @see #FLAG_DIR_PREFERS_GRID
+ */
+ public static final int FLAG_DIR_HIDE_GRID_TITLES = 1 << 6;
}
/**
@@ -298,9 +307,12 @@
* <p>
* Type: INTEGER (int)
*
+ * @see #FLAG_ADVANCED
+ * @see #FLAG_EMPTY
* @see #FLAG_LOCAL_ONLY
* @see #FLAG_SUPPORTS_CREATE
- * @see #FLAG_ADVANCED
+ * @see #FLAG_SUPPORTS_RECENTS
+ * @see #FLAG_SUPPORTS_SEARCH
*/
public static final String COLUMN_FLAGS = "flags";
@@ -414,6 +426,27 @@
* @see DocumentsContract#buildRecentDocumentsUri(String, String)
*/
public static final int FLAG_SUPPORTS_RECENTS = 1 << 3;
+
+ /**
+ * Flag indicating that this root supports search.
+ *
+ * @see #COLUMN_FLAGS
+ * @see DocumentsProvider#querySearchDocuments(String, String,
+ * String[])
+ */
+ public static final int FLAG_SUPPORTS_SEARCH = 1 << 4;
+
+ /**
+ * Flag indicating that this root is currently empty. This may be used
+ * to hide the root when opening documents, but the root will still be
+ * shown when creating documents and {@link #FLAG_SUPPORTS_CREATE} is
+ * also set.
+ *
+ * @see #COLUMN_FLAGS
+ * @see DocumentsProvider#querySearchDocuments(String, String,
+ * String[])
+ */
+ public static final int FLAG_EMPTY = 1 << 5;
}
/**
@@ -459,6 +492,7 @@
private static final String PATH_SEARCH = "search";
private static final String PARAM_QUERY = "query";
+ private static final String PARAM_MANAGE = "manage";
/**
* Build Uri representing the roots of a document provider. When queried, a
@@ -484,9 +518,9 @@
}
/**
- * Build Uri representing the recently modified documents of a specific
- * root. When queried, a provider will return zero or more rows with columns
- * defined by {@link Document}.
+ * Build Uri representing the recently modified documents of a specific root
+ * in a document provider. When queried, a provider will return zero or more
+ * rows with columns defined by {@link Document}.
*
* @see DocumentsProvider#queryRecentDocuments(String, String[])
* @see #getRootId(Uri)
@@ -529,21 +563,17 @@
/**
* Build Uri representing a search for matching documents under a specific
- * directory in a document provider. When queried, a provider will return
- * zero or more rows with columns defined by {@link Document}.
+ * root in a document provider. When queried, a provider will return zero or
+ * more rows with columns defined by {@link Document}.
*
- * @param parentDocumentId the document to return children for, which must
- * be both a directory with MIME type of
- * {@link Document#MIME_TYPE_DIR} and have
- * {@link Document#FLAG_DIR_SUPPORTS_SEARCH} set.
* @see DocumentsProvider#querySearchDocuments(String, String, String[])
- * @see #getDocumentId(Uri)
+ * @see #getRootId(Uri)
* @see #getSearchDocumentsQuery(Uri)
*/
public static Uri buildSearchDocumentsUri(
- String authority, String parentDocumentId, String query) {
+ String authority, String rootId, String query) {
return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority)
- .appendPath(PATH_DOCUMENT).appendPath(parentDocumentId).appendPath(PATH_SEARCH)
+ .appendPath(PATH_ROOT).appendPath(rootId).appendPath(PATH_SEARCH)
.appendQueryParameter(PARAM_QUERY, query).build();
}
@@ -583,6 +613,16 @@
return searchDocumentsUri.getQueryParameter(PARAM_QUERY);
}
+ /** {@hide} */
+ public static Uri setManageMode(Uri uri) {
+ return uri.buildUpon().appendQueryParameter(PARAM_MANAGE, "true").build();
+ }
+
+ /** {@hide} */
+ public static boolean isManageMode(Uri uri) {
+ return uri.getBooleanQueryParameter(PARAM_MANAGE, false);
+ }
+
/**
* Return list of all documents that the calling package has "open." These
* are Uris matching {@link DocumentsContract} to which persistent
@@ -631,35 +671,47 @@
*/
public static Bitmap getDocumentThumbnail(
ContentResolver resolver, Uri documentUri, Point size, CancellationSignal signal) {
+ final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+ documentUri.getAuthority());
+ try {
+ return getDocumentThumbnail(client, documentUri, size, signal);
+ } catch (RemoteException e) {
+ return null;
+ } finally {
+ ContentProviderClient.closeQuietly(client);
+ }
+ }
+
+ /** {@hide} */
+ public static Bitmap getDocumentThumbnail(
+ ContentProviderClient client, Uri documentUri, Point size, CancellationSignal signal)
+ throws RemoteException {
final Bundle openOpts = new Bundle();
openOpts.putParcelable(DocumentsContract.EXTRA_THUMBNAIL_SIZE, size);
AssetFileDescriptor afd = null;
try {
- afd = resolver.openTypedAssetFileDescriptor(documentUri, "image/*", openOpts, signal);
+ afd = client.openTypedAssetFileDescriptor(documentUri, "image/*", openOpts, signal);
final FileDescriptor fd = afd.getFileDescriptor();
final long offset = afd.getStartOffset();
- final long length = afd.getDeclaredLength();
- // Some thumbnails might be a region inside a larger file, such as
- // an EXIF thumbnail. Since BitmapFactory aggressively seeks around
- // the entire file, we read the region manually.
- byte[] region = null;
- if (offset > 0 && length <= 64 * KB_IN_BYTES) {
- region = new byte[(int) length];
+ // Try seeking on the returned FD, since it gives us the most
+ // optimal decode path; otherwise fall back to buffering.
+ BufferedInputStream is = null;
+ try {
Libcore.os.lseek(fd, offset, SEEK_SET);
- if (IoBridge.read(fd, region, 0, region.length) != region.length) {
- region = null;
- }
+ } catch (ErrnoException e) {
+ is = new BufferedInputStream(new FileInputStream(fd), THUMBNAIL_BUFFER_SIZE);
+ is.mark(THUMBNAIL_BUFFER_SIZE);
}
// We requested a rough thumbnail size, but the remote size may have
// returned something giant, so defensively scale down as needed.
final BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
- if (region != null) {
- BitmapFactory.decodeByteArray(region, 0, region.length, opts);
+ if (is != null) {
+ BitmapFactory.decodeStream(is, null, opts);
} else {
BitmapFactory.decodeFileDescriptor(fd, null, opts);
}
@@ -670,14 +722,17 @@
opts.inJustDecodeBounds = false;
opts.inSampleSize = Math.min(widthSample, heightSample);
Log.d(TAG, "Decoding with sample size " + opts.inSampleSize);
- if (region != null) {
- return BitmapFactory.decodeByteArray(region, 0, region.length, opts);
+ if (is != null) {
+ is.reset();
+ return BitmapFactory.decodeStream(is, null, opts);
} else {
+ try {
+ Libcore.os.lseek(fd, offset, SEEK_SET);
+ } catch (ErrnoException e) {
+ e.rethrowAsIOException();
+ }
return BitmapFactory.decodeFileDescriptor(fd, null, opts);
}
- } catch (ErrnoException e) {
- Log.w(TAG, "Failed to load thumbnail for " + documentUri + ": " + e);
- return null;
} catch (IOException e) {
Log.w(TAG, "Failed to load thumbnail for " + documentUri + ": " + e);
return null;
@@ -694,16 +749,29 @@
* @param mimeType MIME type of new document
* @param displayName name of new document
* @return newly created document, or {@code null} if failed
+ * @hide
*/
public static Uri createDocument(ContentResolver resolver, Uri parentDocumentUri,
String mimeType, String displayName) {
+ final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+ parentDocumentUri.getAuthority());
+ try {
+ return createDocument(client, parentDocumentUri, mimeType, displayName);
+ } finally {
+ ContentProviderClient.closeQuietly(client);
+ }
+ }
+
+ /** {@hide} */
+ public static Uri createDocument(ContentProviderClient client, Uri parentDocumentUri,
+ String mimeType, String displayName) {
final Bundle in = new Bundle();
in.putString(Document.COLUMN_DOCUMENT_ID, getDocumentId(parentDocumentUri));
in.putString(Document.COLUMN_MIME_TYPE, mimeType);
in.putString(Document.COLUMN_DISPLAY_NAME, displayName);
try {
- final Bundle out = resolver.call(parentDocumentUri, METHOD_CREATE_DOCUMENT, null, in);
+ final Bundle out = client.call(METHOD_CREATE_DOCUMENT, null, in);
return buildDocumentUri(
parentDocumentUri.getAuthority(), out.getString(Document.COLUMN_DOCUMENT_ID));
} catch (Exception e) {
@@ -718,11 +786,22 @@
* @param documentUri document with {@link Document#FLAG_SUPPORTS_DELETE}
*/
public static boolean deleteDocument(ContentResolver resolver, Uri documentUri) {
+ final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+ documentUri.getAuthority());
+ try {
+ return deleteDocument(client, documentUri);
+ } finally {
+ ContentProviderClient.closeQuietly(client);
+ }
+ }
+
+ /** {@hide} */
+ public static boolean deleteDocument(ContentProviderClient client, Uri documentUri) {
final Bundle in = new Bundle();
in.putString(Document.COLUMN_DOCUMENT_ID, getDocumentId(documentUri));
try {
- final Bundle out = resolver.call(documentUri, METHOD_DELETE_DOCUMENT, null, in);
+ final Bundle out = client.call(METHOD_DELETE_DOCUMENT, null, in);
return true;
} catch (Exception e) {
Log.w(TAG, "Failed to delete document", e);
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 1b0fc4d..bc4e28b 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -75,9 +75,9 @@
private static final int MATCH_ROOTS = 1;
private static final int MATCH_ROOT = 2;
private static final int MATCH_RECENT = 3;
- private static final int MATCH_DOCUMENT = 4;
- private static final int MATCH_CHILDREN = 5;
- private static final int MATCH_SEARCH = 6;
+ private static final int MATCH_SEARCH = 4;
+ private static final int MATCH_DOCUMENT = 5;
+ private static final int MATCH_CHILDREN = 6;
private String mAuthority;
@@ -94,9 +94,9 @@
mMatcher.addURI(mAuthority, "root", MATCH_ROOTS);
mMatcher.addURI(mAuthority, "root/*", MATCH_ROOT);
mMatcher.addURI(mAuthority, "root/*/recent", MATCH_RECENT);
+ mMatcher.addURI(mAuthority, "root/*/search", MATCH_SEARCH);
mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT);
mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN);
- mMatcher.addURI(mAuthority, "document/*/search", MATCH_SEARCH);
// Sanity check our setup
if (!info.exported) {
@@ -167,14 +167,21 @@
String parentDocumentId, String[] projection, String sortOrder)
throws FileNotFoundException;
+ /** {@hide} */
+ @SuppressWarnings("unused")
+ public Cursor queryChildDocumentsForManage(
+ String parentDocumentId, String[] projection, String sortOrder)
+ throws FileNotFoundException {
+ throw new UnsupportedOperationException("Manage not supported");
+ }
+
/**
- * Return documents that that match the given query, starting the search at
- * the given directory.
+ * Return documents that that match the given query.
*
- * @param parentDocumentId the directory to start search at.
+ * @param rootId the root to search under.
*/
@SuppressWarnings("unused")
- public Cursor querySearchDocuments(String parentDocumentId, String query, String[] projection)
+ public Cursor querySearchDocuments(String rootId, String query, String[] projection)
throws FileNotFoundException {
throw new UnsupportedOperationException("Search not supported");
}
@@ -259,13 +266,18 @@
return queryRoots(projection);
case MATCH_RECENT:
return queryRecentDocuments(getRootId(uri), projection);
+ case MATCH_SEARCH:
+ return querySearchDocuments(
+ getRootId(uri), getSearchDocumentsQuery(uri), projection);
case MATCH_DOCUMENT:
return queryDocument(getDocumentId(uri), projection);
case MATCH_CHILDREN:
- return queryChildDocuments(getDocumentId(uri), projection, sortOrder);
- case MATCH_SEARCH:
- return querySearchDocuments(
- getDocumentId(uri), getSearchDocumentsQuery(uri), projection);
+ if (DocumentsContract.isManageMode(uri)) {
+ return queryChildDocumentsForManage(
+ getDocumentId(uri), projection, sortOrder);
+ } else {
+ return queryChildDocuments(getDocumentId(uri), projection, sortOrder);
+ }
default:
throw new UnsupportedOperationException("Unsupported Uri " + uri);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1a80818..6c6635d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -160,6 +160,38 @@
"android.settings.SECURITY_SETTINGS";
/**
+ * Activity Action: Show trusted credentials settings, opening to the user tab,
+ * to allow management of installed credentials.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_TRUSTED_CREDENTIALS_USER =
+ "com.android.settings.TRUSTED_CREDENTIALS_USER";
+
+ /**
+ * Activity Action: Show dialog explaining that an installed CA cert may enable
+ * monitoring of encrypted network traffic.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MONITORING_CERT_INFO =
+ "com.android.settings.MONITORING_CERT_INFO";
+
+ /**
* Activity Action: Show settings to allow configuration of privacy options.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -2439,7 +2471,9 @@
SIP_CALL_OPTIONS,
SIP_RECEIVE_CALLS,
POINTER_SPEED,
- VIBRATE_WHEN_RINGING
+ VIBRATE_WHEN_RINGING,
+ RINGTONE,
+ NOTIFICATION_SOUND
};
// Settings moved to Settings.Secure
@@ -3333,7 +3367,9 @@
*/
public static final int LOCATION_MODE_SENSORS_ONLY = 1;
/**
- * Reduced power usage, such as limiting the number of GPS updates per hour.
+ * Reduced power usage, such as limiting the number of GPS updates per hour. Requests
+ * with {@link android.location.Criteria#POWER_HIGH} may be downgraded to
+ * {@link android.location.Criteria#POWER_MEDIUM}.
*/
public static final int LOCATION_MODE_BATTERY_SAVING = 2;
/**
@@ -4319,6 +4355,12 @@
public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
/**
+ * Specifies the package name currently configured to be the primary sms application
+ * @hide
+ */
+ public static final String SMS_DEFAULT_APPLICATION = "sms_default_application";
+
+ /**
* Name of a package that the current user has explicitly allowed to see all of that
* user's notifications.
*
@@ -4329,6 +4371,9 @@
/** @hide */
public static final String BAR_SERVICE_COMPONENT = "bar_service_component";
+ /** @hide */
+ public static final String TRANSIENT_NAV_CONFIRMATIONS = "transient_nav_confirmations";
+
/**
* This are the settings to be backed up.
*
@@ -4382,10 +4427,13 @@
/**
* Helper method for determining if a location provider is enabled.
+ *
* @param cr the content resolver to use
* @param provider the location provider to query
* @return true if the provider is enabled
- * @deprecated use {@link #getInt(ContentResolver, String)} and {@link #LOCATION_MODE}
+ *
+ * @deprecated use {@link #LOCATION_MODE} or
+ * {@link LocationManager#isProviderEnabled(String)}
*/
@Deprecated
public static final boolean isLocationProviderEnabled(ContentResolver cr, String provider) {
@@ -4398,8 +4446,8 @@
* @param provider the location provider to query
* @param userId the userId to query
* @return true if the provider is enabled
- * @deprecated use {@link #getIntForUser(ContentResolver, String, int, int)} and
- * {@link #LOCATION_MODE}
+ * @deprecated use {@link #LOCATION_MODE} or
+ * {@link LocationManager#isProviderEnabled(String)}
* @hide
*/
@Deprecated
@@ -5635,6 +5683,9 @@
/** {@hide} */
public static final String
BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX = "bluetooth_input_device_priority_";
+ /** {@hide} */
+ public static final String
+ BLUETOOTH_MAP_PRIORITY_PREFIX = "bluetooth_map_priority_";
/**
* Get the key that retrieves a bluetooth headset's priority.
@@ -5661,6 +5712,13 @@
}
/**
+ * Get the key that retrieves a bluetooth map priority.
+ * @hide
+ */
+ public static final String getBluetoothMapPriorityKey(String address) {
+ return BLUETOOTH_MAP_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
+ }
+ /**
* Scaling factor for normal window animations. Setting to 0 will
* disable window animations.
*/
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index 457e66c..e991d84 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -55,7 +55,10 @@
* <p>Starting this intent with just {@link Activity#startActivity(Intent)} is not supported.
* You must either use {@link Activity#startActivityForResult(Intent, int)}, or provide a
* PendingIntent, to receive recognition results.
- *
+ *
+ * <p>The implementation of this API is likely to stream audio to remote servers to perform
+ * speech recognition which can use a substantial amount of bandwidth.
+ *
* <p>Required extras:
* <ul>
* <li>{@link #EXTRA_LANGUAGE_MODEL}
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 8fee41d..94aedbd 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -39,8 +39,14 @@
* This class provides access to the speech recognition service. This service allows access to the
* speech recognizer. Do not instantiate this class directly, instead, call
* {@link SpeechRecognizer#createSpeechRecognizer(Context)}. This class's methods must be
- * invoked only from the main application thread. Please note that the application must have
- * {@link android.Manifest.permission#RECORD_AUDIO} permission to use this class.
+ * invoked only from the main application thread.
+ *
+ * <p>The implementation of this API is likely to stream audio to remote servers to perform speech
+ * recognition. As such this API is not intended to be used for continuous recognition, which would
+ * consume a significant amount of battery and bandwidth.
+ *
+ * <p>Please note that the application must have {@link android.Manifest.permission#RECORD_AUDIO}
+ * permission to use this class.
*/
public class SpeechRecognizer {
/** DEBUG value to enable verbose debug prints */
diff --git a/core/java/android/speech/hotword/HotwordRecognitionListener.java b/core/java/android/speech/hotword/HotwordRecognitionListener.java
deleted file mode 100644
index 8a32654..0000000
--- a/core/java/android/speech/hotword/HotwordRecognitionListener.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package android.speech.hotword;
-
-import android.content.Intent;
-import android.os.Bundle;
-
-/**
- * Used for receiving notifications from the HotwordRecognitionService when the
- * hotword recognition related events occur.
- * All the callbacks are executed on the application main thread.
- * {@hide}
- */
-public interface HotwordRecognitionListener {
- /**
- * Called when the service starts listening for hotword.
- */
- void onHotwordRecognitionStarted();
-
- /**
- * Called when the service stops listening for hotword.
- */
- void onHotwordRecognitionStopped();
-
- /**
- * Called on an event of interest to the client.
- *
- * @param eventType the event type.
- * @param eventBundle a Bundle containing the hotword event(s).
- */
- void onHotwordEvent(int eventType, Bundle eventBundle);
-
- /**
- * Called back when hotword is detected.
- *
- * @param intent for the activity to launch, post hotword detection.
- */
- void onHotwordRecognized(Intent intent);
-
- /**
- * Called when the HotwordRecognitionService encounters an error.
- *
- * @param errorCode the error code describing the error that was encountered.
- */
- void onHotwordError(int errorCode);
-}
\ No newline at end of file
diff --git a/core/java/android/speech/hotword/HotwordRecognitionService.java b/core/java/android/speech/hotword/HotwordRecognitionService.java
deleted file mode 100644
index 9a59f19..0000000
--- a/core/java/android/speech/hotword/HotwordRecognitionService.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package android.speech.hotword;
-
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.Log;
-
-/**
- * This class provides a base class for hotword detection service implementations.
- * This class should be extended only if you wish to implement a new hotword recognizer.
- */
-public abstract class HotwordRecognitionService extends Service {
- /**
- * The {@link Intent} that must be declared as handled by the service.
- */
- @SdkConstant(SdkConstantType.SERVICE_ACTION)
- public static final String SERVICE_INTERFACE =
- "android.speech.hotword.HotwordRecognitionService";
-
- /** Log messages identifier */
- private static final String TAG = "HotwordRecognitionService";
-
- /** Debugging flag */
- private static final boolean DBG = false;
-
- /**
- * Key used to retrieve a string to be displayed to the user passed to the
- * {@link android.speech.hotword.HotwordRecognitionListener#onHotwordEvent(int, Bundle)} method.
- */
- public static final String KEY_PROMPT_TEXT = "prompt_text";
-
- /**
- * Event type used to indicate to the user that the prompt for
- * hotword recognition has changed.
- */
- public static final int EVENT_TYPE_PROMPT_CHANGED = 1;
-
- /** Audio recording error. */
- public static final int ERROR_AUDIO = 1;
-
- /** RecognitionService busy. */
- public static final int ERROR_RECOGNIZER_BUSY = 2;
-
- /** This indicates a permanent failure and the clients shouldn't retry on this */
- public static final int ERROR_FAILED = 3;
-
- /** Client-side errors */
- public static final int ERROR_CLIENT = 4;
-
- /** The service timed out */
- public static final int ERROR_TIMEOUT = 5;
-
- /** The service received concurrent start calls */
- public static final int ERROR_SERVICE_ALREADY_STARTED = 6;
-
- /** Hotword recognition is unavailable on the device */
- public static final int ERROR_UNAVAILABLE = 7;
-
- private static final int MSG_START_RECOGNITION = 1;
- private static final int MSG_STOP_RECOGNITION = 2;
-
- /**
- * The current callback of an application that invoked the
- * {@link HotwordRecognitionService#onStartHotwordRecognition(Callback)} method
- */
- private Callback mCurrentCallback = null;
-
- // Handle the client dying.
- private final IBinder.DeathRecipient mCallbackDeathRecipient = new IBinder.DeathRecipient() {
- @Override
- public void binderDied() {
- if (DBG) Log.i(TAG, "HotwordRecognitionService listener died");
- mCurrentCallback = null;
- }
- };
-
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_START_RECOGNITION:
- dispatchStartRecognition((IHotwordRecognitionListener) msg.obj);
- break;
- case MSG_STOP_RECOGNITION:
- dispatchStopRecognition((IHotwordRecognitionListener) msg.obj);
- break;
- }
- }
- };
-
- /** Binder of the hotword recognition service */
- private RecognitionServiceBinder mBinder = new RecognitionServiceBinder(this);
-
- private void dispatchStartRecognition(IHotwordRecognitionListener listener) {
- if (mCurrentCallback == null) {
- if (DBG) Log.d(TAG, "created new mCurrentCallback, listener = " + listener.asBinder());
- try {
- listener.asBinder().linkToDeath(mCallbackDeathRecipient, 0);
- } catch (RemoteException e) {
- if (DBG) Log.d(TAG, "listener died before linkToDeath()");
- }
- mCurrentCallback = new Callback(listener);
- HotwordRecognitionService.this.onStartHotwordRecognition(mCurrentCallback);
- } else {
- try {
- listener.onHotwordError(ERROR_RECOGNIZER_BUSY);
- } catch (RemoteException e) {
- if (DBG) Log.d(TAG, "onError call from startRecognition failed");
- }
- if (DBG) Log.d(TAG, "concurrent startRecognition received - ignoring this call");
- }
- }
-
- private void dispatchStopRecognition(IHotwordRecognitionListener listener) {
- try {
- if (mCurrentCallback == null) {
- listener.onHotwordError(ERROR_CLIENT);
- Log.w(TAG, "stopRecognition called with no preceding startRecognition - ignoring");
- } else if (mCurrentCallback.mListener.asBinder() != listener.asBinder()) {
- listener.onHotwordError(ERROR_RECOGNIZER_BUSY);
- Log.w(TAG, "stopRecognition called by a different caller - ignoring");
- } else { // the correct state
- mCurrentCallback.onHotwordRecognitionStopped();
- mCurrentCallback = null;
- HotwordRecognitionService.this.onStopHotwordRecognition();
- }
- } catch (RemoteException e) { // occurs if onError fails
- if (DBG) Log.d(TAG, "onError call from stopRecognition failed");
- }
- }
-
- @Override
- public IBinder onBind(final Intent intent) {
- if (DBG) Log.d(TAG, "onBind, intent=" + intent);
- return mBinder;
- }
-
- @Override
- public void onDestroy() {
- if (DBG) Log.d(TAG, "onDestroy");
- if (mCurrentCallback != null) {
- mCurrentCallback.mListener.asBinder().unlinkToDeath(mCallbackDeathRecipient, 0);
- mCurrentCallback = null;
- }
- mBinder.clearReference();
- super.onDestroy();
- }
-
- /**
- * Notifies the service to start a recognition.
- *
- * @param callback that receives the callbacks from the service.
- */
- public abstract void onStartHotwordRecognition(Callback callback);
-
- /**
- * Notifies the service to stop recognition.
- */
- public abstract void onStopHotwordRecognition();
-
- /** Binder of the hotword recognition service */
- private static class RecognitionServiceBinder extends IHotwordRecognitionService.Stub {
- private HotwordRecognitionService mInternalService;
-
- public RecognitionServiceBinder(HotwordRecognitionService service) {
- mInternalService = service;
- }
-
- public void startHotwordRecognition(IHotwordRecognitionListener listener) {
- if (DBG) Log.d(TAG, "startRecognition called by: " + listener.asBinder());
- if (mInternalService != null && mInternalService.checkPermissions(listener)) {
- mInternalService.mHandler.sendMessage(
- Message.obtain(mInternalService.mHandler, MSG_START_RECOGNITION, listener));
- }
- }
-
- public void stopHotwordRecognition(IHotwordRecognitionListener listener) {
- if (DBG) Log.d(TAG, "stopRecognition called by: " + listener.asBinder());
- if (mInternalService != null && mInternalService.checkPermissions(listener)) {
- mInternalService.mHandler.sendMessage(
- Message.obtain(mInternalService.mHandler, MSG_STOP_RECOGNITION, listener));
- }
- }
-
- private void clearReference() {
- mInternalService = null;
- }
- }
-
- /**
- * Checks whether the caller has sufficient permissions
- *
- * @param listener to send the error message to in case of error.
- * @return {@code true} if the caller has enough permissions, {@code false} otherwise.
- */
- private boolean checkPermissions(IHotwordRecognitionListener listener) {
- if (DBG) Log.d(TAG, "checkPermissions");
- if (checkCallingOrSelfPermission(android.Manifest.permission.HOTWORD_RECOGNITION) ==
- PackageManager.PERMISSION_GRANTED) {
- return true;
- }
- try {
- Log.e(TAG, "Recognition service called without HOTWORD_RECOGNITION permissions");
- listener.onHotwordError(ERROR_FAILED);
- } catch (RemoteException e) {
- Log.e(TAG, "onHotwordError(ERROR_FAILED) message failed", e);
- }
- return false;
- }
-
- /**
- * This class acts passes on the callbacks received from the Hotword service
- * to the listener.
- */
- public static class Callback {
- private final IHotwordRecognitionListener mListener;
-
- private Callback(IHotwordRecognitionListener listener) {
- mListener = listener;
- }
-
- /**
- * Called when the service starts listening for hotword.
- */
- public void onHotwordRecognitionStarted() throws RemoteException {
- mListener.onHotwordRecognitionStarted();
- }
-
- /**
- * Called when the service starts listening for hotword.
- */
- public void onHotwordRecognitionStopped() throws RemoteException {
- mListener.onHotwordRecognitionStopped();
- }
-
- /**
- * Called on an event of interest to the client.
- *
- * @param eventType the event type.
- * @param eventBundle a Bundle containing the hotword event(s).
- */
- public void onHotwordEvent(int eventType, Bundle eventBundle) throws RemoteException {
- mListener.onHotwordEvent(eventType, eventBundle);
- }
-
- /**
- * Called back when hotword is detected.
- *
- * @param activityIntent for the activity to launch, post hotword detection.
- */
- public void onHotwordRecognized(Intent activityIntent) throws RemoteException {
- mListener.onHotwordRecognized(activityIntent);
- }
-
- /**
- * Called when the HotwordRecognitionService encounters an error.
- *
- * @param errorCode the error code describing the error that was encountered.
- */
- public void onError(int errorCode) throws RemoteException {
- mListener.onHotwordError(errorCode);
- }
- }
-}
diff --git a/core/java/android/speech/hotword/HotwordRecognizer.java b/core/java/android/speech/hotword/HotwordRecognizer.java
deleted file mode 100644
index 9f05f31..0000000
--- a/core/java/android/speech/hotword/HotwordRecognizer.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package android.speech.hotword;
-
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Queue;
-
-/**
- * This class provides access to the Hotword recognition service.
- * This class's methods must be invoked on the main application thread.
- * {@hide}
- */
-public class HotwordRecognizer {
- /** DEBUG value to enable verbose debug prints */
- private final static boolean DBG = false;
-
- /** Log messages identifier */
- private static final String TAG = "HotwordRecognizer";
-
- /** action codes */
- private static final int MSG_START = 1;
- private static final int MSG_STOP = 2;
-
- /** The underlying HotwordRecognitionService endpoint */
- private IHotwordRecognitionService mService;
-
- /** The connection to the actual service */
- private Connection mConnection;
-
- /** Context with which the manager was created */
- private final Context mContext;
-
- /** Component to direct service intent to */
- private final ComponentName mServiceComponent;
-
- /** Handler that will execute the main tasks */
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_START:
- handleStartRecognition();
- break;
- case MSG_STOP:
- handleStopRecognition();
- break;
- }
- }
- };
-
- /**
- * Temporary queue, saving the messages until the connection will be established, afterwards,
- * only mHandler will receive the messages
- */
- private final Queue<Message> mPendingTasks = new LinkedList<Message>();
-
- /** The Listener that will receive all the callbacks */
- private final InternalListener mListener = new InternalListener();
-
- /**
- * Checks whether a hotword recognition service is available on the system. If this method
- * returns {@code false}, {@link HotwordRecognizer#createHotwordRecognizer(Context)} will
- * fail.
- *
- * @param context with which {@code HotwordRecognizer} will be created
- * @return {@code true} if recognition is available, {@code false} otherwise
- */
- public static boolean isHotwordRecognitionAvailable(final Context context) {
- final List<ResolveInfo> list = context.getPackageManager().queryIntentServices(
- new Intent(HotwordRecognitionService.SERVICE_INTERFACE), 0);
- return list != null && list.size() != 0;
- }
-
- /**
- * Factory method to create a new {@code HotwordRecognizer}.
- *
- * @param context in which to create {@code HotwordRecognizer}
- * @return a new {@code HotwordRecognizer}
- */
- public static HotwordRecognizer createHotwordRecognizer(final Context context) {
- ComponentName serviceComponent = null;
- // Resolve to a default ComponentName.
- final List<ResolveInfo> list = context.getPackageManager().queryIntentServices(
- new Intent(HotwordRecognitionService.SERVICE_INTERFACE), 0);
- for (int i = 0; i < list.size(); i++) {
- final ResolveInfo ri = list.get(i);
- if (!ri.serviceInfo.enabled) {
- continue;
- }
- if ((ri.serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM)
- != PackageManager.MATCH_DEFAULT_ONLY) {
- serviceComponent = new ComponentName(
- ri.serviceInfo.packageName, ri.serviceInfo.name);
- break;
- }
- }
- // If all else fails, pick the first one.
- if (serviceComponent == null && !list.isEmpty()) {
- serviceComponent = new ComponentName(
- list.get(0).serviceInfo.packageName, list.get(0).serviceInfo.name);
- }
- return createHotwordRecognizer(context, serviceComponent);
- }
-
- /**
- * Factory method to create a new {@code HotwordRecognizer}.
- *
- * Use this version of the method to specify a specific service to direct this
- * {@link HotwordRecognizer} to. Normally you would not use this; use
- * {@link #createHotwordRecognizer(Context)} instead to use the system default recognition
- * service.
- *
- * @param context in which to create {@code HotwordRecognizer}
- * @param serviceComponent the {@link ComponentName} of a specific service to direct this
- * {@code HotwordRecognizer} to
- * @return a new {@code HotwordRecognizer}
- */
- public static HotwordRecognizer createHotwordRecognizer(
- final Context context, final ComponentName serviceComponent) {
- if (context == null) {
- throw new IllegalArgumentException("Context cannot be null)");
- }
- checkIsCalledFromMainThread();
- return new HotwordRecognizer(context, serviceComponent);
- }
-
- /**
- * Starts recognizing hotword and sets the listener that will receive the callbacks.
- *
- * @param listener listener that will receive all the callbacks from the created
- * {@link HotwordRecognizer}, this must not be null.
- */
- public void startRecognition(HotwordRecognitionListener listener) {
- checkIsCalledFromMainThread();
- if (mConnection == null) { // first time connection
- if (listener == null) {
- throw new IllegalArgumentException("listener must not be null");
- }
-
- mConnection = new Connection();
- Intent serviceIntent = new Intent(HotwordRecognitionService.SERVICE_INTERFACE);
- mListener.mInternalListener = listener;
-
- if (mServiceComponent == null) {
- Log.e(TAG, "no selected voice recognition service");
- mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
- return;
- } else {
- serviceIntent.setComponent(mServiceComponent);
- }
-
- if (!mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE)) {
- Log.e(TAG, "bind to recognition service failed");
- mConnection = null;
- mService = null;
- mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
- return;
- }
- putMessage(Message.obtain(mHandler, MSG_START));
- } else {
- mListener.onHotwordError(HotwordRecognitionService.ERROR_SERVICE_ALREADY_STARTED);
- return;
- }
- }
-
- /**
- * Stops recognizing hotword.
- */
- public void stopRecognition() {
- checkIsCalledFromMainThread();
- putMessage(Message.obtain(mHandler, MSG_STOP));
- }
-
- // Private constructor.
- private HotwordRecognizer(Context context, ComponentName serviceComponent) {
- mContext = context;
- mServiceComponent = serviceComponent;
- }
-
- private void handleStartRecognition() {
- if (!checkOpenConnection()) {
- return;
- }
- try {
- mService.startHotwordRecognition(mListener);
- if (DBG) Log.d(TAG, "service startRecognition command succeeded");
- } catch (final RemoteException e) {
- Log.e(TAG, "startRecognition() failed", e);
- mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
- }
- }
-
- private void handleStopRecognition() {
- if (!checkOpenConnection()) {
- return;
- }
- try {
- mService.stopHotwordRecognition(mListener);
- if (mConnection != null) {
- mContext.unbindService(mConnection);
- }
- if (DBG) Log.d(TAG, "service stopRecognition command succeeded");
- } catch (final RemoteException e) {
- Log.e(TAG, "stopRecognition() failed", e);
- mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
- } finally {
- mPendingTasks.clear();
- mService = null;
- mConnection = null;
- mListener.mInternalListener = null;
- }
- }
-
- private boolean checkOpenConnection() {
- if (mService != null) {
- return true;
- }
- mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
- Log.e(TAG, "not connected to the recognition service");
- return false;
- }
-
- private static void checkIsCalledFromMainThread() {
- if (Looper.myLooper() != Looper.getMainLooper()) {
- throw new RuntimeException(
- "HotwordRecognizer should be used only from the application's main thread");
- }
- }
-
- private void putMessage(Message msg) {
- if (mService == null) {
- mPendingTasks.offer(msg);
- } else {
- mHandler.sendMessage(msg);
- }
- }
-
- /**
- * Basic ServiceConnection that records the mService variable.
- * Additionally, on creation it invokes
- * {@link IHotwordRecognitionService#startHotwordRecognition(IHotwordRecognitionListener)}.
- */
- private class Connection implements ServiceConnection {
-
- public void onServiceConnected(final ComponentName name, final IBinder service) {
- // always done on the application main thread, so no need to send message to mHandler
- mService = IHotwordRecognitionService.Stub.asInterface(service);
- if (DBG) Log.d(TAG, "onServiceConnected - Success");
- while (!mPendingTasks.isEmpty()) {
- mHandler.sendMessage(mPendingTasks.poll());
- }
- }
-
- public void onServiceDisconnected(final ComponentName name) {
- // always done on the application main thread, so no need to send message to mHandler
- mService = null;
- mConnection = null;
- mPendingTasks.clear();
- if (DBG) Log.d(TAG, "onServiceDisconnected - Success");
- }
- }
-
- /**
- * Internal wrapper of IHotwordRecognitionListener which will propagate the results to
- * HotwordRecognitionListener.
- */
- private class InternalListener extends IHotwordRecognitionListener.Stub {
- private HotwordRecognitionListener mInternalListener;
-
- private final static int MSG_ON_START = 1;
- private final static int MSG_ON_STOP = 2;
- private final static int MSG_ON_EVENT = 3;
- private final static int MSG_ON_RECOGNIZED = 4;
- private final static int MSG_ON_ERROR = 5;
-
- private final Handler mInternalHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (mInternalListener == null) {
- return;
- }
- switch (msg.what) {
- case MSG_ON_START:
- mInternalListener.onHotwordRecognitionStarted();
- break;
- case MSG_ON_STOP:
- mInternalListener.onHotwordRecognitionStopped();
- break;
- case MSG_ON_EVENT:
- mInternalListener.onHotwordEvent(msg.arg1, (Bundle) msg.obj);
- break;
- case MSG_ON_RECOGNIZED:
- mInternalListener.onHotwordRecognized((Intent) msg.obj);
- break;
- case MSG_ON_ERROR:
- mInternalListener.onHotwordError((Integer) msg.obj);
- break;
- }
- }
- };
-
- @Override
- public void onHotwordRecognitionStarted() throws RemoteException {
- Message.obtain(mInternalHandler, MSG_ON_START).sendToTarget();
- }
-
- @Override
- public void onHotwordRecognitionStopped() throws RemoteException {
- Message.obtain(mInternalHandler, MSG_ON_STOP).sendToTarget();
- }
-
- @Override
- public void onHotwordEvent(final int eventType, final Bundle params) {
- Message.obtain(mInternalHandler, MSG_ON_EVENT, eventType, eventType, params)
- .sendToTarget();
- }
-
- @Override
- public void onHotwordRecognized(Intent activityIntent) throws RemoteException {
- Message.obtain(mInternalHandler, MSG_ON_RECOGNIZED, activityIntent)
- .sendToTarget();
- }
-
- @Override
- public void onHotwordError(final int error) {
- Message.obtain(mInternalHandler, MSG_ON_ERROR, error).sendToTarget();
- }
- }
-}
diff --git a/core/java/android/speech/hotword/IHotwordRecognitionListener.aidl b/core/java/android/speech/hotword/IHotwordRecognitionListener.aidl
deleted file mode 100644
index 4ea2e8e0..0000000
--- a/core/java/android/speech/hotword/IHotwordRecognitionListener.aidl
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.speech.hotword;
-
-import android.content.Intent;
-import android.os.Bundle;
-
-/**
- * Listener for hotword detection events.
- * This indicates when the hotword was detected, and also notifies the
- * client of the intermediate events that may be used to show visual feedback
- * to the user.
- * {@hide}
- */
-oneway interface IHotwordRecognitionListener {
- /**
- * Called when the service starts listening for hotword.
- */
- void onHotwordRecognitionStarted();
-
- /**
- * Called when the service starts listening for hotword.
- */
- void onHotwordRecognitionStopped();
-
- /**
- * Called on an event of interest to the client.
- *
- * @param eventType the event type.
- * @param eventBundle a Bundle containing the hotword event(s).
- */
- void onHotwordEvent(in int eventType, in Bundle eventBundle);
-
- /**
- * Called back when hotword is detected.
- *
- * @param intent for the activity to launch, post hotword detection.
- */
- void onHotwordRecognized(in Intent intent);
-
- /**
- * Called when the HotwordRecognitionService encounters an error.
- *
- * @param errorCode the error code describing the error that was encountered.
- */
- void onHotwordError(in int errorCode);
-}
diff --git a/core/java/android/speech/hotword/IHotwordRecognitionService.aidl b/core/java/android/speech/hotword/IHotwordRecognitionService.aidl
deleted file mode 100644
index 331d81c..0000000
--- a/core/java/android/speech/hotword/IHotwordRecognitionService.aidl
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.speech.hotword;
-
-import android.speech.hotword.IHotwordRecognitionListener;
-
-/**
- * A service interface to Hotword recognition.
- * Call startHotwordDetection with a listener when you want to begin detecting
- * hotword;
- * The service would automatically stop detection when hotword is detected;
- * So it's a create-once use-once service.
- * The service doesn't support nested calls to start detection and disallows them.
- * {@hide}
- */
-oneway interface IHotwordRecognitionService {
- /**
- * Start hotword recognition.
- * The clients should rely on the callback to figure out if the detection was
- * started.
- *
- * @param listener a listener to notify of hotword events.
- */
- void startHotwordRecognition(in IHotwordRecognitionListener listener);
-
- /**
- * Stop hotword recognition.
- * Stops the recognition only if it was started by the same caller.
- *
- * @param listener a listener to notify of hotword events.
- */
- void stopHotwordRecognition(in IHotwordRecognitionListener listener);
-}
diff --git a/core/java/android/text/AndroidBidi.java b/core/java/android/text/AndroidBidi.java
index eacd40d..b1c07f5 100644
--- a/core/java/android/text/AndroidBidi.java
+++ b/core/java/android/text/AndroidBidi.java
@@ -60,6 +60,9 @@
*/
public static Directions directions(int dir, byte[] levels, int lstart,
char[] chars, int cstart, int len) {
+ if (len == 0) {
+ return Layout.DIRS_ALL_LEFT_TO_RIGHT;
+ }
int baseLevel = dir == Layout.DIR_LEFT_TO_RIGHT ? 0 : 1;
int curLevel = levels[lstart];
diff --git a/core/java/android/transition/Fade.java b/core/java/android/transition/Fade.java
index 12e0d73..4cc2c42 100644
--- a/core/java/android/transition/Fade.java
+++ b/core/java/android/transition/Fade.java
@@ -91,6 +91,9 @@
return null;
}
final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", startAlpha, endAlpha);
+ if (DBG) {
+ Log.d(LOG_TAG, "Created animator " + anim);
+ }
if (listener != null) {
anim.addListener(listener);
anim.addPauseListener(listener);
@@ -146,12 +149,41 @@
final View endView = endValues.view;
if (DBG) {
View startView = (startValues != null) ? startValues.view : null;
- Log.d(LOG_TAG, "Fade.onDisappear: startView, startVis, endView, endVis = " +
+ Log.d(LOG_TAG, "Fade.onAppear: startView, startVis, endView, endVis = " +
startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
}
// if alpha < 1, just fade it in from the current value
if (endView.getAlpha() == 1.0f) {
endView.setAlpha(0);
+ TransitionListener transitionListener = new TransitionListenerAdapter() {
+ boolean mCanceled = false;
+ float mPausedAlpha;
+
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ endView.setAlpha(1);
+ mCanceled = true;
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ if (!mCanceled) {
+ endView.setAlpha(1);
+ }
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+ mPausedAlpha = endView.getAlpha();
+ endView.setAlpha(1);
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ endView.setAlpha(mPausedAlpha);
+ }
+ };
+ addListener(transitionListener);
}
return createAnimation(endView, endView.getAlpha(), 1, null);
}
diff --git a/core/java/android/transition/TextChange.java b/core/java/android/transition/TextChange.java
index 4f14d46..0b1e4e1 100644
--- a/core/java/android/transition/TextChange.java
+++ b/core/java/android/transition/TextChange.java
@@ -137,14 +137,17 @@
@Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
- if (startValues == null || endValues == null || !(endValues.view instanceof TextView)) {
+ if (startValues == null || endValues == null ||
+ !(startValues.view instanceof TextView) || !(endValues.view instanceof TextView)) {
return null;
}
final TextView view = (TextView) endValues.view;
Map<String, Object> startVals = startValues.values;
Map<String, Object> endVals = endValues.values;
- final CharSequence startText = (CharSequence) startVals.get(PROPNAME_TEXT);
- final CharSequence endText = (CharSequence) endVals.get(PROPNAME_TEXT);
+ final CharSequence startText = startVals.get(PROPNAME_TEXT) != null ?
+ (CharSequence) startVals.get(PROPNAME_TEXT) : "";
+ final CharSequence endText = endVals.get(PROPNAME_TEXT) != null ?
+ (CharSequence) endVals.get(PROPNAME_TEXT) : "";
if (!startText.equals(endText)) {
view.setText(startText);
Animator anim;
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 59df183..60b4708 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -29,6 +29,7 @@
import android.view.ViewGroup;
import android.view.ViewOverlay;
import android.widget.ListView;
+import android.widget.Spinner;
import java.util.ArrayList;
import java.util.List;
@@ -100,6 +101,12 @@
TimeInterpolator mInterpolator = null;
ArrayList<Integer> mTargetIds = new ArrayList<Integer>();
ArrayList<View> mTargets = new ArrayList<View>();
+ ArrayList<Integer> mTargetIdExcludes = null;
+ ArrayList<View> mTargetExcludes = null;
+ ArrayList<Class> mTargetTypeExcludes = null;
+ ArrayList<Integer> mTargetIdChildExcludes = null;
+ ArrayList<View> mTargetChildExcludes = null;
+ ArrayList<Class> mTargetTypeChildExcludes = null;
private TransitionValuesMaps mStartValues = new TransitionValuesMaps();
private TransitionValuesMaps mEndValues = new TransitionValuesMaps();
TransitionSet mParent = null;
@@ -122,6 +129,10 @@
// Whether this transition is currently paused, due to a call to pause()
boolean mPaused = false;
+ // Whether this transition has ended. Used to avoid pause/resume on transitions
+ // that have completed
+ private boolean mEnded = false;
+
// The set of listeners to be sent transition lifecycle events.
ArrayList<TransitionListener> mListeners = null;
@@ -426,10 +437,8 @@
Log.d(LOG_TAG, " differing start/end values for view " +
view);
if (start == null || end == null) {
- if (start == null) {
- Log.d(LOG_TAG, " " + ((start == null) ?
- "start null, end non-null" : "start non-null, end null"));
- }
+ Log.d(LOG_TAG, " " + ((start == null) ?
+ "start null, end non-null" : "start non-null, end null"));
} else {
for (String key : start.values.keySet()) {
Object startValue = start.values.get(key);
@@ -500,6 +509,21 @@
* views are ignored and only the ids are used).
*/
boolean isValidTarget(View target, long targetId) {
+ if (mTargetIdExcludes != null && mTargetIdExcludes.contains(targetId)) {
+ return false;
+ }
+ if (mTargetExcludes != null && mTargetExcludes.contains(target)) {
+ return false;
+ }
+ if (mTargetTypeExcludes != null && target != null) {
+ int numTypes = mTargetTypeExcludes.size();
+ for (int i = 0; i < numTypes; ++i) {
+ Class type = mTargetTypeExcludes.get(i);
+ if (type.isInstance(target)) {
+ return false;
+ }
+ }
+ }
if (mTargetIds.size() == 0 && mTargets.size() == 0) {
return true;
}
@@ -648,9 +672,9 @@
* @return The Transition to which the targetId is added.
* Returning the same object makes it easier to chain calls during
* construction, such as
- * <code>transitionSet.addTransitions(new Fade()).addTargetId(someId);</code>
+ * <code>transitionSet.addTransitions(new Fade()).addTarget(someId);</code>
*/
- public Transition addTargetId(int targetId) {
+ public Transition addTarget(int targetId) {
if (targetId > 0) {
mTargetIds.add(targetId);
}
@@ -667,7 +691,7 @@
* construction, such as
* <code>transitionSet.addTransitions(new Fade()).removeTargetId(someId);</code>
*/
- public Transition removeTargetId(int targetId) {
+ public Transition removeTarget(int targetId) {
if (targetId > 0) {
mTargetIds.remove(targetId);
}
@@ -675,6 +699,212 @@
}
/**
+ * Whether to add the given id to the list of target ids to exclude from this
+ * transition. The <code>exclude</code> parameter specifies whether the target
+ * should be added to or removed from the excluded list.
+ *
+ * <p>Excluding targets is a general mechanism for allowing transitions to run on
+ * a view hierarchy while skipping target views that should not be part of
+ * the transition. For example, you may want to avoid animating children
+ * of a specific ListView or Spinner. Views can be excluded either by their
+ * id, or by their instance reference, or by the Class of that view
+ * (eg, {@link Spinner}).</p>
+ *
+ * @see #excludeChildren(int, boolean)
+ * @see #excludeTarget(View, boolean)
+ * @see #excludeTarget(Class, boolean)
+ *
+ * @param targetId The id of a target to ignore when running this transition.
+ * @param exclude Whether to add the target to or remove the target from the
+ * current list of excluded targets.
+ * @return This transition object.
+ */
+ public Transition excludeTarget(int targetId, boolean exclude) {
+ mTargetIdExcludes = excludeId(mTargetIdExcludes, targetId, exclude);
+ return this;
+ }
+
+ /**
+ * Whether to add the children of the given id to the list of targets to exclude
+ * from this transition. The <code>exclude</code> parameter specifies whether
+ * the children of the target should be added to or removed from the excluded list.
+ * Excluding children in this way provides a simple mechanism for excluding all
+ * children of specific targets, rather than individually excluding each
+ * child individually.
+ *
+ * <p>Excluding targets is a general mechanism for allowing transitions to run on
+ * a view hierarchy while skipping target views that should not be part of
+ * the transition. For example, you may want to avoid animating children
+ * of a specific ListView or Spinner. Views can be excluded either by their
+ * id, or by their instance reference, or by the Class of that view
+ * (eg, {@link Spinner}).</p>
+ *
+ * @see #excludeTarget(int, boolean)
+ * @see #excludeChildren(View, boolean)
+ * @see #excludeChildren(Class, boolean)
+ *
+ * @param targetId The id of a target whose children should be ignored when running
+ * this transition.
+ * @param exclude Whether to add the target to or remove the target from the
+ * current list of excluded-child targets.
+ * @return This transition object.
+ */
+ public Transition excludeChildren(int targetId, boolean exclude) {
+ mTargetIdChildExcludes = excludeId(mTargetIdChildExcludes, targetId, exclude);
+ return this;
+ }
+
+ /**
+ * Utility method to manage the boilerplate code that is the same whether we
+ * are excluding targets or their children.
+ */
+ private ArrayList<Integer> excludeId(ArrayList<Integer> list, int targetId, boolean exclude) {
+ if (targetId > 0) {
+ if (exclude) {
+ list = ArrayListManager.add(list, targetId);
+ } else {
+ list = ArrayListManager.remove(list, targetId);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Whether to add the given target to the list of targets to exclude from this
+ * transition. The <code>exclude</code> parameter specifies whether the target
+ * should be added to or removed from the excluded list.
+ *
+ * <p>Excluding targets is a general mechanism for allowing transitions to run on
+ * a view hierarchy while skipping target views that should not be part of
+ * the transition. For example, you may want to avoid animating children
+ * of a specific ListView or Spinner. Views can be excluded either by their
+ * id, or by their instance reference, or by the Class of that view
+ * (eg, {@link Spinner}).</p>
+ *
+ * @see #excludeChildren(View, boolean)
+ * @see #excludeTarget(int, boolean)
+ * @see #excludeTarget(Class, boolean)
+ *
+ * @param target The target to ignore when running this transition.
+ * @param exclude Whether to add the target to or remove the target from the
+ * current list of excluded targets.
+ * @return This transition object.
+ */
+ public Transition excludeTarget(View target, boolean exclude) {
+ mTargetExcludes = excludeView(mTargetExcludes, target, exclude);
+ return this;
+ }
+
+ /**
+ * Whether to add the children of given target to the list of target children
+ * to exclude from this transition. The <code>exclude</code> parameter specifies
+ * whether the target should be added to or removed from the excluded list.
+ *
+ * <p>Excluding targets is a general mechanism for allowing transitions to run on
+ * a view hierarchy while skipping target views that should not be part of
+ * the transition. For example, you may want to avoid animating children
+ * of a specific ListView or Spinner. Views can be excluded either by their
+ * id, or by their instance reference, or by the Class of that view
+ * (eg, {@link Spinner}).</p>
+ *
+ * @see #excludeTarget(View, boolean)
+ * @see #excludeChildren(int, boolean)
+ * @see #excludeChildren(Class, boolean)
+ *
+ * @param target The target to ignore when running this transition.
+ * @param exclude Whether to add the target to or remove the target from the
+ * current list of excluded targets.
+ * @return This transition object.
+ */
+ public Transition excludeChildren(View target, boolean exclude) {
+ mTargetChildExcludes = excludeView(mTargetChildExcludes, target, exclude);
+ return this;
+ }
+
+ /**
+ * Utility method to manage the boilerplate code that is the same whether we
+ * are excluding targets or their children.
+ */
+ private ArrayList<View> excludeView(ArrayList<View> list, View target, boolean exclude) {
+ if (target != null) {
+ if (exclude) {
+ list = ArrayListManager.add(list, target);
+ } else {
+ list = ArrayListManager.remove(list, target);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Whether to add the given type to the list of types to exclude from this
+ * transition. The <code>exclude</code> parameter specifies whether the target
+ * type should be added to or removed from the excluded list.
+ *
+ * <p>Excluding targets is a general mechanism for allowing transitions to run on
+ * a view hierarchy while skipping target views that should not be part of
+ * the transition. For example, you may want to avoid animating children
+ * of a specific ListView or Spinner. Views can be excluded either by their
+ * id, or by their instance reference, or by the Class of that view
+ * (eg, {@link Spinner}).</p>
+ *
+ * @see #excludeChildren(Class, boolean)
+ * @see #excludeTarget(int, boolean)
+ * @see #excludeTarget(View, boolean)
+ *
+ * @param type The type to ignore when running this transition.
+ * @param exclude Whether to add the target type to or remove it from the
+ * current list of excluded target types.
+ * @return This transition object.
+ */
+ public Transition excludeTarget(Class type, boolean exclude) {
+ mTargetTypeExcludes = excludeType(mTargetTypeExcludes, type, exclude);
+ return this;
+ }
+
+ /**
+ * Whether to add the given type to the list of types whose children should
+ * be excluded from this transition. The <code>exclude</code> parameter
+ * specifies whether the target type should be added to or removed from
+ * the excluded list.
+ *
+ * <p>Excluding targets is a general mechanism for allowing transitions to run on
+ * a view hierarchy while skipping target views that should not be part of
+ * the transition. For example, you may want to avoid animating children
+ * of a specific ListView or Spinner. Views can be excluded either by their
+ * id, or by their instance reference, or by the Class of that view
+ * (eg, {@link Spinner}).</p>
+ *
+ * @see #excludeTarget(Class, boolean)
+ * @see #excludeChildren(int, boolean)
+ * @see #excludeChildren(View, boolean)
+ *
+ * @param type The type to ignore when running this transition.
+ * @param exclude Whether to add the target type to or remove it from the
+ * current list of excluded target types.
+ * @return This transition object.
+ */
+ public Transition excludeChildren(Class type, boolean exclude) {
+ mTargetTypeChildExcludes = excludeType(mTargetTypeChildExcludes, type, exclude);
+ return this;
+ }
+
+ /**
+ * Utility method to manage the boilerplate code that is the same whether we
+ * are excluding targets or their children.
+ */
+ private ArrayList<Class> excludeType(ArrayList<Class> list, Class type, boolean exclude) {
+ if (type != null) {
+ if (exclude) {
+ list = ArrayListManager.add(list, type);
+ } else {
+ list = ArrayListManager.remove(list, type);
+ }
+ }
+ return list;
+ }
+
+ /**
* Sets the target view instances that this Transition is interested in
* animating. By default, there are no targets, and a Transition will
* listen for changes on every view in the hierarchy below the sceneRoot
@@ -682,18 +912,18 @@
* the Transition to only listen for, and act on, these views.
* All other views will be ignored.
*
- * <p>The target list is like the {@link #addTargetId(int) targetId}
+ * <p>The target list is like the {@link #addTarget(int) targetId}
* list except this list specifies the actual View instances, not the ids
* of the views. This is an important distinction when scene changes involve
* view hierarchies which have been inflated separately; different views may
* share the same id but not actually be the same instance. If the transition
- * should treat those views as the same, then {@link #addTargetId(int)} should be used
+ * should treat those views as the same, then {@link #addTarget(int)} should be used
* instead of {@link #addTarget(View)}. If, on the other hand, scene changes involve
* changes all within the same view hierarchy, among views which do not
* necessarily have ids set on them, then the target list of views may be more
* convenient.</p>
*
- * @see #addTargetId(int)
+ * @see #addTarget(int)
* @param target A View on which the Transition will act, must be non-null.
* @return The Transition to which the target is added.
* Returning the same object makes it easier to chain calls during
@@ -838,15 +1068,30 @@
// ignore listview children unless we can track them with stable IDs
return;
}
- long id;
+ int id = View.NO_ID;
+ long itemId = View.NO_ID;
if (!isListViewItem) {
id = view.getId();
} else {
ListView listview = (ListView) view.getParent();
int position = listview.getPositionForView(view);
- id = listview.getItemIdAtPosition(position);
+ itemId = listview.getItemIdAtPosition(position);
view.setHasTransientState(true);
}
+ if (mTargetIdExcludes != null && mTargetIdExcludes.contains(id)) {
+ return;
+ }
+ if (mTargetExcludes != null && mTargetExcludes.contains(view)) {
+ return;
+ }
+ if (mTargetTypeExcludes != null && view != null) {
+ int numTypes = mTargetTypeExcludes.size();
+ for (int i = 0; i < numTypes; ++i) {
+ if (mTargetTypeExcludes.get(i).isInstance(view)) {
+ return;
+ }
+ }
+ }
TransitionValues values = new TransitionValues();
values.view = view;
captureStartValues(values);
@@ -857,7 +1102,7 @@
mStartValues.idValues.put((int) id, values);
}
} else {
- mStartValues.itemIdValues.put(id, values);
+ mStartValues.itemIdValues.put(itemId, values);
}
} else {
if (!isListViewItem) {
@@ -866,10 +1111,25 @@
mEndValues.idValues.put((int) id, values);
}
} else {
- mEndValues.itemIdValues.put(id, values);
+ mEndValues.itemIdValues.put(itemId, values);
}
}
if (view instanceof ViewGroup) {
+ // Don't traverse child hierarchy if there are any child-excludes on this view
+ if (mTargetIdChildExcludes != null && mTargetIdChildExcludes.contains(id)) {
+ return;
+ }
+ if (mTargetChildExcludes != null && mTargetChildExcludes.contains(view)) {
+ return;
+ }
+ if (mTargetTypeChildExcludes != null && view != null) {
+ int numTypes = mTargetTypeChildExcludes.size();
+ for (int i = 0; i < numTypes; ++i) {
+ if (mTargetTypeChildExcludes.get(i).isInstance(view)) {
+ return;
+ }
+ }
+ }
ViewGroup parent = (ViewGroup) view;
for (int i = 0; i < parent.getChildCount(); ++i) {
captureHierarchy(parent.getChildAt(i), start);
@@ -914,21 +1174,23 @@
* @hide
*/
public void pause() {
- ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
- int numOldAnims = runningAnimators.size();
- for (int i = numOldAnims - 1; i >= 0; i--) {
- Animator anim = runningAnimators.keyAt(i);
- anim.pause();
- }
- if (mListeners != null && mListeners.size() > 0) {
- ArrayList<TransitionListener> tmpListeners =
- (ArrayList<TransitionListener>) mListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onTransitionPause(this);
+ if (!mEnded) {
+ ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+ int numOldAnims = runningAnimators.size();
+ for (int i = numOldAnims - 1; i >= 0; i--) {
+ Animator anim = runningAnimators.keyAt(i);
+ anim.pause();
}
+ if (mListeners != null && mListeners.size() > 0) {
+ ArrayList<TransitionListener> tmpListeners =
+ (ArrayList<TransitionListener>) mListeners.clone();
+ int numListeners = tmpListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ tmpListeners.get(i).onTransitionPause(this);
+ }
+ }
+ mPaused = true;
}
- mPaused = true;
}
/**
@@ -940,18 +1202,20 @@
*/
public void resume() {
if (mPaused) {
- ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
- int numOldAnims = runningAnimators.size();
- for (int i = numOldAnims - 1; i >= 0; i--) {
- Animator anim = runningAnimators.keyAt(i);
- anim.resume();
- }
- if (mListeners != null && mListeners.size() > 0) {
- ArrayList<TransitionListener> tmpListeners =
- (ArrayList<TransitionListener>) mListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onTransitionResume(this);
+ if (!mEnded) {
+ ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+ int numOldAnims = runningAnimators.size();
+ for (int i = numOldAnims - 1; i >= 0; i--) {
+ Animator anim = runningAnimators.keyAt(i);
+ anim.resume();
+ }
+ if (mListeners != null && mListeners.size() > 0) {
+ ArrayList<TransitionListener> tmpListeners =
+ (ArrayList<TransitionListener>) mListeners.clone();
+ int numListeners = tmpListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ tmpListeners.get(i).onTransitionResume(this);
+ }
}
}
mPaused = false;
@@ -976,12 +1240,13 @@
View oldView = oldInfo.view;
TransitionValues newValues = mEndValues.viewValues != null ?
mEndValues.viewValues.get(oldView) : null;
+ if (newValues == null) {
+ newValues = mEndValues.idValues.get(oldView.getId());
+ }
if (oldValues != null) {
// if oldValues null, then transition didn't care to stash values,
// and won't get canceled
- if (newValues == null) {
- cancel = true;
- } else {
+ if (newValues != null) {
for (String key : oldValues.values.keySet()) {
Object oldValue = oldValues.values.get(key);
Object newValue = newValues.values.get(key);
@@ -1071,6 +1336,7 @@
tmpListeners.get(i).onTransitionStart(this);
}
}
+ mEnded = false;
}
mNumInstances++;
}
@@ -1111,6 +1377,7 @@
v.setHasTransientState(false);
}
}
+ mEnded = true;
}
}
@@ -1185,6 +1452,8 @@
try {
clone = (Transition) super.clone();
clone.mAnimators = new ArrayList<Animator>();
+ clone.mStartValues = new TransitionValuesMaps();
+ clone.mEndValues = new TransitionValuesMaps();
} catch (CloneNotSupportedException e) {}
return clone;
@@ -1346,4 +1615,51 @@
this.values = values;
}
}
+
+ /**
+ * Utility class for managing typed ArrayLists efficiently. In particular, this
+ * can be useful for lists that we don't expect to be used often (eg, the exclude
+ * lists), so we'd like to keep them nulled out by default. This causes the code to
+ * become tedious, with constant null checks, code to allocate when necessary,
+ * and code to null out the reference when the list is empty. This class encapsulates
+ * all of that functionality into simple add()/remove() methods which perform the
+ * necessary checks, allocation/null-out as appropriate, and return the
+ * resulting list.
+ */
+ private static class ArrayListManager {
+
+ /**
+ * Add the specified item to the list, returning the resulting list.
+ * The returned list can either the be same list passed in or, if that
+ * list was null, the new list that was created.
+ *
+ * Note that the list holds unique items; if the item already exists in the
+ * list, the list is not modified.
+ */
+ static <T> ArrayList<T> add(ArrayList<T> list, T item) {
+ if (list == null) {
+ list = new ArrayList<T>();
+ }
+ if (!list.contains(item)) {
+ list.add(item);
+ }
+ return list;
+ }
+
+ /**
+ * Remove the specified item from the list, returning the resulting list.
+ * The returned list can either the be same list passed in or, if that
+ * list becomes empty as a result of the remove(), the new list was created.
+ */
+ static <T> ArrayList<T> remove(ArrayList<T> list, T item) {
+ if (list != null) {
+ list.remove(item);
+ if (list.isEmpty()) {
+ list = null;
+ }
+ }
+ return list;
+ }
+ }
+
}
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index ebedeeb..eeb6cba 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -235,7 +235,7 @@
int numTargets = targetIds.size();
if (numTargets > 0) {
for (int i = 0; i < numTargets; ++i) {
- transition.addTargetId(targetIds.get(i));
+ transition.addTarget(targetIds.get(i));
}
}
}
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 9904413..44ca4e5 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -22,6 +22,7 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
/**
@@ -68,8 +69,9 @@
ArrayMap<Scene, Transition> mSceneTransitions = new ArrayMap<Scene, Transition>();
ArrayMap<Scene, ArrayMap<Scene, Transition>> mScenePairTransitions =
new ArrayMap<Scene, ArrayMap<Scene, Transition>>();
- private static ThreadLocal<ArrayMap<ViewGroup, ArrayList<Transition>>> sRunningTransitions =
- new ThreadLocal<ArrayMap<ViewGroup, ArrayList<Transition>>>();
+ private static ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>
+ sRunningTransitions =
+ new ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>();
private static ArrayList<ViewGroup> sPendingTransitions = new ArrayList<ViewGroup>();
@@ -184,20 +186,24 @@
}
private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() {
- ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
+ WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>> runningTransitions =
sRunningTransitions.get();
- if (runningTransitions == null) {
- runningTransitions = new ArrayMap<ViewGroup, ArrayList<Transition>>();
+ if (runningTransitions == null || runningTransitions.get() == null) {
+ ArrayMap<ViewGroup, ArrayList<Transition>> transitions =
+ new ArrayMap<ViewGroup, ArrayList<Transition>>();
+ runningTransitions = new WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>(
+ transitions);
sRunningTransitions.set(runningTransitions);
}
- return runningTransitions;
+ return runningTransitions.get();
}
private static void sceneChangeRunTransition(final ViewGroup sceneRoot,
final Transition transition) {
if (transition != null) {
final ViewTreeObserver observer = sceneRoot.getViewTreeObserver();
- observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ final ViewTreeObserver.OnPreDrawListener listener =
+ new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
sPendingTransitions.remove(sceneRoot);
@@ -236,7 +242,8 @@
// values set on them again and avoid artifacts.
return false;
}
- });
+ };
+ observer.addOnPreDrawListener(listener);
}
}
@@ -351,10 +358,10 @@
if (transition == null) {
transition = sDefaultTransition;
}
- final Transition finalTransition = transition.clone();
- sceneChangeSetup(sceneRoot, transition);
+ final Transition transitionClone = transition.clone();
+ sceneChangeSetup(sceneRoot, transitionClone);
Scene.setCurrentScene(sceneRoot, null);
- sceneChangeRunTransition(sceneRoot, finalTransition);
+ sceneChangeRunTransition(sceneRoot, transitionClone);
}
}
}
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index 1972c2a..f72b36e 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -155,8 +155,8 @@
}
@Override
- public TransitionSet addTargetId(int targetId) {
- return (TransitionSet) super.addTargetId(targetId);
+ public TransitionSet addTarget(int targetId) {
+ return (TransitionSet) super.addTarget(targetId);
}
@Override
@@ -165,8 +165,8 @@
}
@Override
- public TransitionSet removeTargetId(int targetId) {
- return (TransitionSet) super.removeTargetId(targetId);
+ public TransitionSet removeTarget(int targetId) {
+ return (TransitionSet) super.removeTarget(targetId);
}
@Override
@@ -278,9 +278,11 @@
@Override
public void captureStartValues(TransitionValues transitionValues) {
int targetId = transitionValues.view.getId();
- for (Transition childTransition : mTransitions) {
- if (childTransition.isValidTarget(transitionValues.view, targetId)) {
- childTransition.captureStartValues(transitionValues);
+ if (isValidTarget(transitionValues.view, targetId)) {
+ for (Transition childTransition : mTransitions) {
+ if (childTransition.isValidTarget(transitionValues.view, targetId)) {
+ childTransition.captureStartValues(transitionValues);
+ }
}
}
}
@@ -288,9 +290,11 @@
@Override
public void captureEndValues(TransitionValues transitionValues) {
int targetId = transitionValues.view.getId();
- for (Transition childTransition : mTransitions) {
- if (childTransition.isValidTarget(transitionValues.view, targetId)) {
- childTransition.captureEndValues(transitionValues);
+ if (isValidTarget(transitionValues.view, targetId)) {
+ for (Transition childTransition : mTransitions) {
+ if (childTransition.isValidTarget(transitionValues.view, targetId)) {
+ childTransition.captureEndValues(transitionValues);
+ }
}
}
}
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 75d3e7c..f49821f 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -65,9 +65,6 @@
ViewGroup endParent;
}
- // Temporary structure, used in calculating state in setup() and play()
- private VisibilityInfo mTmpVisibilityInfo = new VisibilityInfo();
-
@Override
public String[] getTransitionProperties() {
return sTransitionProperties;
@@ -161,7 +158,7 @@
private VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
TransitionValues endValues) {
- final VisibilityInfo visInfo = mTmpVisibilityInfo;
+ final VisibilityInfo visInfo = new VisibilityInfo();
visInfo.visibilityChange = false;
visInfo.fadeIn = false;
if (startValues != null) {
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index 63e8c25..d6e116f 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -39,6 +39,12 @@
* a single garbage collection step of all removed entries. This garbage collection will
* need to be performed at any time the array needs to be grown or the the map size or
* entry values are retrieved.</p>
+ *
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.</p>
*/
public class LongSparseArray<E> implements Cloneable {
private static final Object DELETED = new Object();
@@ -238,6 +244,11 @@
* Given an index in the range <code>0...size()-1</code>, returns
* the key from the <code>index</code>th key-value mapping that this
* LongSparseArray stores.
+ *
+ * <p>The keys corresponding to indices in ascending order are guaranteed to
+ * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+ * smallest key and <code>keyAt(size()-1)</code> will return the largest
+ * key.</p>
*/
public long keyAt(int index) {
if (mGarbage) {
@@ -251,6 +262,12 @@
* Given an index in the range <code>0...size()-1</code>, returns
* the value from the <code>index</code>th key-value mapping that this
* LongSparseArray stores.
+ *
+ * <p>The values corresponding to indices in ascending order are guaranteed
+ * to be associated with keys in ascending order, e.g.,
+ * <code>valueAt(0)</code> will return the value associated with the
+ * smallest key and <code>valueAt(size()-1)</code> will return the value
+ * associated with the largest key.</p>
*/
@SuppressWarnings("unchecked")
public E valueAt(int index) {
diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java
index 133e415..87d868b 100644
--- a/core/java/android/util/LongSparseLongArray.java
+++ b/core/java/android/util/LongSparseLongArray.java
@@ -35,6 +35,12 @@
* and deleting entries in the array. For containers holding up to hundreds of items,
* the performance difference is not significant, less than 50%.</p>
*
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.</p>
+ *
* @hide
*/
public class LongSparseLongArray implements Cloneable {
@@ -163,6 +169,11 @@
* Given an index in the range <code>0...size()-1</code>, returns
* the key from the <code>index</code>th key-value mapping that this
* SparseLongArray stores.
+ *
+ * <p>The keys corresponding to indices in ascending order are guaranteed to
+ * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+ * smallest key and <code>keyAt(size()-1)</code> will return the largest
+ * key.</p>
*/
public long keyAt(int index) {
return mKeys[index];
@@ -172,6 +183,12 @@
* Given an index in the range <code>0...size()-1</code>, returns
* the value from the <code>index</code>th key-value mapping that this
* SparseLongArray stores.
+ *
+ * <p>The values corresponding to indices in ascending order are guaranteed
+ * to be associated with keys in ascending order, e.g.,
+ * <code>valueAt(0)</code> will return the value associated with the
+ * smallest key and <code>valueAt(size()-1)</code> will return the value
+ * associated with the largest key.</p>
*/
public long valueAt(int index) {
return mValues[index];
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 6e66090..6e168a8 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -39,6 +39,12 @@
* a single garbage collection step of all removed entries. This garbage collection will
* need to be performed at any time the array needs to be grown or the the map size or
* entry values are retrieved.</p>
+ *
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.</p>
*/
public class SparseArray<E> implements Cloneable {
private static final Object DELETED = new Object();
@@ -251,6 +257,11 @@
* Given an index in the range <code>0...size()-1</code>, returns
* the key from the <code>index</code>th key-value mapping that this
* SparseArray stores.
+ *
+ * <p>The keys corresponding to indices in ascending order are guaranteed to
+ * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+ * smallest key and <code>keyAt(size()-1)</code> will return the largest
+ * key.</p>
*/
public int keyAt(int index) {
if (mGarbage) {
@@ -264,6 +275,12 @@
* Given an index in the range <code>0...size()-1</code>, returns
* the value from the <code>index</code>th key-value mapping that this
* SparseArray stores.
+ *
+ * <p>The values corresponding to indices in ascending order are guaranteed
+ * to be associated with keys in ascending order, e.g.,
+ * <code>valueAt(0)</code> will return the value associated with the
+ * smallest key and <code>valueAt(size()-1)</code> will return the value
+ * associated with the largest key.</p>
*/
@SuppressWarnings("unchecked")
public E valueAt(int index) {
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index da196d7..68487e3 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -33,6 +33,12 @@
* HashMap, since lookups require a binary search and adds and removes require inserting
* and deleting entries in the array. For containers holding up to hundreds of items,
* the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.</p>
*/
public class SparseBooleanArray implements Cloneable {
/**
@@ -159,16 +165,27 @@
/**
* Given an index in the range <code>0...size()-1</code>, returns
* the key from the <code>index</code>th key-value mapping that this
- * SparseBooleanArray stores.
+ * SparseBooleanArray stores.
+ *
+ * <p>The keys corresponding to indices in ascending order are guaranteed to
+ * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+ * smallest key and <code>keyAt(size()-1)</code> will return the largest
+ * key.</p>
*/
public int keyAt(int index) {
return mKeys[index];
}
-
+
/**
* Given an index in the range <code>0...size()-1</code>, returns
* the value from the <code>index</code>th key-value mapping that this
- * SparseBooleanArray stores.
+ * SparseBooleanArray stores.
+ *
+ * <p>The values corresponding to indices in ascending order are guaranteed
+ * to be associated with keys in ascending order, e.g.,
+ * <code>valueAt(0)</code> will return the value associated with the
+ * smallest key and <code>valueAt(size()-1)</code> will return the value
+ * associated with the largest key.</p>
*/
public boolean valueAt(int index) {
return mValues[index];
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index c2bacb0..0835cb0 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -32,6 +32,12 @@
* HashMap, since lookups require a binary search and adds and removes require inserting
* and deleting entries in the array. For containers holding up to hundreds of items,
* the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.</p>
*/
public class SparseIntArray implements Cloneable {
private int[] mKeys;
@@ -169,16 +175,27 @@
/**
* Given an index in the range <code>0...size()-1</code>, returns
* the key from the <code>index</code>th key-value mapping that this
- * SparseIntArray stores.
+ * SparseIntArray stores.
+ *
+ * <p>The keys corresponding to indices in ascending order are guaranteed to
+ * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+ * smallest key and <code>keyAt(size()-1)</code> will return the largest
+ * key.</p>
*/
public int keyAt(int index) {
return mKeys[index];
}
-
+
/**
* Given an index in the range <code>0...size()-1</code>, returns
* the value from the <code>index</code>th key-value mapping that this
- * SparseIntArray stores.
+ * SparseIntArray stores.
+ *
+ * <p>The values corresponding to indices in ascending order are guaranteed
+ * to be associated with keys in ascending order, e.g.,
+ * <code>valueAt(0)</code> will return the value associated with the
+ * smallest key and <code>valueAt(size()-1)</code> will return the value
+ * associated with the largest key.</p>
*/
public int valueAt(int index) {
return mValues[index];
diff --git a/core/java/android/util/SparseLongArray.java b/core/java/android/util/SparseLongArray.java
index 182fd35..62c1c0d 100644
--- a/core/java/android/util/SparseLongArray.java
+++ b/core/java/android/util/SparseLongArray.java
@@ -32,6 +32,12 @@
* HashMap, since lookups require a binary search and adds and removes require inserting
* and deleting entries in the array. For containers holding up to hundreds of items,
* the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.</p>
*/
public class SparseLongArray implements Cloneable {
private int[] mKeys;
@@ -159,6 +165,11 @@
* Given an index in the range <code>0...size()-1</code>, returns
* the key from the <code>index</code>th key-value mapping that this
* SparseLongArray stores.
+ *
+ * <p>The keys corresponding to indices in ascending order are guaranteed to
+ * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+ * smallest key and <code>keyAt(size()-1)</code> will return the largest
+ * key.</p>
*/
public int keyAt(int index) {
return mKeys[index];
@@ -168,6 +179,12 @@
* Given an index in the range <code>0...size()-1</code>, returns
* the value from the <code>index</code>th key-value mapping that this
* SparseLongArray stores.
+ *
+ * <p>The values corresponding to indices in ascending order are guaranteed
+ * to be associated with keys in ascending order, e.g.,
+ * <code>valueAt(0)</code> will return the value associated with the
+ * smallest key and <code>valueAt(size()-1)</code> will return the value
+ * associated with the largest key.</p>
*/
public long valueAt(int index) {
return mValues[index];
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index ba64f6b..f215189 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -34,6 +34,8 @@
import android.os.Trace;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.view.Surface.OutOfResourcesException;
+
import com.google.android.gles_jni.EGLImpl;
import javax.microedition.khronos.egl.EGL10;
@@ -74,7 +76,7 @@
* System property used to enable or disable dirty regions invalidation.
* This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true.
* The default value of this property is assumed to be true.
- *
+ *
* Possible values:
* "true", to enable partial invalidates
* "false", to disable partial invalidates
@@ -134,7 +136,7 @@
/**
* System property used to debug EGL configuration choice.
- *
+ *
* Possible values:
* "choice", print the chosen configuration only
* "all", print all possible configurations
@@ -147,7 +149,7 @@
* Possible values:
* "true", to enable dirty regions debugging
* "false", to disable dirty regions debugging
- *
+ *
* @hide
*/
public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions";
@@ -208,14 +210,14 @@
/**
* A process can set this flag to false to prevent the use of hardware
* rendering.
- *
+ *
* @hide
*/
public static boolean sRendererDisabled = false;
/**
* Further hardware renderer disabling for the system process.
- *
+ *
* @hide
*/
public static boolean sSystemRendererDisabled = false;
@@ -235,7 +237,7 @@
/**
* Invoke this method to disable hardware rendering in the current process.
- *
+ *
* @hide
*/
public static void disable(boolean system) {
@@ -248,7 +250,7 @@
/**
* Indicates whether hardware acceleration is available under any form for
* the view hierarchy.
- *
+ *
* @return True if the view hierarchy can potentially be hardware accelerated,
* false otherwise
*/
@@ -258,30 +260,30 @@
/**
* Destroys the hardware rendering context.
- *
+ *
* @param full If true, destroys all associated resources.
*/
abstract void destroy(boolean full);
/**
* Initializes the hardware renderer for the specified surface.
- *
+ *
* @param surface The surface to hardware accelerate
- *
+ *
* @return True if the initialization was successful, false otherwise.
*/
- abstract boolean initialize(Surface surface) throws Surface.OutOfResourcesException;
-
+ abstract boolean initialize(Surface surface) throws OutOfResourcesException;
+
/**
* Updates the hardware renderer for the specified surface.
*
* @param surface The surface to hardware accelerate
*/
- abstract void updateSurface(Surface surface) throws Surface.OutOfResourcesException;
+ abstract void updateSurface(Surface surface) throws OutOfResourcesException;
/**
* Destroys the layers used by the specified view hierarchy.
- *
+ *
* @param view The root of the view hierarchy
*/
abstract void destroyLayers(View view);
@@ -289,11 +291,11 @@
/**
* Destroys all hardware rendering resources associated with the specified
* view hierarchy.
- *
+ *
* @param view The root of the view hierarchy
*/
abstract void destroyHardwareResources(View view);
-
+
/**
* This method should be invoked whenever the current hardware renderer
* context should be reset.
@@ -306,7 +308,7 @@
* This method should be invoked to ensure the hardware renderer is in
* valid state (for instance, to ensure the correct EGL context is bound
* to the current thread.)
- *
+ *
* @return true if the renderer is now valid, false otherwise
*/
abstract boolean validate();
@@ -314,7 +316,7 @@
/**
* This method ensures the hardware renderer is in a valid state
* before executing the specified action.
- *
+ *
* This method will attempt to set a valid state even if the window
* the renderer is attached to was destroyed.
*
@@ -325,7 +327,7 @@
/**
* Setup the hardware renderer for drawing. This is called whenever the
* size of the target surface changes or when the surface is first created.
- *
+ *
* @param width Width of the drawing surface.
* @param height Height of the drawing surface.
*/
@@ -384,7 +386,7 @@
/**
* Sets the directory to use as a persistent storage for hardware rendering
* resources.
- *
+ *
* @param cacheDir A directory the current process can write to
*
* @hide
@@ -447,7 +449,7 @@
/**
* Indicates that the specified hardware layer needs to be updated
* as soon as possible.
- *
+ *
* @param layer The hardware layer that needs an update
*
* @see #flushLayerUpdates()
@@ -481,7 +483,7 @@
* Invoked before a view is drawn by a hardware renderer.
* This method can be used to apply transformations to the
* canvas but no drawing command should be issued.
- *
+ *
* @param canvas The Canvas used to render the view.
*/
void onHardwarePreDraw(HardwareCanvas canvas);
@@ -489,7 +491,7 @@
/**
* Invoked after a view is drawn by a hardware renderer.
* It is safe to invoke drawing commands from this method.
- *
+ *
* @param canvas The Canvas used to render the view.
*/
void onHardwarePostDraw(HardwareCanvas canvas);
@@ -509,9 +511,9 @@
/**
* Creates a new display list that can be used to record batches of
* drawing operations.
- *
+ *
* @param name The name of the display list, used for debugging purpose. May be null.
- *
+ *
* @return A new display list.
*
* @hide
@@ -521,20 +523,20 @@
/**
* Creates a new hardware layer. A hardware layer built by calling this
* method will be treated as a texture layer, instead of as a render target.
- *
+ *
* @param isOpaque Whether the layer should be opaque or not
- *
+ *
* @return A hardware layer
*/
abstract HardwareLayer createHardwareLayer(boolean isOpaque);
/**
* Creates a new hardware layer.
- *
+ *
* @param width The minimum width of the layer
* @param height The minimum height of the layer
* @param isOpaque Whether the layer should be opaque or not
- *
+ *
* @return A hardware layer
*/
abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque);
@@ -544,7 +546,7 @@
* specified hardware layer.
*
* @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
- *
+ *
* @return A {@link SurfaceTexture}
*/
abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer);
@@ -560,11 +562,11 @@
/**
* Detaches the specified functor from the current functor execution queue.
- *
+ *
* @param functor The native functor to remove from the execution queue.
- *
- * @see HardwareCanvas#callDrawGLFunction(int)
- * @see #attachFunctor(android.view.View.AttachInfo, int)
+ *
+ * @see HardwareCanvas#callDrawGLFunction(int)
+ * @see #attachFunctor(android.view.View.AttachInfo, int)
*/
abstract void detachFunctor(int functor);
@@ -591,12 +593,12 @@
* @param width The width of the drawing surface.
* @param height The height of the drawing surface.
* @param surface The surface to hardware accelerate
- *
+ *
* @return true if the surface was initialized, false otherwise. Returning
* false might mean that the surface was already initialized.
*/
boolean initializeIfNeeded(int width, int height, Surface surface)
- throws Surface.OutOfResourcesException {
+ throws OutOfResourcesException {
if (isRequested()) {
// We lost the gl context, so recreate it.
if (!isEnabled()) {
@@ -618,10 +620,10 @@
/**
* Creates a hardware renderer using OpenGL.
- *
+ *
* @param glVersion The version of OpenGL to use (1 for OpenGL 1, 11 for OpenGL 1.1, etc.)
* @param translucent True if the surface is translucent, false otherwise
- *
+ *
* @return A hardware renderer backed by OpenGL.
*/
static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) {
@@ -636,7 +638,7 @@
* Invoke this method when the system is running out of memory. This
* method will attempt to recover as much memory as possible, based on
* the specified hint.
- *
+ *
* @param level Hint about the amount of memory that should be trimmed,
* see {@link android.content.ComponentCallbacks}
*/
@@ -649,7 +651,7 @@
* Starts the process of trimming memory. Usually this call will setup
* hardware rendering context and reclaim memory.Extra cleanup might
* be required by calling {@link #endTrimMemory()}.
- *
+ *
* @param level Hint about the amount of memory that should be trimmed,
* see {@link android.content.ComponentCallbacks}
*/
@@ -667,7 +669,7 @@
/**
* Indicates whether hardware acceleration is currently enabled.
- *
+ *
* @return True if hardware acceleration is in use, false otherwise.
*/
boolean isEnabled() {
@@ -676,7 +678,7 @@
/**
* Indicates whether hardware acceleration is currently enabled.
- *
+ *
* @param enabled True if the hardware renderer is in use, false otherwise.
*/
void setEnabled(boolean enabled) {
@@ -686,7 +688,7 @@
/**
* Indicates whether hardware acceleration is currently request but not
* necessarily enabled yet.
- *
+ *
* @return True if requested, false otherwise.
*/
boolean isRequested() {
@@ -696,7 +698,7 @@
/**
* Indicates whether hardware acceleration is currently requested but not
* necessarily enabled yet.
- *
+ *
* @return True to request hardware acceleration, false otherwise.
*/
void setRequested(boolean requested) {
@@ -837,7 +839,7 @@
Thread mEglThread;
EGLSurface mEglSurface;
-
+
GL mGl;
HardwareCanvas mCanvas;
@@ -1050,7 +1052,7 @@
}
@Override
- boolean initialize(Surface surface) throws Surface.OutOfResourcesException {
+ boolean initialize(Surface surface) throws OutOfResourcesException {
if (isRequested() && !isEnabled()) {
boolean contextCreated = initializeEgl();
mGl = createEglSurface(surface);
@@ -1078,9 +1080,9 @@
}
return false;
}
-
+
@Override
- void updateSurface(Surface surface) throws Surface.OutOfResourcesException {
+ void updateSurface(Surface surface) throws OutOfResourcesException {
if (isRequested() && isEnabled()) {
createEglSurface(surface);
}
@@ -1094,15 +1096,15 @@
synchronized (sEglLock) {
if (sEgl == null && sEglConfig == null) {
sEgl = (EGL10) EGLContext.getEGL();
-
+
// Get to the default display.
sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
-
+
if (sEglDisplay == EGL_NO_DISPLAY) {
throw new RuntimeException("eglGetDisplay failed "
+ GLUtils.getEGLErrorString(sEgl.eglGetError()));
}
-
+
// We can now initialize EGL for that display
int[] version = new int[2];
if (!sEgl.eglInitialize(sEglDisplay, version)) {
@@ -1216,7 +1218,7 @@
Log.d(LOG_TAG, " CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0]));
}
- GL createEglSurface(Surface surface) throws Surface.OutOfResourcesException {
+ GL createEglSurface(Surface surface) throws OutOfResourcesException {
// Check preconditions.
if (sEgl == null) {
throw new RuntimeException("egl not initialized");
@@ -1228,7 +1230,7 @@
throw new RuntimeException("eglConfig not initialized");
}
if (Thread.currentThread() != mEglThread) {
- throw new IllegalStateException("HardwareRenderer cannot be used "
+ throw new IllegalStateException("HardwareRenderer cannot be used "
+ "from multiple threads");
}
@@ -1394,8 +1396,8 @@
boolean canDraw() {
return mGl != null && mCanvas != null;
- }
-
+ }
+
int onPreDraw(Rect dirty) {
return DisplayList.STATUS_DONE;
}
@@ -1732,7 +1734,7 @@
* Ensures the current EGL context and surface are the ones we expect.
* This method throws an IllegalStateException if invoked from a thread
* that did not initialize EGL.
- *
+ *
* @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
* {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
* {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
diff --git a/core/java/android/view/IApplicationToken.aidl b/core/java/android/view/IApplicationToken.aidl
index 5f0600f..633b40f 100644
--- a/core/java/android/view/IApplicationToken.aidl
+++ b/core/java/android/view/IApplicationToken.aidl
@@ -23,7 +23,7 @@
void windowsDrawn();
void windowsVisible();
void windowsGone();
- boolean keyDispatchingTimedOut();
+ boolean keyDispatchingTimedOut(String reason);
long getKeyDispatchingTimeout();
}
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index afc7b3e..e829116 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -424,12 +424,17 @@
/**
* The controller number for a given input device.
* <p>
- * Each game controller or joystick is given a unique controller number when initially
- * configured by the system. The number is not stable and may be changed by the system at any
- * point. All controller numbers will be non-negative. A game controller or joystick will be
- * given a unique number indexed from one; everything else will be assigned a controller number
+ * Each gamepad or joystick is given a unique, positive controller number when initially
+ * configured by the system. This number may change due to events such as device disconnects /
+ * reconnects or user initiated reassignment. Any change in number will trigger an event that
+ * can be observed by registering an {@link InputManager.InputDeviceListener}.
+ * </p>
+ * <p>
+ * All input devices which are not gamepads or joysticks will be assigned a controller number
* of 0.
* </p>
+ *
+ * @return The controller number of the device.
*/
public int getControllerNumber() {
return mControllerNumber;
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 0bebc04..f36c78f 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -130,7 +130,7 @@
private float mFocusX;
private float mFocusY;
- private boolean mDoubleTapScales;
+ private boolean mQuickScaleEnabled;
private float mCurrSpan;
private float mPrevSpan;
@@ -159,6 +159,7 @@
private static final long TOUCH_STABILIZE_TIME = 128; // ms
private static final int DOUBLE_TAP_MODE_NONE = 0;
private static final int DOUBLE_TAP_MODE_IN_PROGRESS = 1;
+ private static final float SCALE_FACTOR = .5f;
/**
@@ -197,7 +198,7 @@
* @throws NullPointerException if {@code listener} is null.
*/
public ScaleGestureDetector(Context context, OnScaleGestureListener listener,
- Handler handler) {
+ Handler handler) {
mContext = context;
mListener = listener;
mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
@@ -306,7 +307,7 @@
final int action = event.getActionMasked();
// Forward the event to check for double tap gesture
- if (mDoubleTapScales) {
+ if (mQuickScaleEnabled) {
mGestureDetector.onTouchEvent(event);
}
@@ -409,7 +410,9 @@
mPrevSpanY = mCurrSpanY = spanY;
mInitialSpan = mPrevSpan = mCurrSpan = span;
}
- if (!mInProgress && span >= mMinSpan &&
+
+ final int minSpan = inDoubleTapMode() ? mSpanSlop : mMinSpan;
+ if (!mInProgress && span >= minSpan &&
(wasInProgress || Math.abs(span - mInitialSpan) > mSpanSlop)) {
mPrevSpanX = mCurrSpanX = spanX;
mPrevSpanY = mCurrSpanY = spanY;
@@ -453,8 +456,8 @@
* @param scales true to enable quick scaling, false to disable
*/
public void setQuickScaleEnabled(boolean scales) {
- mDoubleTapScales = scales;
- if (mDoubleTapScales && mGestureDetector == null) {
+ mQuickScaleEnabled = scales;
+ if (mQuickScaleEnabled && mGestureDetector == null) {
GestureDetector.SimpleOnGestureListener gestureListener =
new GestureDetector.SimpleOnGestureListener() {
@Override
@@ -464,11 +467,19 @@
mDoubleTapMode = DOUBLE_TAP_MODE_IN_PROGRESS;
return true;
}
- };
+ };
mGestureDetector = new GestureDetector(mContext, gestureListener, mHandler);
}
}
+ /**
+ * Return whether the quick scale gesture, in which the user performs a double tap followed by a
+ * swipe, should perform scaling. {@see #setQuickScaleEnabled(boolean)}.
+ */
+ public boolean isQuickScaleEnabled() {
+ return mQuickScaleEnabled;
+ }
+
/**
* Returns {@code true} if a scale gesture is in progress.
*/
@@ -572,11 +583,15 @@
* @return The current scaling factor.
*/
public float getScaleFactor() {
- if (inDoubleTapMode() && mEventBeforeOrAboveStartingGestureEvent) {
+ if (inDoubleTapMode()) {
// Drag is moving up; the further away from the gesture
// start, the smaller the span should be, the closer,
// the larger the span, and therefore the larger the scale
- return (1 / mCurrSpan) / (1 / mPrevSpan);
+ final boolean scaleUp =
+ (mEventBeforeOrAboveStartingGestureEvent && (mCurrSpan < mPrevSpan)) ||
+ (!mEventBeforeOrAboveStartingGestureEvent && (mCurrSpan > mPrevSpan));
+ final float spanDiff = (Math.abs(1 - (mCurrSpan / mPrevSpan)) * SCALE_FACTOR);
+ return mPrevSpan <= 0 ? 1 : scaleUp ? (1 + spanDiff) : (1 - spanDiff);
}
return mPrevSpan > 0 ? mCurrSpan / mPrevSpan : 1;
}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 409db84..1bfda2d 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -116,6 +116,7 @@
*
* @param surfaceTexture The {@link SurfaceTexture} that is updated by this
* Surface.
+ * @throws OutOfResourcesException if the surface could not be created.
*/
public Surface(SurfaceTexture surfaceTexture) {
if (surfaceTexture == null) {
@@ -124,12 +125,7 @@
synchronized (mLock) {
mName = surfaceTexture.toString();
- try {
- setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
- } catch (OutOfResourcesException ex) {
- // We can't throw OutOfResourcesException because it would be an API change.
- throw new RuntimeException(ex);
- }
+ setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
}
}
@@ -229,9 +225,12 @@
* The caller may also pass <code>null</code> instead, in the case where the
* entire surface should be redrawn.
* @return A canvas for drawing into the surface.
+ *
+ * @throws IllegalArgumentException If the inOutDirty rectangle is not valid.
+ * @throws OutOfResourcesException If the canvas cannot be locked.
*/
public Canvas lockCanvas(Rect inOutDirty)
- throws OutOfResourcesException, IllegalArgumentException {
+ throws Surface.OutOfResourcesException, IllegalArgumentException {
synchronized (mLock) {
checkNotReleasedLocked();
if (mLockedObject != 0) {
@@ -239,7 +238,7 @@
// double-lock, but that won't happen if mNativeObject was updated. We can't
// abandon the old mLockedObject because it might still be in use, so instead
// we just refuse to re-lock the Surface.
- throw new RuntimeException("Surface was already locked");
+ throw new IllegalStateException("Surface was already locked");
}
mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
return mCanvas;
@@ -266,7 +265,7 @@
Integer.toHexString(mLockedObject) +")");
}
if (mLockedObject == 0) {
- throw new RuntimeException("Surface was not locked");
+ throw new IllegalStateException("Surface was not locked");
}
nativeUnlockCanvasAndPost(mLockedObject, canvas);
nativeRelease(mLockedObject);
@@ -411,9 +410,11 @@
}
/**
- * Exception thrown when a surface couldn't be created or resized.
+ * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
+ * when a SurfaceTexture could not successfully be allocated.
*/
- public static class OutOfResourcesException extends Exception {
+ @SuppressWarnings("serial")
+ public static class OutOfResourcesException extends RuntimeException {
public OutOfResourcesException() {
}
public OutOfResourcesException(String name) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index dc31e0b..b22d5cf 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -24,6 +24,7 @@
import android.os.IBinder;
import android.os.SystemProperties;
import android.util.Log;
+import android.view.Surface.OutOfResourcesException;
/**
* SurfaceControl
@@ -75,23 +76,12 @@
private final CloseGuard mCloseGuard = CloseGuard.get();
- private String mName;
+ private final String mName;
int mNativeObject; // package visibility only for Surface.java access
private static final boolean HEADLESS = "1".equals(
SystemProperties.get("ro.config.headless", "0"));
- /**
- * Exception thrown when a surface couldn't be created or resized.
- */
- public static class OutOfResourcesException extends Exception {
- public OutOfResourcesException() {
- }
- public OutOfResourcesException(String name) {
- super(name);
- }
- }
-
/* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */
/**
@@ -220,6 +210,8 @@
* @param h The surface initial height.
* @param flags The surface creation flags. Should always include {@link #HIDDEN}
* in the creation flags.
+ *
+ * @throws throws OutOfResourcesException If the SurfaceControl cannot be created.
*/
public SurfaceControl(SurfaceSession session,
String name, int w, int h, int format, int flags)
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 8b2b556..1e4b29f 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -43,7 +43,7 @@
* You can control the format of this surface and, if you like, its size; the
* SurfaceView takes care of placing the surface at the correct location on the
* screen
- *
+ *
* <p>The surface is Z ordered so that it is behind the window holding its
* SurfaceView; the SurfaceView punches a hole in its window to allow its
* surface to be displayed. The view hierarchy will take care of correctly
@@ -52,7 +52,7 @@
* buttons on top of the Surface, though note however that it can have an
* impact on performance since a full alpha-blended composite will be performed
* each time the Surface changes.
- *
+ *
* <p> The transparent region that makes the surface visible is based on the
* layout positions in the view hierarchy. If the post-layout transform
* properties are used to draw a sibling view on top of the SurfaceView, the
@@ -60,16 +60,16 @@
*
* <p>Access to the underlying surface is provided via the SurfaceHolder interface,
* which can be retrieved by calling {@link #getHolder}.
- *
+ *
* <p>The Surface will be created for you while the SurfaceView's window is
* visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
* and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
* Surface is created and destroyed as the window is shown and hidden.
- *
+ *
* <p>One of the purposes of this class is to provide a surface in which a
* secondary thread can render into the screen. If you are going to use it
* this way, you need to be aware of some threading semantics:
- *
+ *
* <ul>
* <li> All SurfaceView and
* {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
@@ -91,7 +91,7 @@
= new ArrayList<SurfaceHolder.Callback>();
final int[] mLocation = new int[2];
-
+
final ReentrantLock mSurfaceLock = new ReentrantLock();
final Surface mSurface = new Surface(); // Current surface in use
final Surface mNewSurface = new Surface(); // New surface we are switching to
@@ -106,13 +106,13 @@
final Rect mOverscanInsets = new Rect();
final Rect mContentInsets = new Rect();
final Configuration mConfiguration = new Configuration();
-
+
static final int KEEP_SCREEN_ON_MSG = 1;
static final int GET_NEW_SURFACE_MSG = 2;
static final int UPDATE_WINDOW_MSG = 3;
-
+
int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
-
+
boolean mIsCreating = false;
final Handler mHandler = new Handler() {
@@ -131,14 +131,15 @@
}
}
};
-
+
final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
= new ViewTreeObserver.OnScrollChangedListener() {
+ @Override
public void onScrollChanged() {
updateWindow(false, false);
}
};
-
+
boolean mRequestedVisible = false;
boolean mWindowVisibility = false;
boolean mViewVisibility = false;
@@ -152,7 +153,7 @@
boolean mHaveFrame = false;
boolean mSurfaceCreated = false;
long mLastLockTime = 0;
-
+
boolean mVisible = false;
int mLeft = -1;
int mTop = -1;
@@ -169,7 +170,7 @@
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
- // reposition ourselves where the surface is
+ // reposition ourselves where the surface is
mHaveFrame = getWidth() > 0 && getHeight() > 0;
updateWindow(false, false);
return true;
@@ -181,7 +182,7 @@
super(context);
init();
}
-
+
public SurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
@@ -195,11 +196,11 @@
private void init() {
setWillNotDraw(true);
}
-
+
/**
* Return the SurfaceHolder providing access and control over this
* SurfaceView's underlying surface.
- *
+ *
* @return SurfaceHolder The holder of the surface.
*/
public SurfaceHolder getHolder() {
@@ -285,7 +286,7 @@
: getDefaultSize(0, heightMeasureSpec);
setMeasuredDimension(width, height);
}
-
+
/** @hide */
@Override
protected boolean setFrame(int left, int top, int right, int bottom) {
@@ -299,7 +300,7 @@
if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
return super.gatherTransparentRegion(region);
}
-
+
boolean opaque = true;
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
// this view draws, remove it from the transparent region
@@ -350,10 +351,10 @@
* regular surface view in the window (but still behind the window itself).
* This is typically used to place overlays on top of an underlying media
* surface view.
- *
+ *
* <p>Note that this must be set before the surface view's containing
* window is attached to the window manager.
- *
+ *
* <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
*/
public void setZOrderMediaOverlay(boolean isMediaOverlay) {
@@ -361,7 +362,7 @@
? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
: WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
}
-
+
/**
* Control whether the surface view's surface is placed on top of its
* window. Normally it is placed behind the window, to allow it to
@@ -369,10 +370,10 @@
* hierarchy. By setting this, you cause it to be placed above the
* window. This means that none of the contents of the window this
* SurfaceView is in will be visible on top of its surface.
- *
+ *
* <p>Note that this must be set before the surface view's containing
* window is attached to the window manager.
- *
+ *
* <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
*/
public void setZOrderOnTop(boolean onTop) {
@@ -427,7 +428,7 @@
if (mTranslator != null) {
mSurface.setCompatibilityTranslator(mTranslator);
}
-
+
int myWidth = mRequestedWidth;
if (myWidth <= 0) myWidth = getWidth();
int myHeight = mRequestedHeight;
@@ -458,7 +459,7 @@
mFormat = mRequestedFormat;
// Scaling/Translate window's layout here because mLayout is not used elsewhere.
-
+
// Places the window relative
mLayout.x = mLeft;
mLayout.y = mTop;
@@ -467,7 +468,7 @@
if (mTranslator != null) {
mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
}
-
+
mLayout.format = mRequestedFormat;
mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
@@ -489,7 +490,7 @@
mSession.addToDisplayWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
mVisible ? VISIBLE : GONE, display.getDisplayId(), mContentInsets);
}
-
+
boolean realSizeChanged;
boolean reportDrawNeeded;
@@ -501,7 +502,7 @@
reportDrawNeeded = mReportDrawNeeded;
mReportDrawNeeded = false;
mDrawingStopped = !visible;
-
+
if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface);
relayoutResult = mSession.relayout(
@@ -527,7 +528,7 @@
mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
}
-
+
final int surfaceWidth = mSurfaceFrame.right;
final int surfaceHeight = mSurfaceFrame.bottom;
realSizeChanged = mLastSurfaceWidth != surfaceWidth
@@ -667,10 +668,12 @@
}
}
+ @Override
public void dispatchAppVisibility(boolean visible) {
// The point of SurfaceView is to let the app control the surface.
}
+ @Override
public void dispatchGetNewSurface() {
SurfaceView surfaceView = mSurfaceView.get();
if (surfaceView != null) {
@@ -679,10 +682,12 @@
}
}
+ @Override
public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
}
+ @Override
public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
}
@@ -690,30 +695,34 @@
int mCurHeight = -1;
}
- private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
-
+ private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
+
private static final String LOG_TAG = "SurfaceHolder";
-
+
+ @Override
public boolean isCreating() {
return mIsCreating;
}
+ @Override
public void addCallback(Callback callback) {
synchronized (mCallbacks) {
- // This is a linear search, but in practice we'll
+ // This is a linear search, but in practice we'll
// have only a couple callbacks, so it doesn't matter.
- if (mCallbacks.contains(callback) == false) {
+ if (mCallbacks.contains(callback) == false) {
mCallbacks.add(callback);
}
}
}
+ @Override
public void removeCallback(Callback callback) {
synchronized (mCallbacks) {
mCallbacks.remove(callback);
}
}
-
+
+ @Override
public void setFixedSize(int width, int height) {
if (mRequestedWidth != width || mRequestedHeight != height) {
mRequestedWidth = width;
@@ -722,6 +731,7 @@
}
}
+ @Override
public void setSizeFromLayout() {
if (mRequestedWidth != -1 || mRequestedHeight != -1) {
mRequestedWidth = mRequestedHeight = -1;
@@ -729,6 +739,7 @@
}
}
+ @Override
public void setFormat(int format) {
// for backward compatibility reason, OPAQUE always
@@ -745,15 +756,17 @@
/**
* @deprecated setType is now ignored.
*/
+ @Override
@Deprecated
public void setType(int type) { }
+ @Override
public void setKeepScreenOn(boolean screenOn) {
Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
msg.arg1 = screenOn ? 1 : 0;
mHandler.sendMessage(msg);
}
-
+
/**
* Gets a {@link Canvas} for drawing into the SurfaceView's Surface
*
@@ -763,6 +776,7 @@
* The caller must redraw the entire surface.
* @return A canvas for drawing into the surface.
*/
+ @Override
public Canvas lockCanvas() {
return internalLockCanvas(null);
}
@@ -782,6 +796,7 @@
* entire surface should be redrawn.
* @return A canvas for drawing into the surface.
*/
+ @Override
public Canvas lockCanvas(Rect inOutDirty) {
return internalLockCanvas(inOutDirty);
}
@@ -806,7 +821,7 @@
mLastLockTime = SystemClock.uptimeMillis();
return c;
}
-
+
// If the Surface is not ready to be drawn, then return null,
// but throttle calls to this function so it isn't called more
// than every 100ms.
@@ -821,7 +836,7 @@
}
mLastLockTime = now;
mSurfaceLock.unlock();
-
+
return null;
}
@@ -831,15 +846,18 @@
*
* @param canvas The canvas previously obtained from {@link #lockCanvas}.
*/
+ @Override
public void unlockCanvasAndPost(Canvas canvas) {
mSurface.unlockCanvasAndPost(canvas);
mSurfaceLock.unlock();
}
+ @Override
public Surface getSurface() {
return mSurface;
}
+ @Override
public Rect getSurfaceFrame() {
return mSurfaceFrame;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 30531ed..a5db6ee 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2134,6 +2134,50 @@
<< PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
/**
+ * Shift for the bits in {@link #mPrivateFlags2} related to the
+ * "accessibilityLiveRegion" attribute.
+ */
+ static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 22;
+
+ /**
+ * Live region mode specifying that accessibility services should not
+ * automatically announce changes to this view. This is the default live
+ * region mode for most views.
+ * <p>
+ * Use with {@link #setAccessibilityLiveRegion(int)}.
+ */
+ public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000;
+
+ /**
+ * Live region mode specifying that accessibility services should announce
+ * changes to this view.
+ * <p>
+ * Use with {@link #setAccessibilityLiveRegion(int)}.
+ */
+ public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001;
+
+ /**
+ * Live region mode specifying that accessibility services should interrupt
+ * ongoing speech to immediately announce changes to this view.
+ * <p>
+ * Use with {@link #setAccessibilityLiveRegion(int)}.
+ */
+ public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002;
+
+ /**
+ * The default whether the view is important for accessibility.
+ */
+ static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE;
+
+ /**
+ * Mask for obtaining the bits which specify a view's accessibility live
+ * region mode.
+ */
+ static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE
+ | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE)
+ << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT;
+
+ /**
* Flag indicating whether a view has accessibility focus.
*/
static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000;
@@ -3763,6 +3807,9 @@
setImportantForAccessibility(a.getInt(attr,
IMPORTANT_FOR_ACCESSIBILITY_DEFAULT));
break;
+ case R.styleable.View_accessibilityLiveRegion:
+ setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT));
+ break;
}
}
@@ -4710,7 +4757,8 @@
if (gainFocus) {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
} else {
- notifyViewAccessibilityStateChangedIfNeeded();
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
InputMethodManager imm = InputMethodManager.peekInstance();
@@ -5431,7 +5479,8 @@
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
notifySubtreeAccessibilityStateChangedIfNeeded();
} else {
- notifyViewAccessibilityStateChangedIfNeeded();
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION);
}
}
@@ -6954,6 +7003,58 @@
}
/**
+ * Sets the live region mode for this view. This indicates to accessibility
+ * services whether they should automatically notify the user about changes
+ * to the view's content description or text, or to the content descriptions
+ * or text of the view's children (where applicable).
+ * <p>
+ * For example, in a login screen with a TextView that displays an "incorrect
+ * password" notification, that view should be marked as a live region with
+ * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}.
+ * <p>
+ * To disable change notifications for this view, use
+ * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region
+ * mode for most views.
+ * <p>
+ * To indicate that the user should be notified of changes, use
+ * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}.
+ * <p>
+ * If the view's changes should interrupt ongoing speech and notify the user
+ * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}.
+ *
+ * @param mode The live region mode for this view, one of:
+ * <ul>
+ * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE}
+ * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE}
+ * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}
+ * </ul>
+ * @attr ref android.R.styleable#View_accessibilityLiveRegion
+ */
+ public void setAccessibilityLiveRegion(int mode) {
+ if (mode != getAccessibilityLiveRegion()) {
+ mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK;
+ mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT)
+ & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK;
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ }
+ }
+
+ /**
+ * Gets the live region mode for this View.
+ *
+ * @return The live region mode for the view.
+ *
+ * @attr ref android.R.styleable#View_accessibilityLiveRegion
+ *
+ * @see #setAccessibilityLiveRegion(int)
+ */
+ public int getAccessibilityLiveRegion() {
+ return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK)
+ >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT;
+ }
+
+ /**
* Sets how to determine whether this view is important for accessibility
* which is if it fires accessibility events and if it is reported to
* accessibility services that query the screen.
@@ -6975,7 +7076,8 @@
if (oldIncludeForAccessibility != includeForAccessibility()) {
notifySubtreeAccessibilityStateChangedIfNeeded();
} else {
- notifyViewAccessibilityStateChangedIfNeeded();
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
}
}
@@ -6997,7 +7099,8 @@
return false;
case IMPORTANT_FOR_ACCESSIBILITY_AUTO:
return isActionableForAccessibility() || hasListenersForAccessibility()
- || getAccessibilityNodeProvider() != null;
+ || getAccessibilityNodeProvider() != null
+ || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE;
default:
throw new IllegalArgumentException("Unknow important for accessibility mode: "
+ mode);
@@ -7094,7 +7197,7 @@
*
* @hide
*/
- public void notifyViewAccessibilityStateChangedIfNeeded() {
+ public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) {
if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
return;
}
@@ -7102,7 +7205,7 @@
mSendViewStateChangedAccessibilityEvent =
new SendViewStateChangedAccessibilityEvent();
}
- mSendViewStateChangedAccessibilityEvent.runOrPost();
+ mSendViewStateChangedAccessibilityEvent.runOrPost(changeType);
}
/**
@@ -7124,7 +7227,8 @@
mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED;
if (mParent != null) {
try {
- mParent.childAccessibilityStateChanged(this);
+ mParent.notifySubtreeAccessibilityStateChanged(
+ this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
} catch (AbstractMethodError e) {
Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
" does not fully implement ViewParent", e);
@@ -7251,7 +7355,8 @@
|| getAccessibilitySelectionEnd() != end)
&& (start == end)) {
setAccessibilitySelection(start, end);
- notifyViewAccessibilityStateChangedIfNeeded();
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
return true;
}
} break;
@@ -8008,7 +8113,7 @@
public boolean onKeyDown(int keyCode, KeyEvent event) {
boolean result = false;
- if (KeyEvent.isConfirmKey(event.getKeyCode())) {
+ if (KeyEvent.isConfirmKey(keyCode)) {
if ((mViewFlags & ENABLED_MASK) == DISABLED) {
return true;
}
@@ -8050,28 +8155,21 @@
* @param event The KeyEvent object that defines the button action.
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
- boolean result = false;
+ if (KeyEvent.isConfirmKey(keyCode)) {
+ if ((mViewFlags & ENABLED_MASK) == DISABLED) {
+ return true;
+ }
+ if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) {
+ setPressed(false);
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_ENTER: {
- if ((mViewFlags & ENABLED_MASK) == DISABLED) {
- return true;
+ if (!mHasPerformedLongPress) {
+ // This is a tap, so remove the longpress check
+ removeLongPressCallback();
+ return performClick();
}
- if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) {
- setPressed(false);
-
- if (!mHasPerformedLongPress) {
- // This is a tap, so remove the longpress check
- removeLongPressCallback();
-
- result = performClick();
- }
- }
- break;
}
}
- return result;
+ return false;
}
/**
@@ -8832,11 +8930,12 @@
if (oldIncludeForAccessibility != includeForAccessibility()) {
notifySubtreeAccessibilityStateChangedIfNeeded();
} else {
- notifyViewAccessibilityStateChangedIfNeeded();
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
- }
- if ((changed & ENABLED_MASK) != 0) {
- notifyViewAccessibilityStateChangedIfNeeded();
+ } else if ((changed & ENABLED_MASK) != 0) {
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
}
}
@@ -15437,7 +15536,8 @@
invalidate(true);
refreshDrawableState();
dispatchSetSelected(selected);
- notifyViewAccessibilityStateChangedIfNeeded();
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
}
@@ -19179,21 +19279,44 @@
}
private class SendViewStateChangedAccessibilityEvent implements Runnable {
+ private int mChangeTypes = 0;
private boolean mPosted;
+ private boolean mPostedWithDelay;
private long mLastEventTimeMillis;
+ @Override
public void run() {
mPosted = false;
+ mPostedWithDelay = false;
mLastEventTimeMillis = SystemClock.uptimeMillis();
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
- AccessibilityEvent event = AccessibilityEvent.obtain();
+ final AccessibilityEvent event = AccessibilityEvent.obtain();
event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
- event.setContentChangeType(AccessibilityEvent.CONTENT_CHANGE_TYPE_NODE);
+ event.setContentChangeTypes(mChangeTypes);
sendAccessibilityEventUnchecked(event);
}
+ mChangeTypes = 0;
}
- public void runOrPost() {
+ public void runOrPost(int changeType) {
+ mChangeTypes |= changeType;
+
+ // If this is a live region or the child of a live region, collect
+ // all events from this frame and send them on the next frame.
+ if (inLiveRegion()) {
+ // If we're already posted with a delay, remove that.
+ if (mPostedWithDelay) {
+ removeCallbacks(this);
+ mPostedWithDelay = false;
+ }
+ // Only post if we're not already posted.
+ if (!mPosted) {
+ post(this);
+ mPosted = true;
+ }
+ return;
+ }
+
if (mPosted) {
return;
}
@@ -19206,10 +19329,28 @@
} else {
postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
mPosted = true;
+ mPostedWithDelay = true;
}
}
}
+ private boolean inLiveRegion() {
+ if (getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) {
+ return true;
+ }
+
+ ViewParent parent = getParent();
+ while (parent instanceof View) {
+ if (((View) parent).getAccessibilityLiveRegion()
+ != View.ACCESSIBILITY_LIVE_REGION_NONE) {
+ return true;
+ }
+ parent = parent.getParent();
+ }
+
+ return false;
+ }
+
/**
* Dump all private flags in readable format, useful for documentation and
* sanity checking.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index faeee3f..9414237 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -38,6 +38,7 @@
import android.util.Pools.SynchronizedPool;
import android.util.SparseArray;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
@@ -2528,10 +2529,14 @@
}
@Override
- public void childAccessibilityStateChanged(View root) {
- if (mParent != null) {
+ public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
+ // If this is a live region, we should send a subtree change event
+ // from this view. Otherwise, we can let it propagate up.
+ if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) {
+ notifyViewAccessibilityStateChangedIfNeeded(changeType);
+ } else if (mParent != null) {
try {
- mParent.childAccessibilityStateChanged(root);
+ mParent.notifySubtreeAccessibilityStateChanged(this, source, changeType);
} catch (AbstractMethodError e) {
Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
" does not fully implement ViewParent", e);
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 35113db..01376934 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -309,12 +309,21 @@
public ViewParent getParentForAccessibility();
/**
- * A child notifies its parent that the accessibility state of a subtree rooted
- * at a given node changed. That is the structure of the subtree is different.
- *
- * @param root The root of the changed subtree.
+ * Notifies a view parent that the accessibility state of one of its
+ * descendants has changed and that the structure of the subtree is
+ * different.
+ * @param child The direct child whose subtree has changed.
+ * @param source The descendant view that changed.
+ * @param changeType A bit mask of the types of changes that occurred. One
+ * or more of:
+ * <ul>
+ * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION}
+ * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_SUBTREE}
+ * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT}
+ * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED}
+ * </ul>
*/
- public void childAccessibilityStateChanged(View root);
+ public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType);
/**
* Tells if this view parent can resolve the layout direction.
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index cea7e49..67a94be 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -702,6 +702,9 @@
@Override
public void run() {
mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ if (mView.isAttachedToWindow()) {
+ mView.buildLayer();
+ }
}
};
final int currentLayerType = mView.getLayerType();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index c7d61eb0..38f28ae 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -68,6 +68,7 @@
import android.view.animation.Interpolator;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
+import android.view.Surface.OutOfResourcesException;
import android.widget.Scroller;
import com.android.internal.R;
@@ -187,7 +188,7 @@
InputQueue mInputQueue;
FallbackEventHandler mFallbackEventHandler;
Choreographer mChoreographer;
-
+
final Rect mTempRect; // used in the transaction to not thrash the heap.
final Rect mVisRect; // used to retrieve visible rect of focused view.
@@ -278,8 +279,8 @@
volatile Object mLocalDragState;
final PointF mDragPoint = new PointF();
final PointF mLastTouchPoint = new PointF();
-
- private boolean mProfileRendering;
+
+ private boolean mProfileRendering;
private Choreographer.FrameCallback mRenderProfiler;
private boolean mRenderProfilingEnabled;
@@ -291,7 +292,7 @@
private int mFpsNumFrames;
private final ArrayList<DisplayList> mDisplayLists = new ArrayList<DisplayList>();
-
+
/**
* see {@link #playSoundEffect(int)}
*/
@@ -332,7 +333,7 @@
int localValue;
int localChanges;
}
-
+
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
@@ -383,13 +384,13 @@
}
}
}
-
+
public static void addConfigCallback(ComponentCallbacks callback) {
synchronized (sConfigCallbacks) {
sConfigCallbacks.add(callback);
}
}
-
+
// FIXME for perf testing only
private boolean mProfile = false;
@@ -514,7 +515,7 @@
attrs.restore();
}
}
-
+
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
}
@@ -680,7 +681,7 @@
if (mTranslator != null) return;
// Try to enable hardware acceleration if requested
- final boolean hardwareAccelerated =
+ final boolean hardwareAccelerated =
(attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
if (hardwareAccelerated) {
@@ -707,7 +708,7 @@
// Don't enable hardware acceleration when we're not on the main thread
if (!HardwareRenderer.sSystemRendererDisabled &&
Looper.getMainLooper() != Looper.myLooper()) {
- Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+ Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+ "acceleration outside of the main thread, aborting");
return;
}
@@ -918,6 +919,7 @@
return r.intersect(0, 0, mWidth, mHeight);
}
+ @Override
public void bringChildToFront(View child) {
}
@@ -1152,9 +1154,9 @@
mLastInCompatMode = true;
}
}
-
+
mWindowAttributesChangesFlag = 0;
-
+
Rect frame = mWinFrame;
if (mFirst) {
mFullRedrawNeeded = true;
@@ -1522,7 +1524,7 @@
try {
hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
mHolder.getSurface());
- } catch (Surface.OutOfResourcesException e) {
+ } catch (OutOfResourcesException e) {
handleOutOfResourcesException(e);
return;
}
@@ -1549,7 +1551,7 @@
mFullRedrawNeeded = true;
try {
mAttachInfo.mHardwareRenderer.updateSurface(mHolder.getSurface());
- } catch (Surface.OutOfResourcesException e) {
+ } catch (OutOfResourcesException e) {
handleOutOfResourcesException(e);
return;
}
@@ -1644,23 +1646,23 @@
|| mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
-
+
if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
+ mWidth + " measuredWidth=" + host.getMeasuredWidth()
+ " mHeight=" + mHeight
+ " measuredHeight=" + host.getMeasuredHeight()
+ " coveredInsetsChanged=" + contentInsetsChanged);
-
+
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
-
+
// Implementation of weights from WindowManager.LayoutParams
// We just grow the dimensions as needed and re-measure if
// needs be
int width = host.getMeasuredWidth();
int height = host.getMeasuredHeight();
boolean measureAgain = false;
-
+
if (lp.horizontalWeight > 0.0f) {
width += (int) ((mWidth - width) * lp.horizontalWeight);
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
@@ -1673,14 +1675,14 @@
MeasureSpec.EXACTLY);
measureAgain = true;
}
-
+
if (measureAgain) {
if (DEBUG_LAYOUT) Log.v(TAG,
"And hey let's measure once more: width=" + width
+ " height=" + height);
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
-
+
layoutRequested = true;
}
}
@@ -1851,7 +1853,7 @@
}
mPendingTransitions.clear();
}
-
+
performDraw();
}
} else {
@@ -2078,6 +2080,7 @@
return validLayoutRequesters;
}
+ @Override
public void requestTransparentRegion(View child) {
// the test below should not fail unless someone is messing with us
checkThread();
@@ -2128,10 +2131,12 @@
int mResizeAlpha;
final Paint mResizePaint = new Paint();
+ @Override
public void onHardwarePreDraw(HardwareCanvas canvas) {
canvas.translate(0, -mHardwareYOffset);
}
+ @Override
public void onHardwarePostDraw(HardwareCanvas canvas) {
if (mResizeBuffer != null) {
mResizePaint.setAlpha(mResizeAlpha);
@@ -2365,7 +2370,7 @@
try {
attachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
mHolder.getSurface());
- } catch (Surface.OutOfResourcesException e) {
+ } catch (OutOfResourcesException e) {
handleOutOfResourcesException(e);
return;
}
@@ -2741,6 +2746,7 @@
mAccessibilityFocusedVirtualView = node;
}
+ @Override
public void requestChildFocus(View child, View focused) {
if (DEBUG_INPUT_RESIZE) {
Log.v(TAG, "Request child focus: focus now " + focused);
@@ -2749,6 +2755,7 @@
scheduleTraversals();
}
+ @Override
public void clearChildFocus(View child) {
if (DEBUG_INPUT_RESIZE) {
Log.v(TAG, "Clearing child focus");
@@ -2762,6 +2769,7 @@
return null;
}
+ @Override
public void focusableViewAvailable(View v) {
checkThread();
if (mView != null) {
@@ -2783,6 +2791,7 @@
}
}
+ @Override
public void recomputeViewAttributes(View child) {
checkThread();
if (mView == child) {
@@ -3076,7 +3085,7 @@
try {
mAttachInfo.mHardwareRenderer.initializeIfNeeded(
mWidth, mHeight, mHolder.getSurface());
- } catch (Surface.OutOfResourcesException e) {
+ } catch (OutOfResourcesException e) {
Log.e(TAG, "OutOfResourcesException locking surface", e);
try {
if (!mWindowSession.outOfMemory(mWindow)) {
@@ -4990,7 +4999,7 @@
// most recent data.
mSeq = args.seq;
mAttachInfo.mForceReportNewAttributes = true;
- scheduleTraversals();
+ scheduleTraversals();
}
if (mView == null) return;
if (args.localChanges != 0) {
@@ -5080,7 +5089,7 @@
if (restore) {
params.restore();
}
-
+
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
@@ -5093,6 +5102,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public void playSoundEffect(int effectId) {
checkThread();
@@ -5133,6 +5143,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public boolean performHapticFeedback(int effectId, boolean always) {
try {
return mWindowSession.performHapticFeedback(mWindow, effectId, always);
@@ -5144,6 +5155,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public View focusSearch(View focused, int direction) {
checkThread();
if (!(mView instanceof ViewGroup)) {
@@ -5155,7 +5167,7 @@
public void debug() {
mView.debug();
}
-
+
public void dumpGfxInfo(int[] info) {
info[0] = info[1] = 0;
if (mView != null) {
@@ -5574,8 +5586,8 @@
final class InvalidateOnAnimationRunnable implements Runnable {
private boolean mPosted;
- private ArrayList<View> mViews = new ArrayList<View>();
- private ArrayList<AttachInfo.InvalidateInfo> mViewRects =
+ private final ArrayList<View> mViews = new ArrayList<View>();
+ private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
new ArrayList<AttachInfo.InvalidateInfo>();
private View[] mTempViews;
private AttachInfo.InvalidateInfo[] mTempViewRects;
@@ -5795,12 +5807,12 @@
* This event is send at most once every
* {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
*/
- private void postSendWindowContentChangedCallback(View source) {
+ private void postSendWindowContentChangedCallback(View source, int changeType) {
if (mSendWindowContentChangedAccessibilityEvent == null) {
mSendWindowContentChangedAccessibilityEvent =
new SendWindowContentChangedAccessibilityEvent();
}
- mSendWindowContentChangedAccessibilityEvent.runOrPost(source);
+ mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
}
/**
@@ -5813,20 +5825,25 @@
}
}
+ @Override
public boolean showContextMenuForChild(View originalView) {
return false;
}
+ @Override
public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
return null;
}
+ @Override
public void createContextMenu(ContextMenu menu) {
}
+ @Override
public void childDrawableStateChanged(View child) {
}
+ @Override
public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
if (mView == null) {
return false;
@@ -5867,8 +5884,8 @@
}
@Override
- public void childAccessibilityStateChanged(View child) {
- postSendWindowContentChangedCallback(child);
+ public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
+ postSendWindowContentChangedCallback(source, changeType);
}
@Override
@@ -5958,10 +5975,12 @@
}
}
+ @Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
// ViewAncestor never intercepts touch event, so this can be a no-op
}
+ @Override
public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
if (rectangle != null) {
@@ -5977,6 +5996,7 @@
return scrolled;
}
+ @Override
public void childHasTransientStateChanged(View child, boolean hasTransientState) {
// Do nothing.
}
@@ -5997,20 +6017,23 @@
// Not currently interesting -- from changing between fixed and layout size.
}
+ @Override
public void setFormat(int format) {
((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
}
+ @Override
public void setType(int type) {
((RootViewSurfaceTaker)mView).setSurfaceType(type);
}
-
+
@Override
public void onUpdateSurface() {
// We take care of format and type changes on our own.
throw new IllegalStateException("Shouldn't be here");
}
+ @Override
public boolean isCreating() {
return mIsCreating;
}
@@ -6020,7 +6043,8 @@
throw new UnsupportedOperationException(
"Currently only support sizing from layout");
}
-
+
+ @Override
public void setKeepScreenOn(boolean screenOn) {
((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
}
@@ -6035,6 +6059,7 @@
mWindowSession = viewAncestor.mWindowSession;
}
+ @Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
@@ -6052,6 +6077,7 @@
}
}
+ @Override
public void dispatchAppVisibility(boolean visible) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
@@ -6059,6 +6085,7 @@
}
}
+ @Override
public void dispatchScreenState(boolean on) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
@@ -6066,6 +6093,7 @@
}
}
+ @Override
public void dispatchGetNewSurface() {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
@@ -6073,6 +6101,7 @@
}
}
+ @Override
public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
@@ -6089,6 +6118,7 @@
}
}
+ @Override
public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
@@ -6119,14 +6149,16 @@
}
}
}
-
+
+ @Override
public void closeSystemDialogs(String reason) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchCloseSystemDialogs(reason);
}
}
-
+
+ @Override
public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
boolean sync) {
if (sync) {
@@ -6137,6 +6169,7 @@
}
}
+ @Override
public void dispatchWallpaperCommand(String action, int x, int y,
int z, Bundle extras, boolean sync) {
if (sync) {
@@ -6148,6 +6181,7 @@
}
/* Drag/drop */
+ @Override
public void dispatchDragEvent(DragEvent event) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
@@ -6155,6 +6189,7 @@
}
}
+ @Override
public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
int localValue, int localChanges) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
@@ -6164,6 +6199,7 @@
}
}
+ @Override
public void doneAnimating() {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
@@ -6178,50 +6214,63 @@
}
}
- private SurfaceHolder mHolder = new SurfaceHolder() {
+ private final SurfaceHolder mHolder = new SurfaceHolder() {
// we only need a SurfaceHolder for opengl. it would be nice
// to implement everything else though, especially the callback
// support (opengl doesn't make use of it right now, but eventually
// will).
+ @Override
public Surface getSurface() {
return mSurface;
}
+ @Override
public boolean isCreating() {
return false;
}
+ @Override
public void addCallback(Callback callback) {
}
+ @Override
public void removeCallback(Callback callback) {
}
+ @Override
public void setFixedSize(int width, int height) {
}
+ @Override
public void setSizeFromLayout() {
}
+ @Override
public void setFormat(int format) {
}
+ @Override
public void setType(int type) {
}
+ @Override
public void setKeepScreenOn(boolean screenOn) {
}
+ @Override
public Canvas lockCanvas() {
return null;
}
+ @Override
public Canvas lockCanvas(Rect dirty) {
return null;
}
+ @Override
public void unlockCanvasAndPost(Canvas canvas) {
}
+ @Override
public Rect getSurfaceFrame() {
return null;
}
@@ -6316,6 +6365,7 @@
*/
final class AccessibilityInteractionConnectionManager
implements AccessibilityStateChangeListener {
+ @Override
public void onAccessibilityStateChanged(boolean enabled) {
if (enabled) {
ensureConnection();
@@ -6488,16 +6538,19 @@
}
private class SendWindowContentChangedAccessibilityEvent implements Runnable {
+ private int mChangeTypes = 0;
+
public View mSource;
public long mLastEventTimeMillis;
+ @Override
public void run() {
// The accessibility may be turned off while we were waiting so check again.
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
mLastEventTimeMillis = SystemClock.uptimeMillis();
AccessibilityEvent event = AccessibilityEvent.obtain();
event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
- event.setContentChangeType(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
+ event.setContentChangeTypes(mChangeTypes);
mSource.sendAccessibilityEventUnchecked(event);
} else {
mLastEventTimeMillis = 0;
@@ -6505,17 +6558,20 @@
// In any case reset to initial state.
mSource.resetSubtreeAccessibilityStateChanged();
mSource = null;
+ mChangeTypes = 0;
}
- public void runOrPost(View source) {
+ public void runOrPost(View source, int changeType) {
if (mSource != null) {
// If there is no common predecessor, then mSource points to
// a removed view, hence in this case always prefer the source.
View predecessor = getCommonPredecessor(mSource, source);
mSource = (predecessor != null) ? predecessor : source;
+ mChangeTypes |= changeType;
return;
}
mSource = source;
+ mChangeTypes = changeType;
final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
final long minEventIntevalMillis =
ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 730c4eb..ad8b51d 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -992,6 +992,8 @@
mData = mDataCopy;
}
mDataCopy = null;
+ mAccess.mData.clear();
+ mAccess.mSize = 0;
}
int size() {
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 82c8163..7e2bffa 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -326,7 +326,7 @@
* <em>Properties:</em></br>
* <ul>
* <li>{@link #getEventType()} - The type of the event.</li>
- * <li>{@link #getContentChangeType()} - The type of content change.</li>
+ * <li>{@link #getContentChangeTypes()} - The type of content changes.</li>
* <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
@@ -663,15 +663,27 @@
/**
* Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
- * The subtree rooted at the source node changed.
+ * The type of change is not defined.
*/
- public static final int CONTENT_CHANGE_TYPE_SUBTREE = 0;
+ public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0x00000000;
/**
* Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
- * Only the source node changed.
+ * A node in the subtree rooted at the source node was added or removed.
*/
- public static final int CONTENT_CHANGE_TYPE_NODE = 1;
+ public static final int CONTENT_CHANGE_TYPE_SUBTREE = 0x00000001;
+
+ /**
+ * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+ * The node's text changed.
+ */
+ public static final int CONTENT_CHANGE_TYPE_TEXT = 0x00000002;
+
+ /**
+ * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+ * The node's content description changed.
+ */
+ public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 0x00000004;
/**
* Mask for {@link AccessibilityEvent} all types.
@@ -708,7 +720,7 @@
private long mEventTime;
int mMovementGranularity;
int mAction;
- int mContentChangeType;
+ int mContentChangeTypes;
private final ArrayList<AccessibilityRecord> mRecords = new ArrayList<AccessibilityRecord>();
@@ -728,7 +740,7 @@
mEventType = event.mEventType;
mMovementGranularity = event.mMovementGranularity;
mAction = event.mAction;
- mContentChangeType = event.mContentChangeType;
+ mContentChangeTypes = event.mContentChangeTypes;
mEventTime = event.mEventTime;
mPackageName = event.mPackageName;
}
@@ -792,30 +804,33 @@
}
/**
- * Gets the type of node tree change signaled by an
- * {@link #TYPE_WINDOW_CONTENT_CHANGED} event.
+ * Gets the bit mask of change types signaled by an
+ * {@link #TYPE_WINDOW_CONTENT_CHANGED} event. A single event may represent
+ * multiple change types.
*
- * @see #CONTENT_CHANGE_TYPE_NODE
- * @see #CONTENT_CHANGE_TYPE_SUBTREE
- *
- * @return The change type.
+ * @return The bit mask of change types. One or more of:
+ * <ul>
+ * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION}
+ * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_SUBTREE}
+ * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT}
+ * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED}
+ * </ul>
*/
- public int getContentChangeType() {
- return mContentChangeType;
+ public int getContentChangeTypes() {
+ return mContentChangeTypes;
}
/**
- * Sets the type of node tree change signaled by an
+ * Sets the bit mask of node tree changes signaled by an
* {@link #TYPE_WINDOW_CONTENT_CHANGED} event.
*
- * @see #CONTENT_CHANGE_TYPE_NODE
- * @see #CONTENT_CHANGE_TYPE_SUBTREE
- *
- * @param changeType The change type.
+ * @param changeTypes The bit mask of change types.
+ * @throws IllegalStateException If called from an AccessibilityService.
+ * @see #getContentChangeTypes()
*/
- public void setContentChangeType(int changeType) {
+ public void setContentChangeTypes(int changeTypes) {
enforceNotSealed();
- mContentChangeType = changeType;
+ mContentChangeTypes = changeTypes;
}
/**
@@ -985,7 +1000,7 @@
mEventType = 0;
mMovementGranularity = 0;
mAction = 0;
- mContentChangeType = 0;
+ mContentChangeTypes = 0;
mPackageName = null;
mEventTime = 0;
while (!mRecords.isEmpty()) {
@@ -1004,7 +1019,7 @@
mEventType = parcel.readInt();
mMovementGranularity = parcel.readInt();
mAction = parcel.readInt();
- mContentChangeType = parcel.readInt();
+ mContentChangeTypes = parcel.readInt();
mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
mEventTime = parcel.readLong();
mConnectionId = parcel.readInt();
@@ -1057,7 +1072,7 @@
parcel.writeInt(mEventType);
parcel.writeInt(mMovementGranularity);
parcel.writeInt(mAction);
- parcel.writeInt(mContentChangeType);
+ parcel.writeInt(mContentChangeTypes);
TextUtils.writeToParcel(mPackageName, parcel, 0);
parcel.writeLong(mEventTime);
parcel.writeInt(mConnectionId);
@@ -1119,7 +1134,7 @@
builder.append(super.toString());
if (DEBUG) {
builder.append("\n");
- builder.append("; ContentChangeType: ").append(mContentChangeType);
+ builder.append("; ContentChangeTypes: ").append(mContentChangeTypes);
builder.append("; sourceWindowId: ").append(mSourceWindowId);
builder.append("; mSourceNodeId: ").append(mSourceNodeId);
for (int i = 0; i < mRecords.size(); i++) {
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index c61516b..9fc37cf 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -418,19 +418,13 @@
private static final int BOOLEAN_PROPERTY_EDITABLE = 0x00001000;
- private static final int BOOLEAN_PROPERTY_LIVE_REGION = 0x00002000;
+ private static final int BOOLEAN_PROPERTY_OPENS_POPUP = 0x00002000;
- private static final int BOOLEAN_PROPERTY_OPENS_POPUP = 0x00004000;
+ private static final int BOOLEAN_PROPERTY_DISMISSABLE = 0x00004000;
- private static final int BOOLEAN_PROPERTY_EXPANDABLE = 0x00008000;
+ private static final int BOOLEAN_PROPERTY_MULTI_LINE = 0x00008000;
- private static final int BOOLEAN_PROPERTY_EXPANDED = 0x00010000;
-
- private static final int BOOLEAN_PROPERTY_DISMISSABLE = 0x00020000;
-
- private static final int BOOLEAN_PROPERTY_MULTI_LINE = 0x00040000;
-
- private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00080000;
+ private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00010000;
/**
* Bits that provide the id of a virtual descendant of a view.
@@ -517,6 +511,7 @@
private int mTextSelectionStart = UNDEFINED;
private int mTextSelectionEnd = UNDEFINED;
private int mInputType = InputType.TYPE_NULL;
+ private int mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
private Bundle mExtras;
@@ -1471,39 +1466,42 @@
}
/**
- * Gets if the node is a live region.
+ * Gets the node's live region mode.
* <p>
- * A live region is a node that contains information that is important
- * for the user and when it changes the user has to be notified. For
- * example, if the user plays a video and the application shows a
- * progress indicator with the percentage of buffering, then the progress
- * indicator should be marked as a live region.
- * </p>
+ * A live region is a node that contains information that is important for
+ * the user and when it changes the user should be notified. For example,
+ * in a login screen with a TextView that displays an "incorrect password"
+ * notification, that view should be marked as a live region with mode
+ * {@link View#ACCESSIBILITY_LIVE_REGION_POLITE}.
* <p>
- * It is the responsibility of the accessibility
- * service to monitor this region and notify the user if it changes.
- * </p>
+ * It is the responsibility of the accessibility service to monitor
+ * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events indicating
+ * changes to live region nodes and their children.
*
- * @return If the node is a live region.
+ * @return The live region mode, or
+ * {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
+ * live region.
+ * @see android.view.View#getAccessibilityLiveRegion()
*/
- public boolean isLiveRegion() {
- return getBooleanProperty(BOOLEAN_PROPERTY_LIVE_REGION);
+ public int getLiveRegion() {
+ return mLiveRegion;
}
/**
- * Sets if the node is a live region for whose changes the user
- * should be notified. It is the responsibility of the accessibility
- * service to monitor this region and notify the user if it changes.
+ * Sets the node's live region mode.
* <p>
- * <strong>Note:</strong> Cannot be called from an
- * {@link android.accessibilityservice.AccessibilityService}.
- * This class is made immutable before being delivered to an AccessibilityService.
- * </p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}. This class is
+ * made immutable before being delivered to an AccessibilityService.
*
- * @param liveRegion If the node is a live region.
+ * @param mode The live region mode, or
+ * {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
+ * live region.
+ * @see android.view.View#setAccessibilityLiveRegion(int)
*/
- public void setLiveRegion(boolean liveRegion) {
- setBooleanProperty(BOOLEAN_PROPERTY_LIVE_REGION, liveRegion);
+ public void setLiveRegion(int mode) {
+ enforceNotSealed();
+ mLiveRegion = mode;
}
/**
@@ -1554,52 +1552,6 @@
}
/**
- * Gets if the node can be expanded.
- *
- * @return If the node can be expanded.
- */
- public boolean isExpandable() {
- return getBooleanProperty(BOOLEAN_PROPERTY_EXPANDABLE);
- }
-
- /**
- * Sets if the node can be expanded.
- * <p>
- * <strong>Note:</strong> Cannot be called from an
- * {@link android.accessibilityservice.AccessibilityService}.
- * This class is made immutable before being delivered to an AccessibilityService.
- * </p>
- *
- * @param expandable If the node can be expanded.
- */
- public void setExpandable(boolean expandable) {
- setBooleanProperty(BOOLEAN_PROPERTY_EXPANDABLE, expandable);
- }
-
- /**
- * Gets if the node is expanded.
- *
- * @return If the node is expanded.
- */
- public boolean isExpanded() {
- return getBooleanProperty(BOOLEAN_PROPERTY_EXPANDED);
- }
-
- /**
- * Sets if the node is expanded.
- * <p>
- * <strong>Note:</strong> Cannot be called from an
- * {@link android.accessibilityservice.AccessibilityService}.
- * This class is made immutable before being delivered to an AccessibilityService.
- * </p>
- *
- * @param expanded If the node is expanded.
- */
- public void setExpanded(boolean expanded) {
- setBooleanProperty(BOOLEAN_PROPERTY_EXPANDED, expanded);
- }
-
- /**
* Gets if the node can be dismissed.
*
* @return If the node can be dismissed.
@@ -2203,6 +2155,7 @@
parcel.writeInt(mTextSelectionStart);
parcel.writeInt(mTextSelectionEnd);
parcel.writeInt(mInputType);
+ parcel.writeInt(mLiveRegion);
if (mExtras != null) {
parcel.writeInt(1);
@@ -2276,6 +2229,7 @@
mTextSelectionStart = other.mTextSelectionStart;
mTextSelectionEnd = other.mTextSelectionEnd;
mInputType = other.mInputType;
+ mLiveRegion = other.mLiveRegion;
if (other.mExtras != null && !other.mExtras.isEmpty()) {
getExtras().putAll(other.mExtras);
}
@@ -2334,6 +2288,7 @@
mTextSelectionEnd = parcel.readInt();
mInputType = parcel.readInt();
+ mLiveRegion = parcel.readInt();
if (parcel.readInt() == 1) {
getExtras().putAll(parcel.readBundle());
@@ -2389,6 +2344,7 @@
mTextSelectionStart = UNDEFINED;
mTextSelectionEnd = UNDEFINED;
mInputType = InputType.TYPE_NULL;
+ mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
if (mExtras != null) {
mExtras.clear();
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
index 1fde2fa..6bef78e 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
@@ -91,16 +91,16 @@
case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
synchronized (mLock) {
final long sourceId = event.getSourceNodeId();
- if (event.getContentChangeType()
- == AccessibilityEvent.CONTENT_CHANGE_TYPE_NODE) {
- refreshCachedNode(sourceId);
- } else {
+ if ((event.getContentChangeTypes()
+ & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) != 0) {
clearSubTreeLocked(sourceId);
+ } else {
+ refreshCachedNode(sourceId);
}
}
} break;
}
- if (Build.IS_DEBUGGABLE && CHECK_INTEGRITY_IF_DEBUGGABLE_BUILD) {
+ if (CHECK_INTEGRITY_IF_DEBUGGABLE_BUILD && Build.IS_DEBUGGABLE) {
checkIntegrity();
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 54b87de..53f7c79 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1412,12 +1412,17 @@
try {
if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod);
- mCurMethod.updateSelection(mCursorSelStart, mCursorSelEnd,
- selStart, selEnd, candidatesStart, candidatesEnd);
+ final int oldSelStart = mCursorSelStart;
+ final int oldSelEnd = mCursorSelEnd;
+ // Update internal values before sending updateSelection to the IME, because
+ // if it changes the text within its onUpdateSelection handler in a way that
+ // does not move the cursor we don't want to call it again with the same values.
mCursorSelStart = selStart;
mCursorSelEnd = selEnd;
mCursorCandStart = candidatesStart;
mCursorCandEnd = candidatesEnd;
+ mCurMethod.updateSelection(oldSelStart, oldSelEnd,
+ selStart, selEnd, candidatesStart, candidatesEnd);
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId, e);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 8fc3ce3..15331dc 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -31,9 +31,8 @@
import android.os.CancellationSignal;
import android.os.Looper;
import android.os.Message;
-import android.os.ParcelFileDescriptor;
import android.os.StrictMode;
-import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
@@ -1069,41 +1068,21 @@
}
/**
- * Exports the contents of this Webview as PDF. Only supported for API levels
+ * Creates a PrintDocumentAdapter that provides the content of this Webview for printing.
+ * Only supported for API levels
* {@link android.os.Build.VERSION_CODES#KITKAT} and above.
*
- * TODO(sgurun) the parameter list is stale. Fix it before unhiding.
- *
- * @param fd The FileDescriptor to export the PDF contents to. Cannot be null.
- * @param width The page width. Should be larger than 0.
- * @param height The page height. Should be larger than 0.
- * @param resultCallback A callback to be invoked when the PDF content is exported.
- * A true indicates success, and a false failure. Cannot be null.
- * @param cancellationSignal Signal for cancelling the PDF conversion request. Must not
- * be null.
- *
- * The PDF conversion is done asynchronously and the PDF output is written to the provided
- * file descriptor. The caller should not close the file descriptor until the resultCallback
- * is called, indicating PDF conversion is complete. Webview will never close the file
- * descriptor.
- * Limitations: Webview cannot be drawn during the PDF export so the application is
- * recommended to take it offscreen, or putting in a layer with an overlaid progress
- * UI / spinner.
- *
- * If the caller cancels the task using the cancellationSignal, the cancellation will be
- * acked using the resultCallback signal.
- *
- * Throws an exception if an IO error occurs accessing the file descriptor.
- *
- * TODO(sgurun) margins, explain the units, make it public.
- * @hide
+ * The adapter works by converting the Webview contents to a PDF stream. The Webview cannot
+ * be drawn during the conversion process - any such draws are undefined. It is recommended
+ * to use a dedicated off screen Webview for the printing. If necessary, an application may
+ * temporarily hide a visible WebView by using a custom PrintDocumentAdapter instance
+ * wrapped around the object returned and observing the onStart and onFinish methods. See
+ * {@link android.print.PrintDocumentAdapter} for more information.
*/
- public void exportToPdf(ParcelFileDescriptor fd, PrintAttributes attributes,
- ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal)
- throws java.io.IOException {
+ public PrintDocumentAdapter createPrintDocumentAdapter() {
checkThread();
- if (DebugFlags.TRACE_API) Log.d(LOGTAG, "exportToPdf");
- mProvider.exportToPdf(fd, attributes, resultCallback, cancellationSignal);
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "createPrintDocumentAdapter");
+ return mProvider.createPrintDocumentAdapter();
}
/**
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 3f22d53..e82ce30 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -62,7 +62,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
-import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
import android.security.KeyChain;
import android.text.Editable;
import android.text.InputType;
@@ -2894,12 +2894,10 @@
}
/**
- * See {@link WebView#exportToPdf()}
+ * See {@link WebView#createPrintDocumentAdapter()}
*/
@Override
- public void exportToPdf(android.os.ParcelFileDescriptor fd, PrintAttributes attributes,
- ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal)
- throws java.io.IOException {
+ public PrintDocumentAdapter createPrintDocumentAdapter() {
// K-only API not implemented in WebViewClassic.
throw new IllegalStateException("This API not supported on Android 4.3 and earlier");
}
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index d625d8a..696aad4 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -25,10 +25,8 @@
import android.graphics.drawable.Drawable;
import android.net.http.SslCertificate;
import android.os.Bundle;
-import android.os.CancellationSignal;
import android.os.Message;
-import android.os.ParcelFileDescriptor;
-import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@@ -149,9 +147,7 @@
public Picture capturePicture();
- public void exportToPdf(ParcelFileDescriptor fd, PrintAttributes attributes,
- ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal)
- throws java.io.IOException;
+ public PrintDocumentAdapter createPrintDocumentAdapter();
public float getScale();
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 40747f0..5c10a77 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -93,7 +93,8 @@
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
- notifyViewAccessibilityStateChangedIfNeeded();
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 05a8dc8..082ff3d 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -114,7 +114,8 @@
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
- notifyViewAccessibilityStateChangedIfNeeded();
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
// Avoid infinite recursions if setChecked() is called from a listener
if (mBroadcasting) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 389d9d6..b239fbd 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1555,8 +1555,9 @@
} else if (mItemCount != mAdapter.getCount()) {
throw new IllegalStateException("The content of the adapter has changed but "
+ "ListView did not receive a notification. Make sure the content of "
- + "your adapter is not modified from a background thread, but only "
- + "from the UI thread. [in ListView(" + getId() + ", " + getClass()
+ + "your adapter is not modified from a background thread, but only from "
+ + "the UI thread. Make sure your adapter calls notifyDataSetChanged() "
+ + "when its content changes. [in ListView(" + getId() + ", " + getClass()
+ ") with Adapter(" + mAdapter.getClass() + ")]");
}
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 19cc3c2..e4956dd 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1099,6 +1099,16 @@
}
@Override
+ public int computeVerticalScrollOffset() {
+ return mCurrentScrollOffset;
+ }
+
+ @Override
+ public int computeVerticalScrollRange() {
+ return mSelectorIndices.length * mSelectorElementHeight;
+ }
+
+ @Override
public int getSolidColor() {
return mSolidColor;
}
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 92c9b93..e03e83d 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -536,7 +536,7 @@
// the right of each child view
width += mPaddingRight;
- if (mLayoutParams.width >= 0) {
+ if (mLayoutParams != null && mLayoutParams.width >= 0) {
width = Math.max(width, mLayoutParams.width);
}
@@ -566,7 +566,7 @@
// the bottom of each child view
height += mPaddingBottom;
- if (mLayoutParams.height >= 0) {
+ if (mLayoutParams != null && mLayoutParams.height >= 0) {
height = Math.max(height, mLayoutParams.height);
}
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index b87ed7a..b75d36f 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -412,6 +412,8 @@
public void setAdapter(SpinnerAdapter adapter) {
super.setAdapter(adapter);
+ mRecycler.clear();
+
if (mPopup != null) {
mPopup.setAdapter(new DropDownAdapter(adapter));
} else {
@@ -426,9 +428,8 @@
if (getChildCount() > 0) {
child = getChildAt(0);
} else if (mAdapter != null && mAdapter.getCount() > 0) {
- child = makeAndAddView(0);
+ child = makeView(0, false);
mRecycler.put(0, child);
- removeAllViewsInLayout();
}
if (child != null) {
@@ -536,7 +537,7 @@
mFirstPosition = mSelectedPosition;
if (mAdapter != null) {
- View sel = makeAndAddView(mSelectedPosition);
+ View sel = makeView(mSelectedPosition, true);
int width = sel.getMeasuredWidth();
int selectedOffset = childrenLeft;
final int layoutDirection = getLayoutDirection();
@@ -571,17 +572,17 @@
* from the old to new positions.
*
* @param position Position in the spinner for the view to obtain
- * @return A view that has been added to the spinner
+ * @param addChild true to add the child to the spinner, false to obtain and configure only.
+ * @return A view for the given position
*/
- private View makeAndAddView(int position) {
-
+ private View makeView(int position, boolean addChild) {
View child;
if (!mDataChanged) {
child = mRecycler.get(position);
if (child != null) {
// Position the view
- setUpChild(child);
+ setUpChild(child, addChild);
return child;
}
@@ -591,7 +592,7 @@
child = mAdapter.getView(position, null, this);
// Position the view
- setUpChild(child);
+ setUpChild(child, addChild);
return child;
}
@@ -601,8 +602,9 @@
* and fill out its layout paramters.
*
* @param child The view to position
+ * @param addChild true if the child should be added to the Spinner during setup
*/
- private void setUpChild(View child) {
+ private void setUpChild(View child, boolean addChild) {
// Respect layout params that are already in the view. Otherwise
// make some up...
@@ -611,7 +613,9 @@
lp = generateDefaultLayoutParams();
}
- addViewInLayout(child, 0, lp);
+ if (addChild) {
+ addViewInLayout(child, 0, lp);
+ }
child.setSelected(hasFocus());
if (mDisableChildrenWhenDisabled) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3c9cc98..ae1b627 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1723,7 +1723,8 @@
setText(mText);
if (hasPasswordTransformationMethod()) {
- notifyViewAccessibilityStateChangedIfNeeded();
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
}
@@ -3826,6 +3827,8 @@
sendOnTextChanged(text, 0, oldlen, textLength);
onTextChanged(text, 0, oldlen, textLength);
+ notifyViewAccessibilityStateChangedIfNeeded(AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT);
+
if (needEditableForNotification) {
sendAfterTextChanged((Editable) text);
}
@@ -4410,7 +4413,8 @@
public void setError(CharSequence error, Drawable icon) {
createEditorIfNeeded();
mEditor.setError(error, icon);
- notifyViewAccessibilityStateChangedIfNeeded();
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
@Override
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 91c47d1..76b8579 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -30,6 +30,8 @@
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -41,6 +43,7 @@
FrameLayout mContent;
int mCount;
final Handler mHandler = new Handler();
+ static final int BGCOLOR = 0xffed1d24;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -53,6 +56,7 @@
Typeface light = Typeface.create("sans-serif-light", Typeface.NORMAL);
mContent = new FrameLayout(this);
+ mContent.setBackgroundColor(0xC0000000);
final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
@@ -64,13 +68,16 @@
logo.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
logo.setVisibility(View.INVISIBLE);
+ final View bg = new View(this);
+ bg.setBackgroundColor(BGCOLOR);
+ bg.setAlpha(0f);
+
final TextView letter = new TextView(this);
letter.setTypeface(bold);
letter.setTextSize(300);
letter.setTextColor(0xFFFFFFFF);
letter.setGravity(Gravity.CENTER);
- letter.setShadowLayer(12*metrics.density, 0, 0, 0xC085F985);
letter.setText(String.valueOf(Build.VERSION.RELEASE).substring(0, 1));
final int p = (int)(4 * metrics.density);
@@ -81,11 +88,11 @@
tv.setPadding(p, p, p, p);
tv.setTextColor(0xFFFFFFFF);
tv.setGravity(Gravity.CENTER);
- tv.setShadowLayer(4 * metrics.density, 0, 2 * metrics.density, 0x66000000);
tv.setTransformationMethod(new AllCapsTransformationMethod(this));
tv.setText("Android " + Build.VERSION.RELEASE);
tv.setVisibility(View.INVISIBLE);
+ mContent.addView(bg);
mContent.addView(letter, lp);
mContent.addView(logo, lp);
@@ -96,24 +103,54 @@
mContent.addView(tv, lp2);
mContent.setOnClickListener(new View.OnClickListener() {
+ int clicks;
@Override
public void onClick(View v) {
- if (logo.getVisibility() != View.VISIBLE) {
- letter.animate().alpha(0.25f).scaleY(0.75f).scaleX(0.75f).setDuration(2000)
- .start();
- logo.setAlpha(0f);
- logo.setVisibility(View.VISIBLE);
- logo.animate().alpha(1f).setDuration(1000).setStartDelay(500).start();
- tv.setAlpha(0f);
- tv.setVisibility(View.VISIBLE);
- tv.animate().alpha(1f).setDuration(1000).setStartDelay(1000).start();
+ clicks++;
+ if (clicks >= 6) {
+ mContent.performLongClick();
+ return;
}
+ letter.animate().cancel();
+ final float offset = (int)letter.getRotation() % 360;
+ letter.animate()
+ .rotationBy((Math.random() > 0.5f ? 360 : -360) - offset)
+ .setInterpolator(new DecelerateInterpolator())
+ .setDuration(700).start();
}
});
mContent.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
+ if (logo.getVisibility() != View.VISIBLE) {
+ bg.setScaleX(0.01f);
+ bg.animate().alpha(1f).scaleX(1f).setStartDelay(500).start();
+ letter.animate().alpha(0f).scaleY(0.5f).scaleX(0.5f)
+ .rotationBy(360)
+ .setInterpolator(new AccelerateInterpolator())
+ .setDuration(1000)
+ .start();
+ logo.setAlpha(0f);
+ logo.setVisibility(View.VISIBLE);
+ logo.setScaleX(0.5f);
+ logo.setScaleY(0.5f);
+ logo.animate().alpha(1f).scaleX(1f).scaleY(1f)
+ .setDuration(1000).setStartDelay(500)
+ .setInterpolator(new AnticipateOvershootInterpolator())
+ .start();
+ tv.setAlpha(0f);
+ tv.setVisibility(View.VISIBLE);
+ tv.animate().alpha(1f).setDuration(1000).setStartDelay(1000).start();
+ return true;
+ }
+ return false;
+ }
+ });
+
+ logo.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
try {
startActivity(new Intent(Intent.ACTION_MAIN)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 1f55a4c..d3fe34e 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -24,6 +24,7 @@
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -969,6 +970,7 @@
if (ps.isInUse()) {
uids.valueAt(iu).resetSafely(now);
} else {
+ uids.valueAt(iu).makeDead();
uids.removeAt(iu);
}
}
@@ -983,9 +985,10 @@
PackageState pkgState = uids.valueAt(iu);
for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
ProcessState ps = pkgState.mProcesses.valueAt(iproc);
- if (ps.isInUse()) {
+ if (ps.isInUse() || ps.mCommonProcess.isInUse()) {
pkgState.mProcesses.valueAt(iproc).resetSafely(now);
} else {
+ pkgState.mProcesses.valueAt(iproc).makeDead();
pkgState.mProcesses.removeAt(iproc);
}
}
@@ -2127,6 +2130,7 @@
int mNumExcessiveCpu;
boolean mMultiPackage;
+ boolean mDead;
public long mTmpTotalTime;
@@ -2230,6 +2234,18 @@
mNumExcessiveCpu = 0;
}
+ void makeDead() {
+ mDead = true;
+ }
+
+ private void ensureNotDead() {
+ if (!mDead) {
+ return;
+ }
+ throw new IllegalStateException("ProcessState dead: name=" + mName
+ + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
+ }
+
void writeToParcel(Parcel out, long now) {
out.writeInt(mMultiPackage ? 1 : 0);
out.writeInt(mDurationsTableSize);
@@ -2271,6 +2287,7 @@
}
public void makeActive() {
+ ensureNotDead();
mActive = true;
}
@@ -2279,7 +2296,8 @@
}
public boolean isInUse() {
- return mActive || mNumActiveServices > 0 || mNumStartedServices > 0;
+ return mActive || mNumActiveServices > 0 || mNumStartedServices > 0
+ || mCurState != STATE_NOTHING;
}
/**
@@ -2315,6 +2333,7 @@
}
void setState(int state, long now) {
+ ensureNotDead();
if (mCurState != state) {
//Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
commitStateTime(now);
@@ -2392,6 +2411,7 @@
}
public void addPss(long pss, long uss, boolean always) {
+ ensureNotDead();
if (!always) {
if (mLastPssState == mCurState && SystemClock.uptimeMillis()
< (mLastPssTime+(30*1000))) {
@@ -2453,6 +2473,7 @@
}
public void reportExcessiveWake(ArrayMap<String, ProcessState> pkgList) {
+ ensureNotDead();
mCommonProcess.mNumExcessiveWake++;
if (!mCommonProcess.mMultiPackage) {
return;
@@ -2464,6 +2485,7 @@
}
public void reportExcessiveCpu(ArrayMap<String, ProcessState> pkgList) {
+ ensureNotDead();
mCommonProcess.mNumExcessiveCpu++;
if (!mCommonProcess.mMultiPackage) {
return;
@@ -2489,15 +2511,27 @@
return this;
}
- private ProcessState pullFixedProc(ArrayMap<String, ProcessState> pkgList,
- int index) {
+ private ProcessState pullFixedProc(ArrayMap<String, ProcessState> pkgList, int index) {
ProcessState proc = pkgList.valueAt(index);
+ if (mDead && proc.mCommonProcess != proc) {
+ // Somehow we try to continue to use a process state that is dead, because
+ // it was not being told it was active during the last commit. We can recover
+ // from this by generating a fresh new state, but this is bad because we
+ // are losing whatever data we had in the old process state.
+ Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage
+ + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
+ proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mName);
+ }
if (proc.mMultiPackage) {
// The array map is still pointing to a common process state
// that is now shared across packages. Update it to point to
// the new per-package state.
- proc = mStats.mPackages.get(pkgList.keyAt(index),
- proc.mUid).mProcesses.get(proc.mName);
+ PackageState pkg = mStats.mPackages.get(pkgList.keyAt(index), proc.mUid);
+ if (pkg == null) {
+ throw new IllegalStateException("No existing package "
+ + pkgList.keyAt(index) + " for multi-proc" + proc.mName);
+ }
+ proc = pkg.mProcesses.get(proc.mName);
if (proc == null) {
throw new IllegalStateException("Didn't create per-package process");
}
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index 30ca73e..58cd60d 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -49,12 +49,12 @@
PROC_SPACE_TERM,
PROC_SPACE_TERM,
PROC_SPACE_TERM,
- PROC_SPACE_TERM|PROC_OUT_LONG, // 9: minor faults
+ PROC_SPACE_TERM|PROC_OUT_LONG, // 10: minor faults
PROC_SPACE_TERM,
- PROC_SPACE_TERM|PROC_OUT_LONG, // 11: major faults
+ PROC_SPACE_TERM|PROC_OUT_LONG, // 12: major faults
PROC_SPACE_TERM,
- PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime
- PROC_SPACE_TERM|PROC_OUT_LONG // 14: stime
+ PROC_SPACE_TERM|PROC_OUT_LONG, // 14: utime
+ PROC_SPACE_TERM|PROC_OUT_LONG, // 15: stime
};
static final int PROCESS_STAT_MINOR_FAULTS = 0;
@@ -69,7 +69,7 @@
private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
PROC_SPACE_TERM,
- PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING, // 1: name
+ PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING, // 2: name
PROC_SPACE_TERM,
PROC_SPACE_TERM,
PROC_SPACE_TERM,
@@ -77,19 +77,20 @@
PROC_SPACE_TERM,
PROC_SPACE_TERM,
PROC_SPACE_TERM,
- PROC_SPACE_TERM|PROC_OUT_LONG, // 9: minor faults
+ PROC_SPACE_TERM|PROC_OUT_LONG, // 10: minor faults
PROC_SPACE_TERM,
- PROC_SPACE_TERM|PROC_OUT_LONG, // 11: major faults
+ PROC_SPACE_TERM|PROC_OUT_LONG, // 12: major faults
PROC_SPACE_TERM,
- PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime
- PROC_SPACE_TERM|PROC_OUT_LONG, // 14: stime
+ PROC_SPACE_TERM|PROC_OUT_LONG, // 14: utime
+ PROC_SPACE_TERM|PROC_OUT_LONG, // 15: stime
PROC_SPACE_TERM,
PROC_SPACE_TERM,
PROC_SPACE_TERM,
PROC_SPACE_TERM,
PROC_SPACE_TERM,
PROC_SPACE_TERM,
- PROC_SPACE_TERM|PROC_OUT_LONG, // 21: vsize
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM|PROC_OUT_LONG, // 23: vsize
};
static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1;
@@ -190,6 +191,10 @@
public String name;
public int nameWidth;
+ // vsize capture when process first detected; can be used to
+ // filter out kernel processes.
+ public long vsize;
+
public long base_uptime;
public long rel_uptime;
@@ -444,6 +449,7 @@
// are actually kernel threads... do we want to? Some
// of them do use CPU, but there can be a *lot* that are
// not doing anything.
+ st.vsize = procStats[PROCESS_FULL_STAT_VSIZE];
if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) {
st.interesting = true;
st.baseName = procStatsString[0];
diff --git a/core/java/com/android/internal/transition/ActionBarTransition.java b/core/java/com/android/internal/transition/ActionBarTransition.java
new file mode 100644
index 0000000..de59728
--- /dev/null
+++ b/core/java/com/android/internal/transition/ActionBarTransition.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.internal.transition;
+
+import android.transition.ChangeBounds;
+import android.transition.Fade;
+import android.transition.TextChange;
+import android.transition.Transition;
+import android.transition.TransitionSet;
+
+public class ActionBarTransition {
+
+ private static final int TRANSITION_DURATION = 120; // ms
+
+ private static final Transition sTransition;
+
+ static {
+ final TextChange tc = new TextChange();
+ tc.setChangeBehavior(TextChange.CHANGE_BEHAVIOR_OUT_IN);
+ final TransitionSet inner = new TransitionSet();
+ inner.addTransition(tc).addTransition(new ChangeBounds());
+ final TransitionSet tg = new TransitionSet();
+ tg.addTransition(new Fade(Fade.OUT)).addTransition(inner).addTransition(new Fade(Fade.IN));
+ tg.setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+ tg.setDuration(TRANSITION_DURATION);
+ sTransition = tg;
+ }
+
+ public static Transition getActionBarTransition() {
+ return sTransition;
+ }
+}
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index 850e1f0..ad65433 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -18,6 +18,7 @@
import java.io.FileInputStream;
+import android.os.Debug;
import android.os.StrictMode;
public class MemInfoReader {
@@ -63,34 +64,11 @@
// /proc/ and /sys/ files perhaps?
StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
try {
- mTotalSize = 0;
- mFreeSize = 0;
- mCachedSize = 0;
- FileInputStream is = new FileInputStream("/proc/meminfo");
- int len = is.read(mBuffer);
- is.close();
- final int BUFLEN = mBuffer.length;
- int count = 0;
- for (int i=0; i<len && count < 3; i++) {
- if (matchText(mBuffer, i, "MemTotal")) {
- i += 8;
- mTotalSize = extractMemValue(mBuffer, i);
- count++;
- } else if (matchText(mBuffer, i, "MemFree")) {
- i += 7;
- mFreeSize = extractMemValue(mBuffer, i);
- count++;
- } else if (matchText(mBuffer, i, "Cached")) {
- i += 6;
- mCachedSize = extractMemValue(mBuffer, i);
- count++;
- }
- while (i < BUFLEN && mBuffer[i] != '\n') {
- i++;
- }
- }
- } catch (java.io.FileNotFoundException e) {
- } catch (java.io.IOException e) {
+ long[] infos = new long[Debug.MEMINFO_COUNT];
+ Debug.getMemInfo(infos);
+ mTotalSize = infos[Debug.MEMINFO_TOTAL] * 1024;
+ mFreeSize = infos[Debug.MEMINFO_FREE] * 1024;
+ mCachedSize = infos[Debug.MEMINFO_CACHED] * 1024;
} finally {
StrictMode.setThreadPolicy(savedPolicy);
}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index c1ae9c2..d5ab0f2 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -21,20 +21,20 @@
import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
+import android.transition.Transition;
+import android.transition.TransitionManager;
import android.util.SparseBooleanArray;
import android.view.ActionProvider;
import android.view.MenuItem;
-import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.View.MeasureSpec;
-import android.view.accessibility.AccessibilityNodeInfo;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageButton;
import android.widget.ListPopupWindow;
import android.widget.ListPopupWindow.ForwardingListener;
-
+import com.android.internal.transition.ActionBarTransition;
import com.android.internal.view.ActionBarPolicy;
import com.android.internal.view.menu.ActionMenuView.ActionMenuChildView;
@@ -73,6 +73,8 @@
final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
int mOpenSubMenuId;
+ private static final Transition sTransition = ActionBarTransition.getActionBarTransition();
+
public ActionMenuPresenter(Context context) {
super(context, com.android.internal.R.layout.action_menu_layout,
com.android.internal.R.layout.action_menu_item_layout);
@@ -159,10 +161,8 @@
public View getItemView(final MenuItemImpl item, View convertView, ViewGroup parent) {
View actionView = item.getActionView();
if (actionView == null || item.hasCollapsibleActionView()) {
- if (!(convertView instanceof ActionMenuItemView)) {
- convertView = null;
- }
- actionView = super.getItemView(item, convertView, parent);
+ // Don't recycle existing item views for action buttons; it interferes with transitions.
+ actionView = super.getItemView(item, null, parent);
}
actionView.setVisibility(item.isActionViewExpanded() ? View.GONE : View.VISIBLE);
@@ -211,6 +211,10 @@
@Override
public void updateMenuView(boolean cleared) {
+ final ViewGroup menuViewParent = (ViewGroup) ((View) mMenuView).getParent();
+ if (menuViewParent != null) {
+ TransitionManager.beginDelayedTransition(menuViewParent, sTransition);
+ }
super.updateMenuView(cleared);
if (mMenu != null) {
@@ -369,6 +373,10 @@
return mOverflowPopup != null && mOverflowPopup.isShowing();
}
+ public boolean isOverflowMenuShowPending() {
+ return mPostedOpenRunnable != null || isOverflowMenuShowing();
+ }
+
/**
* @return true if space has been reserved in the action menu for an overflow item.
*/
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
index ca7f5d0..f3891c7 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -201,6 +201,13 @@
return false;
}
+ public boolean isOverflowMenuShowPending() {
+ if (mActionMenuPresenter != null) {
+ return mActionMenuPresenter.isOverflowMenuShowPending();
+ }
+ return false;
+ }
+
public boolean isOverflowReserved() {
return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved();
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index f2bd522..7efcb6e 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -29,6 +29,12 @@
import android.os.Parcelable;
import android.text.Layout;
import android.text.TextUtils;
+import android.transition.ChangeBounds;
+import android.transition.Fade;
+import android.transition.TextChange;
+import android.transition.Transition;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
import android.util.AttributeSet;
import android.view.CollapsibleActionView;
import android.view.Gravity;
@@ -50,6 +56,7 @@
import android.widget.SpinnerAdapter;
import android.widget.TextView;
import com.android.internal.R;
+import com.android.internal.transition.ActionBarTransition;
import com.android.internal.view.menu.ActionMenuItem;
import com.android.internal.view.menu.ActionMenuPresenter;
import com.android.internal.view.menu.ActionMenuView;
@@ -97,7 +104,6 @@
private LinearLayout mTitleLayout;
private TextView mTitleView;
private TextView mSubtitleView;
- private View mTitleUpView;
private ViewGroup mUpGoerFive;
private Spinner mSpinner;
@@ -138,6 +144,8 @@
Window.Callback mWindowCallback;
+ private final static Transition sTransition = ActionBarTransition.getActionBarTransition();
+
private final AdapterView.OnItemSelectedListener mNavItemSelectedListener =
new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView parent, View view, int position, long id) {
@@ -198,7 +206,7 @@
mHomeLayout = (HomeView) inflater.inflate(homeResId, mUpGoerFive, false);
mExpandedHomeLayout = (HomeView) inflater.inflate(homeResId, mUpGoerFive, false);
- mExpandedHomeLayout.setUp(true);
+ mExpandedHomeLayout.setShowUp(true);
mExpandedHomeLayout.setOnClickListener(mExpandedActionViewUpListener);
mExpandedHomeLayout.setContentDescription(getResources().getText(
R.string.action_bar_up_description));
@@ -251,7 +259,6 @@
mTitleView = null;
mSubtitleView = null;
- mTitleUpView = null;
if (mTitleLayout != null && mTitleLayout.getParent() == mUpGoerFive) {
mUpGoerFive.removeView(mTitleLayout);
}
@@ -475,6 +482,9 @@
public void setCustomNavigationView(View view) {
final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
+ if (showCustom) {
+ TransitionManager.beginDelayedTransition(this, sTransition);
+ }
if (mCustomNavView != null && showCustom) {
removeView(mCustomNavView);
}
@@ -512,6 +522,7 @@
}
private void setTitleImpl(CharSequence title) {
+ TransitionManager.beginDelayedTransition(this, sTransition);
mTitle = title;
if (mTitleView != null) {
mTitleView.setText(title);
@@ -531,6 +542,7 @@
}
public void setSubtitle(CharSequence subtitle) {
+ TransitionManager.beginDelayedTransition(this, sTransition);
mSubtitle = subtitle;
if (mSubtitleView != null) {
mSubtitleView.setText(subtitle);
@@ -611,13 +623,11 @@
mDisplayOptions = options;
if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
- final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0;
- final int vis = showHome && mExpandedActionView == null ? VISIBLE : GONE;
- mHomeLayout.setVisibility(vis);
+ TransitionManager.beginDelayedTransition(this, sTransition);
if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
final boolean setUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
- mHomeLayout.setUp(setUp);
+ mHomeLayout.setShowUp(setUp);
// Showing home as up implicitly enables interaction with it.
// In honeycomb it was always enabled, so make this transition
@@ -641,11 +651,14 @@
}
}
- if (mTitleLayout != null && (flagsChanged &
- (ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME)) != 0) {
- final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0;
- mTitleUpView.setVisibility(!showHome ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE);
- }
+ final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0;
+ final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0;
+ final boolean titleUp = !showHome && homeAsUp;
+ mHomeLayout.setShowIcon(showHome);
+
+ final int homeVis = (showHome || titleUp) && mExpandedActionView == null ?
+ VISIBLE : GONE;
+ mHomeLayout.setVisibility(homeVis);
if ((flagsChanged & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
if ((options & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
@@ -724,6 +737,7 @@
public void setNavigationMode(int mode) {
final int oldMode = mNavigationMode;
if (mode != oldMode) {
+ TransitionManager.beginDelayedTransition(this, sTransition);
switch (oldMode) {
case ActionBar.NAVIGATION_MODE_LIST:
if (mListNavLayout != null) {
@@ -829,7 +843,6 @@
this, false);
mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title);
mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle);
- mTitleUpView = (View) mTitleLayout.findViewById(R.id.up);
if (mTitleStyleRes != 0) {
mTitleView.setTextAppearance(mContext, mTitleStyleRes);
@@ -845,13 +858,9 @@
mSubtitleView.setText(mSubtitle);
mSubtitleView.setVisibility(VISIBLE);
}
-
- final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0;
- final boolean showHome = (mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0;
- final boolean showTitleUp = !showHome;
- mTitleUpView.setVisibility(showTitleUp ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE);
}
+ TransitionManager.beginDelayedTransition(this, sTransition);
mUpGoerFive.addView(mTitleLayout);
if (mExpandedActionView != null ||
(TextUtils.isEmpty(mTitle) && TextUtils.isEmpty(mSubtitle))) {
@@ -955,25 +964,32 @@
int leftOfCenter = availableWidth / 2;
int rightOfCenter = leftOfCenter;
+ final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
+ (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
+
HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
- int homeWidth = 0;
- if (homeLayout.getVisibility() != GONE && homeLayout.getParent() == mUpGoerFive) {
- final ViewGroup.LayoutParams lp = homeLayout.getLayoutParams();
- int homeWidthSpec;
- if (lp.width < 0) {
- homeWidthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST);
- } else {
- homeWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
- }
+ final ViewGroup.LayoutParams homeLp = homeLayout.getLayoutParams();
+ int homeWidthSpec;
+ if (homeLp.width < 0) {
+ homeWidthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST);
+ } else {
+ homeWidthSpec = MeasureSpec.makeMeasureSpec(homeLp.width, MeasureSpec.EXACTLY);
+ }
- /*
- * This is a little weird.
- * We're only measuring the *home* affordance within the Up container here
- * on purpose, because we want to give the available space to all other views before
- * the title text. We'll remeasure the whole up container again later.
- */
- homeLayout.measure(homeWidthSpec, exactHeightSpec);
+ /*
+ * This is a little weird.
+ * We're only measuring the *home* affordance within the Up container here
+ * on purpose, because we want to give the available space to all other views before
+ * the title text. We'll remeasure the whole up container again later.
+ * We need to measure this container so we know the right offset for the up affordance
+ * no matter what.
+ */
+ homeLayout.measure(homeWidthSpec, exactHeightSpec);
+
+ int homeWidth = 0;
+ if ((homeLayout.getVisibility() != GONE && homeLayout.getParent() == mUpGoerFive)
+ || showTitle) {
homeWidth = homeLayout.getMeasuredWidth();
final int homeOffsetWidth = homeWidth + homeLayout.getStartOffset();
availableWidth = Math.max(0, availableWidth - homeOffsetWidth);
@@ -993,9 +1009,6 @@
rightOfCenter - mIndeterminateProgressView.getMeasuredWidth());
}
- final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
- (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
-
if (mExpandedActionView == null) {
switch (mNavigationMode) {
case ActionBar.NAVIGATION_MODE_LIST:
@@ -1124,7 +1137,7 @@
}
final boolean isLayoutRtl = isLayoutRtl();
- final int direction = isLayoutRtl ? +1 : -1;
+ final int direction = isLayoutRtl ? 1 : -1;
int menuStart = isLayoutRtl ? getPaddingLeft() : r - l - getPaddingRight();
// In LTR mode, we start from left padding and go to the right; in RTL mode, we start
// from the padding right and go to the left (in reverse way)
@@ -1132,8 +1145,16 @@
final int y = getPaddingTop();
HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
- final int startOffset = homeLayout.getVisibility() != GONE &&
- homeLayout.getParent() == mUpGoerFive ? homeLayout.getStartOffset() : 0;
+ final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
+ (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
+ int startOffset = 0;
+ if (homeLayout.getParent() == mUpGoerFive) {
+ if (homeLayout.getVisibility() != GONE) {
+ startOffset = homeLayout.getStartOffset();
+ } else if (showTitle) {
+ startOffset = homeLayout.getUpWidth();
+ }
+ }
// Position the up container based on where the edge of the home layout should go.
x += positionChild(mUpGoerFive,
@@ -1141,9 +1162,6 @@
x = next(x, startOffset, isLayoutRtl);
if (mExpandedActionView == null) {
- final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
- (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
-
switch (mNavigationMode) {
case ActionBar.NAVIGATION_MODE_STANDARD:
break;
@@ -1374,6 +1392,7 @@
private ImageView mUpView;
private ImageView mIconView;
private int mUpWidth;
+ private int mStartOffset;
private int mUpIndicatorRes;
private Drawable mDefaultUpIndicator;
@@ -1392,10 +1411,14 @@
}
}
- public void setUp(boolean isUp) {
+ public void setShowUp(boolean isUp) {
mUpView.setVisibility(isUp ? VISIBLE : GONE);
}
+ public void setShowIcon(boolean showIcon) {
+ mIconView.setVisibility(showIcon ? VISIBLE : GONE);
+ }
+
public void setIcon(Drawable icon) {
mIconView.setImageDrawable(icon);
}
@@ -1448,21 +1471,33 @@
}
public int getStartOffset() {
- return mUpView.getVisibility() == GONE ? mUpWidth : 0;
+ return mUpView.getVisibility() == GONE ? mStartOffset : 0;
+ }
+
+ public int getUpWidth() {
+ return mUpWidth;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildWithMargins(mUpView, widthMeasureSpec, 0, heightMeasureSpec, 0);
final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams();
- mUpWidth = upLp.leftMargin + mUpView.getMeasuredWidth() + upLp.rightMargin;
- int width = mUpView.getVisibility() == GONE ? 0 : mUpWidth;
+ final int upMargins = upLp.leftMargin + upLp.rightMargin;
+ mUpWidth = mUpView.getMeasuredWidth();
+ mStartOffset = mUpWidth + upMargins;
+ int width = mUpView.getVisibility() == GONE ? 0 : mStartOffset;
int height = upLp.topMargin + mUpView.getMeasuredHeight() + upLp.bottomMargin;
- measureChildWithMargins(mIconView, widthMeasureSpec, width, heightMeasureSpec, 0);
- final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
- width += iconLp.leftMargin + mIconView.getMeasuredWidth() + iconLp.rightMargin;
- height = Math.max(height,
- iconLp.topMargin + mIconView.getMeasuredHeight() + iconLp.bottomMargin);
+
+ if (mIconView.getVisibility() != GONE) {
+ measureChildWithMargins(mIconView, widthMeasureSpec, width, heightMeasureSpec, 0);
+ final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
+ width += iconLp.leftMargin + mIconView.getMeasuredWidth() + iconLp.rightMargin;
+ height = Math.max(height,
+ iconLp.topMargin + mIconView.getMeasuredHeight() + iconLp.bottomMargin);
+ } else if (upMargins < 0) {
+ // Remove the measurement effects of negative margins used for offsets
+ width -= upMargins;
+ }
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
@@ -1604,6 +1639,8 @@
@Override
public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+ TransitionManager.beginDelayedTransition(ActionBarView.this, sTransition);
+
mExpandedActionView = item.getActionView();
mExpandedHomeLayout.setIcon(mIcon.getConstantState().newDrawable(getResources()));
mCurrentExpandedItem = item;
@@ -1631,6 +1668,8 @@
@Override
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+ TransitionManager.beginDelayedTransition(ActionBarView.this, sTransition);
+
// Do this before detaching the actionview from the hierarchy, in case
// it needs to dismiss the soft keyboard, etc.
if (mExpandedActionView instanceof CollapsibleActionView) {
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index 2d06b68..f773f59 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -159,17 +159,26 @@
}
-static SkMemoryStream* adaptor_to_mem_stream(SkStream* adaptor) {
- SkASSERT(adaptor != NULL);
- SkDynamicMemoryWStream wStream;
- const int bufferSize = 256 * 1024; // 256 KB, same as ViewStateSerializer.
- uint8_t buffer[bufferSize];
- do {
- size_t bytesRead = adaptor->read(buffer, bufferSize);
- wStream.write(buffer, bytesRead);
- } while (!adaptor->isAtEnd());
- SkAutoTUnref<SkData> data(wStream.copyToData());
- return new SkMemoryStream(data.get());
+static SkMemoryStream* adaptor_to_mem_stream(SkStream* stream) {
+ SkASSERT(stream != NULL);
+ size_t bufferSize = 4096;
+ size_t streamLen = 0;
+ size_t len;
+ char* data = (char*)sk_malloc_throw(bufferSize);
+
+ while ((len = stream->read(data + streamLen,
+ bufferSize - streamLen)) != 0) {
+ streamLen += len;
+ if (streamLen == bufferSize) {
+ bufferSize *= 2;
+ data = (char*)sk_realloc_throw(data, bufferSize);
+ }
+ }
+ data = (char*)sk_realloc_throw(data, streamLen);
+
+ SkMemoryStream* streamMem = new SkMemoryStream();
+ streamMem->setMemoryOwned(data, streamLen);
+ return streamMem;
}
SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream,
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 1ff0d635..8cb152d 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -479,7 +479,13 @@
if (fWrappedPixelRef) {
// delegate java obj management to the wrapped ref
fWrappedPixelRef->globalRef(localref);
- } else if (fOnJavaHeap && sk_atomic_inc(&fGlobalRefCnt) == 0) {
+
+ // Note: we only ref and unref the wrapped AndroidPixelRef so that
+ // bitmap->pixelRef()->globalRef() and globalUnref() can be used in a pair, even if
+ // the bitmap has its underlying AndroidPixelRef swapped out/wrapped
+ return;
+ }
+ if (fOnJavaHeap && sk_atomic_inc(&fGlobalRefCnt) == 0) {
JNIEnv *env = vm2env(fVM);
// If JNI ref was passed, it is always used
@@ -506,7 +512,9 @@
if (fWrappedPixelRef) {
// delegate java obj management to the wrapped ref
fWrappedPixelRef->globalUnref();
- } else if (fOnJavaHeap && sk_atomic_dec(&fGlobalRefCnt) == 1) {
+ return;
+ }
+ if (fOnJavaHeap && sk_atomic_dec(&fGlobalRefCnt) == 1) {
JNIEnv *env = vm2env(fVM);
if (!fHasGlobalRef) {
SkDebugf("We don't have a global ref!");
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index bacfdf6..0c9b3bc 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -37,7 +37,7 @@
namespace android {
static const char* const OutOfResourcesException =
- "android/graphics/SurfaceTexture$OutOfResourcesException";
+ "android/view/Surface$OutOfResourcesException";
static const char* const IllegalStateException = "java/lang/IllegalStateException";
const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index f70f0d1..6e496fd 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -19,6 +19,7 @@
#include <jni.h>
#include <JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
#include <utils/Log.h>
#include <utils/String8.h>
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 852c4d4..3c7da1e 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -38,7 +38,7 @@
#endif
// fully-qualified class name
-#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/CameraMetadata"
+#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
using namespace android;
@@ -152,6 +152,21 @@
return reinterpret_cast<jlong>(new CameraMetadata());
}
+static jlong CameraMetadata_allocateCopy(JNIEnv *env, jobject thiz,
+ jobject other) {
+ ALOGV("%s", __FUNCTION__);
+
+ CameraMetadata* otherMetadata =
+ CameraMetadata_getPointerThrow(env, other, "other");
+
+ // In case of exception, return
+ if (otherMetadata == NULL) return NULL;
+
+ // Clone native metadata and return new pointer
+ return reinterpret_cast<jlong>(new CameraMetadata(*otherMetadata));
+}
+
+
static jboolean CameraMetadata_isEmpty(JNIEnv *env, jobject thiz) {
ALOGV("%s", __FUNCTION__);
@@ -361,6 +376,9 @@
{ "nativeAllocate",
"()J",
(void*)CameraMetadata_allocate },
+ { "nativeAllocateCopy",
+ "(L" CAMERA_METADATA_CLASS_NAME ";)J",
+ (void *)CameraMetadata_allocateCopy },
{ "nativeIsEmpty",
"()Z",
(void*)CameraMetadata_isEmpty },
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 0cd6f4a..1c43cc5 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -190,7 +190,7 @@
int frameSize = nbChannels * bytesPerSample;
size_t frameCount = buffSizeInBytes / frameSize;
- if (uint32_t(source) >= AUDIO_SOURCE_CNT) {
+ if ((uint32_t(source) >= AUDIO_SOURCE_CNT) && (uint32_t(source) != AUDIO_SOURCE_HOTWORD)) {
ALOGE("Error creating AudioRecord: unknown source.");
return AUDIORECORD_ERROR_SETUP_INVALIDSOURCE;
}
@@ -387,6 +387,9 @@
(jint)recorderBuffSize : sizeInBytes );
env->ReleaseByteArrayElements(javaAudioData, recordBuff, 0);
+ if (readSize < 0) {
+ readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+ }
return (jint) readSize;
}
@@ -427,8 +430,12 @@
}
// read new data from the recorder
- return (jint) lpRecorder->read(nativeFromJavaBuf,
+ ssize_t readSize = lpRecorder->read(nativeFromJavaBuf,
capacity < sizeInBytes ? capacity : sizeInBytes);
+ if (readSize < 0) {
+ readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+ }
+ return (jint)readSize;
}
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
index 3fd8ed9..463be5e 100644
--- a/core/jni/android_media_RemoteDisplay.cpp
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -24,6 +24,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
+#include <android_runtime/Log.h>
#include <binder/IServiceManager.h>
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index dd07c4f..60540f4 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -21,6 +21,7 @@
#include "utils/misc.h"
#include "cutils/debugger.h"
+#include <cutils/log.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
@@ -515,6 +516,87 @@
return android_os_Debug_getPssPid(env, clazz, getpid(), NULL);
}
+static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
+{
+ char buffer[1024];
+ int numFound = 0;
+
+ if (out == NULL) {
+ jniThrowNullPointerException(env, "out == null");
+ return;
+ }
+
+ int fd = open("/proc/meminfo", O_RDONLY);
+
+ if (fd < 0) {
+ printf("Unable to open /proc/meminfo: %s\n", strerror(errno));
+ return;
+ }
+
+ const int len = read(fd, buffer, sizeof(buffer)-1);
+ close(fd);
+
+ if (len < 0) {
+ printf("Empty /proc/meminfo");
+ return;
+ }
+ buffer[len] = 0;
+
+ static const char* const tags[] = {
+ "MemTotal:",
+ "MemFree:",
+ "Buffers:",
+ "Cached:",
+ "Shmem:",
+ "Slab:",
+ NULL
+ };
+ static const int tagsLen[] = {
+ 9,
+ 8,
+ 8,
+ 7,
+ 6,
+ 5,
+ 0
+ };
+ long mem[] = { 0, 0, 0, 0, 0, 0 };
+
+ char* p = buffer;
+ while (*p && numFound < 6) {
+ int i = 0;
+ while (tags[i]) {
+ if (strncmp(p, tags[i], tagsLen[i]) == 0) {
+ p += tagsLen[i];
+ while (*p == ' ') p++;
+ char* num = p;
+ while (*p >= '0' && *p <= '9') p++;
+ if (*p != 0) {
+ *p = 0;
+ p++;
+ }
+ mem[i] = atoll(num);
+ numFound++;
+ break;
+ }
+ i++;
+ }
+ while (*p && *p != '\n') {
+ p++;
+ }
+ if (*p) p++;
+ }
+
+ int maxNum = env->GetArrayLength(out);
+ jlong* outArray = env->GetLongArrayElements(out, 0);
+ if (outArray != NULL) {
+ for (int i=0; i<maxNum && tags[i]; i++) {
+ outArray[i] = mem[i];
+ }
+ }
+ env->ReleaseLongArrayElements(out, outArray, 0);
+}
+
static jint read_binder_stat(const char* stat)
{
FILE* fp = fopen(BINDER_STATS, "r");
@@ -789,6 +871,8 @@
(void*) android_os_Debug_getPss },
{ "getPss", "(I[J)J",
(void*) android_os_Debug_getPssPid },
+ { "getMemInfo", "([J)V",
+ (void*) android_os_Debug_getMemInfo },
{ "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V",
(void*) android_os_Debug_dumpNativeHeap },
{ "getBinderSentTransactions", "()I",
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index 17a0677..c83541d 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -19,6 +19,7 @@
#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
#include <utils/Log.h>
#include <input/Input.h>
#include "android_view_KeyEvent.h"
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index ad6c0f2..f1b90e1 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -20,6 +20,7 @@
#include <SkMatrix.h>
#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
#include <utils/Log.h>
#include <input/Input.h>
#include "android_os_Parcel.h"
diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp
index 8b6dc60..5e29213 100644
--- a/core/jni/android_view_PointerIcon.cpp
+++ b/core/jni/android_view_PointerIcon.cpp
@@ -21,6 +21,7 @@
#include "android_view_PointerIcon.h"
#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
#include <utils/Log.h>
#include <android/graphics/GraphicsJNI.h>
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 3f54fd7..1868469 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -26,6 +26,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
+#include <android_runtime/Log.h>
#include <binder/Parcel.h>
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2e47928..c2a830d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -899,6 +899,13 @@
android:label="@string/permlab_wakeLock"
android:description="@string/permdesc_wakeLock" />
+ <!-- Allows using the device's IR transmitter, if available -->
+ <permission android:name="android.permission.TRANSMIT_IR"
+ android:permissionGroup="android.permission-group.AFFECTS_BATTERY"
+ android:protectionLevel="normal"
+ android:label="@string/permlab_transmitIr"
+ android:description="@string/permdesc_transmitIr" />
+
<!-- ==================================================== -->
<!-- Permissions related to changing audio settings -->
<!-- ==================================================== -->
@@ -1096,6 +1103,13 @@
android:description="@string/permdesc_use_sip"
android:label="@string/permlab_use_sip" />
+ <!-- Allows an application to request CallHandlerService implementations. -->
+ <permission android:name="android.permission.BIND_CALL_SERVICE"
+ android:permissionGroup="android.permission-group.PHONE_CALLS"
+ android:protectionLevel="system|signature"
+ android:description="@string/permdesc_bind_call_service"
+ android:label="@string/permlab_bind_call_service" />
+
<!-- ================================== -->
<!-- Permissions for sdcard interaction -->
<!-- ================================== -->
@@ -2071,6 +2085,14 @@
android:description="@string/permdesc_captureAudioOutput"
android:protectionLevel="signature|system" />
+ <!-- Allows an application to capture audio for hotword detection.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD"
+ android:label="@string/permlab_captureAudioHotword"
+ android:description="@string/permdesc_captureAudioHotword"
+ android:protectionLevel="signature|system" />
+
<!-- Allows an application to capture video output.
<p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
@@ -2444,13 +2466,6 @@
android:description="@string/permdesc_accessNetworkConditions"
android:protectionLevel="signature|system" />
- <!-- Allows an application to request HotwordRecognition.
- @hide This is not a third-party API (intended for system apps). -->
- <permission android:name="android.permission.HOTWORD_RECOGNITION"
- android:label="@string/permlab_hotwordRecognition"
- android:description="@string/permdesc_hotwordRecognition"
- android:protectionLevel="signature|system" />
-
<!-- The system process is explicitly the only one allowed to launch the
confirmation UI for full backup/restore -->
<uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/res/res/drawable-hdpi/activity_picker_bg_activated.9.png b/core/res/res/drawable-hdpi/activity_picker_bg_activated.9.png
deleted file mode 100644
index e591a7b..0000000
--- a/core/res/res/drawable-hdpi/activity_picker_bg_activated.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/activity_picker_bg_focused.9.png b/core/res/res/drawable-hdpi/activity_picker_bg_focused.9.png
deleted file mode 100644
index ea27290d..0000000
--- a/core/res/res/drawable-hdpi/activity_picker_bg_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb_am.png b/core/res/res/drawable-hdpi/stat_sys_adb_am.png
index 0c13339..382557e 100644
--- a/core/res/res/drawable-hdpi/stat_sys_adb_am.png
+++ b/core/res/res/drawable-hdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_certificate_info.png b/core/res/res/drawable-hdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..3be426c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_notify_call_mute.png b/core/res/res/drawable-ldpi/stat_notify_call_mute.png
index d160009..353ecf2 100644
--- a/core/res/res/drawable-ldpi/stat_notify_call_mute.png
+++ b/core/res/res/drawable-ldpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_speakerphone.png b/core/res/res/drawable-ldpi/stat_sys_speakerphone.png
index 7fc67a0..22ecd30 100644
--- a/core/res/res/drawable-ldpi/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-ldpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/activity_picker_bg_activated.9.png b/core/res/res/drawable-mdpi/activity_picker_bg_activated.9.png
deleted file mode 100644
index 7dfea4c..0000000
--- a/core/res/res/drawable-mdpi/activity_picker_bg_activated.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/activity_picker_bg_focused.9.png b/core/res/res/drawable-mdpi/activity_picker_bg_focused.9.png
deleted file mode 100644
index 99b0279..0000000
--- a/core/res/res/drawable-mdpi/activity_picker_bg_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb_am.png b/core/res/res/drawable-mdpi/stat_sys_adb_am.png
index f0a5089..4380035 100644
--- a/core/res/res/drawable-mdpi/stat_sys_adb_am.png
+++ b/core/res/res/drawable-mdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_certificate_info.png b/core/res/res/drawable-mdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..e15cf38
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
index 4fd0e3c..6351c2d 100644
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ b/core/res/res/drawable-nodpi/platlogo.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-hdpi/stat_notify_call_mute.png b/core/res/res/drawable-sw600dp-hdpi/stat_notify_call_mute.png
index 5d4ad05..996aadc 100644
--- a/core/res/res/drawable-sw600dp-hdpi/stat_notify_call_mute.png
+++ b/core/res/res/drawable-sw600dp-hdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-hdpi/stat_sys_speakerphone.png b/core/res/res/drawable-sw600dp-hdpi/stat_sys_speakerphone.png
index 66895fa..e440805 100644
--- a/core/res/res/drawable-sw600dp-hdpi/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-sw600dp-hdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-mdpi/stat_notify_call_mute.png b/core/res/res/drawable-sw600dp-mdpi/stat_notify_call_mute.png
index 08017ac..5ebf23a 100644
--- a/core/res/res/drawable-sw600dp-mdpi/stat_notify_call_mute.png
+++ b/core/res/res/drawable-sw600dp-mdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-mdpi/stat_sys_speakerphone.png b/core/res/res/drawable-sw600dp-mdpi/stat_sys_speakerphone.png
index 276dea1..0228134 100644
--- a/core/res/res/drawable-sw600dp-mdpi/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-sw600dp-mdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xhdpi/stat_notify_call_mute.png b/core/res/res/drawable-sw600dp-xhdpi/stat_notify_call_mute.png
index cdef5d9..142080a 100644
--- a/core/res/res/drawable-sw600dp-xhdpi/stat_notify_call_mute.png
+++ b/core/res/res/drawable-sw600dp-xhdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xhdpi/stat_sys_speakerphone.png b/core/res/res/drawable-sw600dp-xhdpi/stat_sys_speakerphone.png
index 262af38..f9563b2 100644
--- a/core/res/res/drawable-sw600dp-xhdpi/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-sw600dp-xhdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xxhdpi/stat_notify_call_mute.png b/core/res/res/drawable-sw600dp-xxhdpi/stat_notify_call_mute.png
index 13ec34e..dd1b5be 100644
--- a/core/res/res/drawable-sw600dp-xxhdpi/stat_notify_call_mute.png
+++ b/core/res/res/drawable-sw600dp-xxhdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xxhdpi/stat_sys_speakerphone.png b/core/res/res/drawable-sw600dp-xxhdpi/stat_sys_speakerphone.png
index 34a4c45..df9bff1 100644
--- a/core/res/res/drawable-sw600dp-xxhdpi/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-sw600dp-xxhdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/activity_picker_bg_activated.9.png b/core/res/res/drawable-xhdpi/activity_picker_bg_activated.9.png
deleted file mode 100644
index f01a79e..0000000
--- a/core/res/res/drawable-xhdpi/activity_picker_bg_activated.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/activity_picker_bg_focused.9.png b/core/res/res/drawable-xhdpi/activity_picker_bg_focused.9.png
deleted file mode 100644
index 7bea197..0000000
--- a/core/res/res/drawable-xhdpi/activity_picker_bg_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/default_wallpaper.jpg b/core/res/res/drawable-xhdpi/default_wallpaper.jpg
deleted file mode 100644
index da9fa91..0000000
--- a/core/res/res/drawable-xhdpi/default_wallpaper.jpg
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
index 789a3f5..3222a76 100644
--- a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
+++ b/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_certificate_info.png b/core/res/res/drawable-xhdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..3c93ea0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/activity_picker_bg_activated.9.png b/core/res/res/drawable-xxhdpi/activity_picker_bg_activated.9.png
deleted file mode 100644
index 47bc2b5..0000000
--- a/core/res/res/drawable-xxhdpi/activity_picker_bg_activated.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/activity_picker_bg_focused.9.png b/core/res/res/drawable-xxhdpi/activity_picker_bg_focused.9.png
deleted file mode 100644
index 3bd381d..0000000
--- a/core/res/res/drawable-xxhdpi/activity_picker_bg_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
index a36fa36..e01ad386 100644
--- a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
+++ b/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_2.png b/core/res/res/drawable-xxhdpi/stat_sys_certificate_info.png
similarity index 64%
rename from packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_2.png
rename to core/res/res/drawable-xxhdpi/stat_sys_certificate_info.png
index 71e396e..d96ef64 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_2.png
+++ b/core/res/res/drawable-xxhdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/drawable/activity_picker_bg.xml b/core/res/res/drawable/activity_picker_bg.xml
deleted file mode 100644
index a471c94..0000000
--- a/core/res/res/drawable/activity_picker_bg.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:state_window_focused="false" android:drawable="@color/transparent" />
-
- <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
- <item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/list_selector_disabled_holo_light" />
- <item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/list_selector_disabled_holo_light" />
- <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition_holo_light" />
- <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition_holo_light" />
- <item android:state_focused="true" android:drawable="@drawable/activity_picker_bg_focused" />
- <item android:state_activated="true" android:drawable="@drawable/activity_picker_bg_activated" />
- <item android:drawable="@color/transparent" />
-
-</selector>
diff --git a/core/res/res/layout/action_bar_title_item.xml b/core/res/res/layout/action_bar_title_item.xml
index ccc5b07..fecfded 100644
--- a/core/res/res/layout/action_bar_title_item.xml
+++ b/core/res/res/layout/action_bar_title_item.xml
@@ -16,33 +16,20 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:paddingEnd="8dip"
- android:enabled="false">
-
- <ImageView android:id="@android:id/up"
- android:src="?android:attr/homeAsUpIndicator"
- android:layout_gravity="center_vertical|start"
- android:visibility="gone"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|start"
- android:orientation="vertical">
- <TextView android:id="@+id/action_bar_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="end" />
- <TextView android:id="@+id/action_bar_subtitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/action_bar_subtitle_top_margin"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone" />
- </LinearLayout>
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|start"
+ android:orientation="vertical"
+ android:paddingEnd="8dp">
+ <TextView android:id="@+id/action_bar_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end" />
+ <TextView android:id="@+id/action_bar_subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/action_bar_subtitle_top_margin"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone" />
</LinearLayout>
diff --git a/core/res/res/layout/resolve_list_item.xml b/core/res/res/layout/resolve_list_item.xml
index 28c5b74..281541b 100644
--- a/core/res/res/layout/resolve_list_item.xml
+++ b/core/res/res/layout/resolve_list_item.xml
@@ -21,7 +21,7 @@
android:orientation="horizontal"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:background="@android:drawable/activity_picker_bg">
+ android:background="?attr/activatedBackgroundIndicator">
<!-- Activity icon when presenting dialog
Size will be filled in by ResolverActivity -->
diff --git a/core/res/res/layout/toast_bar.xml b/core/res/res/layout/toast_bar.xml
index b7443d5..a31d7cb 100644
--- a/core/res/res/layout/toast_bar.xml
+++ b/core/res/res/layout/toast_bar.xml
@@ -35,7 +35,7 @@
android:paddingRight="16dp"
android:singleLine="true"
android:textColor="@android:color/white"
- android:textSize="16sp" />
+ android:textSize="14sp" />
<LinearLayout
android:id="@android:id/button1"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 59749d4..49b2bdc 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Te veel <xliff:g id="CONTENT_TYPE">%s</xliff:g> uitgevee."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet se berging is vol. Vee \'n aantal lêers uit om spasie vry te maak."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Foon se berging is vol. Vee \'n aantal lêers uit om spasie vry te maak."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netwerk kan dalk gemonitor word"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Ek"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tablet-opsies"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Foonopsies"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"verhoed program-oorskakelings"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Verhoed dat die gebruiker na \'n ander program oorskakel."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"kry huidige program-inligting"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Laat die houer toe om private inligting oor die huidige program en dienste op die voorgrond van die skerm te herwin."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Laat die houer toe om private inligting oor die huidige program op die voorgrond van die skerm te herwin."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitor en beheer alle programlaaiery"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Laat die program toe om te monitor en te beheer hoe die stelsel aktiwiteite laai. Kwaadwillige programme kan dalk die stelsel heeltemal in gevaar stel. Hierdie toestemming is net nodig vir ontwikkeling, en nooit vir normale gebruik nie."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"stuur uitsending met pakket verwyder"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Laat die program toe om laevlak-kenmerke van Wi-Fi-skerms te beheer."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"vang oudio-uitset vas"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Laat die program oudio-uitset vasvang en herlei."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Aktiveerwoord-opsporing"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Laat die program toe om oudio vir Aktiveerwoord-opsporing op te neem. Die opname kan in die agtergrond plaasvind, maar verhoed nie dat ander oudio opgeneem word nie (bv. Kameraopnemer)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"vang video-uitset vas"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Laat die program video-uitset vasvang en herlei."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"vang veilige video-uitset vas"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"verhoed foon om te slaap"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Laat die program toe om die tablet te keer om te slaap."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Laat die program toe om die foon te keer om te slaap."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"versend infrarooi"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Laat die program toe om die tablet se infrarooisender te gebruik."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Laat die program toe om die foon se infrarooisender te gebruik."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"skakel tablet aan of af"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"Sit foon aan of af"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Laat die program toe om die tablet aan en af te skakel."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 8e782a3..32123fb 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"በጣም ብዙ <xliff:g id="CONTENT_TYPE">%s</xliff:g> ስርዞች።"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"የጡባዊ ተኮ ማከማቻ ሙሉ ነው! ቦታ ነፃ ለማድረግ አንዳንድ ፋይሎች ሰርዝ።"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"የስልክ ማከማቻ ሙሉ ነው! ቦታ ነፃ ለማድረግ አንዳንድ ፋይሎች ሰርዝ።"</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"አውታረ መረብ በክትትል ውስጥ ሊሆን ይችላል"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"እኔ"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"የጡባዊ አማራጮች"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"የስልክ አማራጮች"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"የትግበራ መቀያየርን ተከላከል"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"ተጠቃሚው ከሌላ መተግበሪያ ከመቀየር ይከላከላል።"</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"የአሁኑ የመተግበሪያ መረጃ ያግኙ"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"ያዢው በአሁኑ መተግበሪያ እና በማያ ገጹ ፊት ላይ ስላሉ መተግበሪያዎች የግል መረጃ እንዲያመጣ ያስችለዋል።"</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"ያዢው በማያ ገጹ ፊት ላይ ስላለው የአሁኑ መተግበሪያ የግል መረጃ እንዲያመጣ ያስችለዋል።"</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"ሁሉንም መተግበሪያ ማስነሻ አሳይ እና ተቆጣጠር"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"እንቅስቃሴዎችን ስርዓቱ እንዴት እንደሚያስጀምር ለመከታተል እና ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ፡፡ ተንኮል አዘል መተግበሪያዎች የስርዓቱን ክብረ ገመና ሙሉለሙሉ ሊያጋልጡ ይችላሉ፡፡ ይህ ፍቃድ የሚያስፈልገው ለግንባታ ብቻ ነው፤ ለመደበኛ አጠቃቀም ፈጽሞ አይደለም፡፡"</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"አካታች የተወገደለት ስርጭት ላክ"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"መተግበሪያው በዝቅተኛ ደረጃ ላይ ያሉ የWifi ማሳያዎችን እንዲቆጣጠር ይፈቅድለታል።"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"የድምጽ ውጽዓት ይቅረጹ"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"መተግበሪያው የድምጽ ውጽዓት እንዲቀርጽ እና አቅጣጫውን እንዲያዞር ያስችለዋል።"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ትኩስ ቃል ማወቅ"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"ትኩስ ቃል ለይቶ ለማወቅ ድምጽ እንዲቀርጽ ለመተግበሪያው ይፈቅድለታል። ቀረጻው በጀርባ ሊካሄድ ይችላል ነገር ግን ሌላ የድምጽ ቀረጻዎችን አይከለክልም (ለምሳሌ፣ የካሜራ መቅረጫ)።"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"የቪዲዮ ውጽዓት ይቅረጹ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"መተግበሪያው የቪዲዮ ውጽዓት እንዲቀርጽ እና አቅጣጫውን እንዲያዞር ያስችለዋል።"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ደህንነቱ የተጠበቀ የቪዲዮ ውጽዓት ይቅረጹ"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ስልክ ከማንቀላፋት ተከላከል"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ጡባዊውን ከመተኛት መከልከል ለመተግበሪያው ይፈቅዳሉ።"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"ስልኩን ከመተኛት መከልከል ለመተግበሪያው ይፈቅዳሉ።"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"ኢንፍራርድ አስተላልፍ"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"የጡባዊውን የኢንፍራሪድ አስተላላፊ እንዲጠቀም ለመተግበሪያው ይፈቅድለታል።"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"የስልኩን የኢንፍራሪድ አስተላላፊ እንዲጠቀም ለመተግበሪያው ይፈቅድለታል።"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"ጡባዊ አብራ ወይም አጥፋ"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"ስልክ አብራ ወይም አጥፋ"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"ጡባዊ ተኮውን ለማብራት እና ለማጥፋት ለመተግበሪያው ይፈቅዳሉ።"</string>
@@ -655,7 +665,7 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ያዢው በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን እንዲጠራው ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"በአውታረ መረብ ሁኔታዎች ላይ የተስተዋሉ ነገሮችን ያዳምጣል"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"አንድ መተግበሪያ በአውታረ መረብ ሁኔታዎች ላይ የተስተዋሉ ነገሮችን እንዲያዳምጥ ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አስፈላጊ ሊሆን አይገባም።"</string>
- <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ድንቦች አዘጋጅ"</string>
+ <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ደንቦች አዘጋጅ"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"በማያ-መክፈት የተፈቀዱ የይለፍ ቃል ርዝመት እና ቁምፊዎች ተቆጣጠር።"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"ማሳያውን በምትከፍትበት ጊዜ በስህተት የተተየቡ የይለፍ ቃሎችን ቁጥር ተቆጣጠር፤ እና ጡባዊ ተኮውን ቆልፍ ወይም በጣም ብዙ የተሳሳቱ የይለፍ ቃሎች ከተተየቡ የጡባዊ ተኮን ውሂብ አጥፋ፡፡"</string>
@@ -801,7 +811,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"ለመክፈት፣ምናሌ ተጫን ከዛ 0"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"የአደጋ ጊዜቁጥር"</string>
<string name="lockscreen_carrier_default" msgid="8963839242565653192">"ከአገልግሎት መስጫ ክልል ውጪ"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"ማሳያ ተቆልፏል።"</string>
+ <string name="lockscreen_screen_locked" msgid="7288443074806832904">"ማሳያ መቆለፊያ።"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"ለመክፈት ምናሌ ተጫንወይም የአደጋ ጊዜ ጥሪ አድርግ።"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"ለመክፈት ምናሌ ተጫን"</string>
<string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"ለመክፈት ስርዓተ ጥለት ሳል"</string>
@@ -964,7 +974,7 @@
<string name="oneMonthDurationPast" msgid="7396384508953779925">"ከ1 ወር በፊት"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ከ1 ወር በፊት"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"ከ1 ሰከንድ በፊት"</item>
+ <item quantity="one" msgid="4869870056547896011">"ከ1 ሴኮንድ በፊት"</item>
<item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ሰኮንዶች በፊት"</item>
</plurals>
<plurals name="num_minutes_ago">
@@ -985,7 +995,7 @@
<item quantity="other" msgid="2479586466153314633">"ከ <xliff:g id="COUNT">%d</xliff:g>ቀን በፊት"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"በ1 ሰከንድ"</item>
+ <item quantity="one" msgid="2729745560954905102">"በ1 ሴኮንድ"</item>
<item quantity="other" msgid="1241926116443974687">"በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ"</item>
</plurals>
<plurals name="in_num_minutes">
@@ -1001,7 +1011,7 @@
<item quantity="other" msgid="5109449375100953247">"በ<xliff:g id="COUNT">%d</xliff:g> ቀናት"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 ሰከንድ በፊት"</item>
+ <item quantity="one" msgid="1849036840200069118">"1 ሴኮንድ በፊት"</item>
<item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች በፊት"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
@@ -1017,7 +1027,7 @@
<item quantity="other" msgid="3453342639616481191">"ከ <xliff:g id="COUNT">%d</xliff:g>ቀን በፊት"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"በ1 ሰከንድ"</item>
+ <item quantity="one" msgid="5842225370795066299">"በ1 ሴኮንድ"</item>
<item quantity="other" msgid="5495880108825805108">"በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
@@ -1041,14 +1051,14 @@
<string name="hours" msgid="894424005266852993">"ሰዓቶች"</string>
<string name="minute" msgid="9148878657703769868">"ደቂቃ"</string>
<string name="minutes" msgid="5646001005827034509">" ደቂቃዎች"</string>
- <string name="second" msgid="3184235808021478">"ሰከንድ"</string>
+ <string name="second" msgid="3184235808021478">"ሴኮንድ"</string>
<string name="seconds" msgid="3161515347216589235">"ሰከንዶች"</string>
<string name="week" msgid="5617961537173061583">"ሳምንት"</string>
<string name="weeks" msgid="6509623834583944518">"ሳምንቶች"</string>
<string name="year" msgid="4001118221013892076">"ዓመት"</string>
<string name="years" msgid="6881577717993213522">"ዓመታት"</string>
<plurals name="duration_seconds">
- <item quantity="one" msgid="6962015528372969481">"1 ሰከንድ"</item>
+ <item quantity="one" msgid="6962015528372969481">"1 ሴኮንድ"</item>
<item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች"</item>
</plurals>
<plurals name="duration_minutes">
@@ -1568,7 +1578,7 @@
<string name="write_fail_reason_cancelled" msgid="7091258378121627624">"ተትቷል"</string>
<string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"ይዘት መጻፍ ላይ ስህተት"</string>
<string name="reason_unknown" msgid="6048913880184628119">"አይታወቅም"</string>
- <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"አስተዳዳሪ ፒን ያስገቡ"</string>
+ <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"የአስተዳዳሪ ፒን ያስገቡ"</string>
<string name="restr_pin_enter_pin" msgid="3395953421368476103">"ፒን ያስገቡ"</string>
<string name="restr_pin_incorrect" msgid="8571512003955077924">"ትክክል አይደለም"</string>
<string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"የአሁኑ ፒን"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 8988e2e..7f3e678 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"عمليات حذف <xliff:g id="CONTENT_TYPE">%s</xliff:g> كثيرة للغاية."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"سعة تخزين الجهاز اللوحي ممتلئة! احذف بعض الملفات لإخلاء مساحة."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"سعة تخزين الهاتف ممتلئة. احذف بعض الملفات لإخلاء مساحة."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"قد تكون الشبكة مراقبة"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"بواسطة جهة خارجية غير معلومة"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"بواسطة <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"أنا"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"خيارات الجهاز اللوحي"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"خيارات الهاتف"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"منع التبديل بين التطبيقات"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"لمنع المستخدم من التبديل إلى تطبيق آخر."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"الحصول على معلومات عن التطبيق الحالي"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"للسماح للمالك باسترداد معلومات خاصة عن الخدمات والتطبيق الحالي في مقدمة الشاشة."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"للسماح للمالك باسترداد معلومات خاصة عن التطبيق الحالي في مقدمة الشاشة."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"مراقبة بدء تشغيل جميع التطبيقات والتحكم فيها"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"للسماح للتطبيق بمراقبة كيفية بدء النظام للأنشطة والتحكم فيها. قد تُعرِّض التطبيقات الضارة النظام للضرر بشكل كامل. لن تكون هناك حاجة لهذا الإذن سوى للتطوير فقط، وليس للاستخدام العادي على الإطلاق."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"إرسال بث الحزمة الذي تمت إزالته"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"للسماح للتطبيق بالتحكم في الميزات ذات المستوى المنخفض في شاشات Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"التقاط إخراج الصوت"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"السماح للتطبيق بالتقاط إخراج الصوت وإعادة توجيهه."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"اكتشاف الكلمة المهمة"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"للسماح للتطبيق بالتقاط الصوت لاكتشاف الكلمة المهمة. يمكن أن يتم الالتقاط في الخلفية ولكنه لا يمنع التقاط الأصوات الأخرى (على سبيل المثال، كاميرا الفيديو)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"التقاط إخراج الفيديو"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"السماح للتطبيق بالتقاط إخراج الفيديو وإعادة توجيهه."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"التقاط إخراج الفيديو الآمن"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"منع الهاتف من الدخول في وضع السكون"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"للسماح للتطبيق بمنع الجهاز اللوحي من الانتقال إلى وضع السكون."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"للسماح للتطبيق بمنع الهاتف من الانتقال إلى وضع السكون."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"إرسال الأشعة تحت الحمراء"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"للسماح للتطبيق باستخدام مرسل الأشعة تحت الحمراء الخاص بالجهاز اللوحي."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"للسماح للتطبيق باستخدام مرسل الأشعة تحت الحمراء الخاص بالهاتف."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"تشغيل الجهاز اللوحي أو إيقاف تشغيله"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"تشغيل الهاتف أو إيقاف تشغيله"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"للسماح للتطبيق بتشغيل الجهاز اللوحي أو إيقاف تشغيله."</string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 839ac38..2f0781c 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -314,7 +314,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"tətbiqdən tətbiqə keçidin qarşısını almaq"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"İstifadəçinin başqa tətbiqə keçməsinin qarşısını alır."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"cari tətbiq informasiyası əldə etmək"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Sahibə ekran önündə cari tətbiq və xidmətlər haqqında şəxsi məlumat əldə etməyə imkan verir."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Sahibinə ekranda öndə olan cari tətbiq haqda gizli məlumatı almaq icazəsi verir."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"işə salınan bütün tətbiqləri izləyir və idarə edir"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Tətbiqə sistemin fəaliyyətləri necə başlatdığını nəzarət və kontrol etməyə imkan verir. Zərərli tətbiqlər sistemi tamamilə kompromis edə bilər. Bu icazə yalnız inkişaf üçündür, heç vaxt normal istifadə üçün deyil."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"qaldırılmış yayım paketini göndər"</string>
@@ -655,6 +655,8 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Sahibinə operator xidmətli tətbiq konfiqurasiyasına müraciət imkanı verir. Normal tətbiqlər üçün tələb olunmamalıdır."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"şəbəkə şəraiti haqqında müşahidələr üçün qulaq asmaq"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Tətbiqə şəbəkə şəraiti üzrə müşahidələr üçün qulaq asmaq imkanı verir. Normal tətbiqlər üçün heç vaxt lazım olmamalıdır."</string>
+ <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"isti söz tanınması tələb et"</string>
+ <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Tətbiqə isti söz tanınması tələb etməyə imkan verir. Normal tətbiq üçün lazım ola bilməz."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Parol qaydalarını təyin edin"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Ekran kilidini açan şifrələrin uzunluğunu və onlardakı icazə verilən işarələrə nəzarət edir."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidi cəhdlərini monitorinq et"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index cc799dfd..22464ee 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -131,6 +131,12 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Занадта шмат выдаленняў <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Памяць планшэта поўная. Выдаліце некаторыя файлы, каб вызваліць месца."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Памяць тэлефона поўная. Выдаліце некаторыя файлы, каб вызваліць месца."</string>
+ <!-- no translation found for ssl_ca_cert_warning (5848402127455021714) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Я"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Параметры планшэта"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Параметры тэлефона"</string>
@@ -316,8 +322,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"прадухіляць пераключэнне прыкладанняў"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Не дазваляе карыстальніку пераходзіць да іншага прыкладання."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"атрымаць бягучую інфармацыю прыкладання"</string>
- <!-- no translation found for permdesc_getTopActivityInfo (8153651434145132505) -->
- <skip />
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Дазваляе ўладальніку атрымлiваць асабістую інфармацыю аб бягучым прыкладаннi на пярэднім плане экрана."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"адсочваць і кантраляваць запуск усіх прыкладанняў"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Дазваляе прыкладанню сачыць і кантраляваць, як сістэма запускае працэсы. Шкоднасныя прыкладанні могуць цалкам парушыць працу сістэмы. Гэты дазвол патрэбны толькі для распрацоўкі, ніколі для звычайнага выкарыстання."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"трансляваць паведамленні аб выдаленні пакетаў"</string>
@@ -491,6 +496,10 @@
<skip />
<!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
<skip />
+ <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
+ <skip />
+ <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
+ <skip />
<!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
<skip />
<!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
@@ -562,6 +571,12 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"забараняць тэлефону пераходзіць ў рэжым сну"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дазваляе прыкладанням прадухіляць пераход планшэта ў рэжым сну."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Дазваляе прыкладанням прадухіляць тэлефон ад пераходу ў рэжым сну."</string>
+ <!-- no translation found for permlab_transmitIr (7545858504238530105) -->
+ <skip />
+ <!-- no translation found for permdesc_transmitIr (5358308854306529170) -->
+ <skip />
+ <!-- no translation found for permdesc_transmitIr (7957763745020300725) -->
+ <skip />
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Уключыць або выключыць планшэт"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"уключаць або выключаць тэлефон"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Дазваляе прыкладанням уключаць ці адключаць планшэт."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index b9cb281..040d274 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Изтриванията за <xliff:g id="CONTENT_TYPE">%s</xliff:g> са твърде много."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Хранилището на таблета е пълно. Изтрийте файлове, за да освободите място."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Хранилището на телефона е пълно. Изтрийте файлове, за да освободите място."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежата може да се наблюдава"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Аз"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Опции за таблета"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Опции на телефона"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"предотвратяване на превключването между приложения"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Не позволява на потребителя да превключва към друго приложение."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"извличане на информация за текущото приложение"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Разрешава на собственика да извлича частна информация за текущото приложение и услуги на преден план на екрана."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Разрешава на собственика да извлича частна информация за текущото приложение на преден план на екрана."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"наблюдение и контрол на стартирането на всички приложения"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Разрешава на приложението да наблюдава и контролира как системата стартира дейности. Злонамерените приложения могат изцяло да компрометират системата. Това разрешение е нужно само за програмиране, никога за нормална употреба."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"изпращане на излъчване при премахнат пакет"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Разрешава на приложението да контролира функциите от ниско ниво на дисплеите през WiFi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"записване на възпроизвеждания звук"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Разрешава на приложението да записва и пренасочва възпроизвеждания звук."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Откриване на активиращи думи"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Разрешава на приложението да записва звук с цел откриване на активиращи думи. Това може да става на заден план, но не пречи на записването на други звуци (напр. от видеокамерата)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"записване на възпроизвеждания образ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Разрешава на приложението да записва и пренасочва възпроизвеждания образ."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"записване на защитеното възпроизвеждане на образ"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"предотвратява спящ режим на телефона"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Разрешава на приложението да предотвратява преминаването на таблета в спящ режим."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Разрешава на приложението да предотвратява преминаването на телефона в спящ режим."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"предаване чрез инфрачервени лъчи"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Разрешава на приложението да използва инфрачервения предавател на таблета."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Разрешава на приложението да използва инфрачервения предавател на телефона."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"включване или изключване на таблета"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"включване или изключване на телефона"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Разрешава на приложението да включва или изключва таблета."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4ed0664..a58f5b2 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Massa supressions de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"L\'emmagatzematge de la tauleta és ple. Suprimeix uns quants fitxers per alliberar espai."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"L\'emmagatzematge del telèfon és ple. Suprimeix uns quants fitxers per alliberar espai."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Pot ser que la xarxa se supervisi."</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Mi"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opcions de la tauleta"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opcions del telèfon"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedir els canvis d\'aplicació"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Impedeix que l\'usuari canviï a una altra aplicació."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"obtenció d\'informació de l\'aplicació actual"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Permet que el titular recuperi informació privada sobre l\'aplicació i els serveis actuals al primer pla de la pantalla."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permet que el titular recuperi informació privada sobre l\'aplicació actual al primer pla de la pantalla."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"supervisa i controla tots els inicis d\'aplicacions"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permet que l\'aplicació supervisi i controli com el sistema inicia activitats. Les aplicacions malicioses poden comprometre totalment el sistema. Aquest permís només és necessari per al desenvolupament, mai per a l\'ús normal."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar difusió d\'eliminació de paquet"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permet a l\'aplicació controlar les funcions de baix nivell de les pantalles Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"captura la sortida d\'àudio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permet que l\'aplicació capturi i redirigeixi la sortida d\'àudio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detecció de paraules actives"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permet que l\'aplicació capturi àudio per a la detecció de paraules actives. La captura es pot produir en segon pla però no evita altres captures d\'àudio (per exemple, de càmera de vídeo)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"captura la sortida de vídeo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permet que l\'aplicació capturi i redirigeixi la sortida de vídeo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"captura la sortida de vídeo segur"</string>
@@ -530,19 +537,22 @@
<string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar directament la configuració del telèfon CDMA"</string>
<string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permet que l\'aplicació iniciï l\'aprovisionament CDMA. Les aplicacions malicioses poden iniciar l\'aprovisionament CDMA innecessàriament."</string>
<string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar les notificacions d\'actualització de la ubicació"</string>
- <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permet que l\'aplicació activi i desactivi les notificacions d\'actualització de la ubicació de la ràdio. No la poden fer servir les aplicacions normals."</string>
+ <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permet que l\'aplicació activi i desactivi les notificacions d\'actualització de la ubicació del senyal mòbil. No la poden fer servir les aplicacions normals."</string>
<string name="permlab_checkinProperties" msgid="7855259461268734914">"accedir a les propietats d\'accés"</string>
<string name="permdesc_checkinProperties" msgid="4024526968630194128">"Permet a l\'aplicació l\'accés de lectura/escriptura a les propietats penjades pel servei de registre. No es pot fer servir per a les aplicacions normals."</string>
<string name="permlab_bindGadget" msgid="776905339015863471">"triar widgets"</string>
<string name="permdesc_bindGadget" msgid="8261326938599049290">"Permet que l\'aplicació indiqui al sistema quins widgets pot utilitzar cada aplicació. Amb aquest permís, les aplicacions poden concedir accés a les dades personals a altres aplicacions. No indicat per a les aplicacions normals."</string>
<string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modificar l\'estat del telèfon"</string>
- <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permet que l\'aplicació controli les funcions de telèfon del dispositiu. Una aplicació amb aquest permís pot canviar de xarxa, activar i desactivar la ràdio del telèfon i dur a terme accions semblants sense notificar-t\'ho."</string>
+ <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permet que l\'aplicació controli les funcions de telèfon del dispositiu. Una aplicació amb aquest permís pot canviar de xarxa, activar i desactivar el senyal mòbil i dur a terme accions semblants sense notificar-t\'ho."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"veure l\'estat i la identitat del telèfon"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet que l\'aplicació accedeixi a les funcions de telèfon del dispositiu. Aquest permís permet que l\'aplicació determini el número de telèfon i els identificadors del dispositiu, si hi ha una trucada activa i el número remot connectat amb una trucada."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evita que la tauleta entri en mode d\'inactivitat"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir que el telèfon entri en mode de repòs"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet que l\'aplicació impedeixi que la tauleta entri en repòs."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permet que l\'aplicació impedeixi que el telèfon entri en repòs."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmissió d\'infraroigs"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permet que l\'aplicació utilitzi el transmissor d\'infraroigs de la tauleta."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permet que l\'aplicació utilitzi el transmissor d\'infraroigs del telèfon."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"activa o desactiva la tauleta"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"engegar o apagar el telèfon"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permet que l\'aplicació encengui i apagui la tauleta."</string>
@@ -593,14 +603,14 @@
<string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Permet que l\'aplicació rebi paquets enviats a tots els dispositius d\'una xarxa Wi-Fi mitjançant les adreces multidifusió, no només a la teva tauleta. Fa servir més energia que el mode que no és multidifusió."</string>
<string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Permet que l\'aplicació rebi paquets enviats a tots els dispositius d\'una xarxa Wi-Fi mitjançant les adreces multidifusió, no només al teu telèfon. Fa servir més energia que el mode que no és multidifusió."</string>
<string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"accés a la configuració de Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permet que l\'aplicació configuri la tauleta Bluetooth local i que cerqui i sincronitzi dispositius remots."</string>
- <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permet que l\'aplicació configuri el telèfon Bluetooth local i que cerqui i sincronitzi dispositius remots."</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permet que l\'aplicació configuri la tauleta Bluetooth local i que detecti i emparelli dispositius remots."</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permet que l\'aplicació configuri el telèfon Bluetooth local i que detecti i emparelli dispositius remots."</string>
<string name="permlab_accessWimaxState" msgid="4195907010610205703">"connecta i desconnecta de WiMAX"</string>
<string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Permet que l\'aplicació determini si WiMAX està activat i que vegi la informació sobre totes les xarxes WiMAX que estan connectades."</string>
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Canvia l\'estat de WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permet que l\'aplicació connecti i desconnecti la tauleta de les xarxes WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permet que l\'aplicació connecti i desconnecti el telèfon de les xarxes WiMAX."</string>
- <string name="permlab_bluetooth" msgid="6127769336339276828">"sincronització amb dispositius Bluetooth"</string>
+ <string name="permlab_bluetooth" msgid="6127769336339276828">"emparella amb dispositius Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permet que l\'aplicació visualitzi la configuració de Bluetooth de la tauleta i que estableixi i accepti connexions amb dispositius sincronitzats."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permet que una aplicació visualitzi la configuració de Bluetooth del telèfon i que estableixi i accepti connexions amb els dispositius sincronitzats."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"controla Near Field Communication (NFC)"</string>
@@ -734,7 +744,7 @@
<string name="phoneTypeIsdn" msgid="8022453193171370337">"XDSI"</string>
<string name="phoneTypeMain" msgid="6766137010628326916">"Principal"</string>
<string name="phoneTypeOtherFax" msgid="8587657145072446565">"Altres faxos"</string>
- <string name="phoneTypeRadio" msgid="4093738079908667513">"Ràdio"</string>
+ <string name="phoneTypeRadio" msgid="4093738079908667513">"Senyal mòbil"</string>
<string name="phoneTypeTelex" msgid="3367879952476250512">"Tèlex"</string>
<string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
<string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Mòbil de la feina"</string>
@@ -1458,7 +1468,7 @@
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tauleta"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telèfon"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Auriculars"</string>
- <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altaveus del connector"</string>
+ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altaveus de la base"</string>
<string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Àudio per Bluetooth"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index b71ff18..0bd1b2f1 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Příliš mnoho smazaných položek služby <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Úložiště tabletu je plné. Uvolněte místo smazáním některých souborů."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Paměť telefonu je plná. Uvolněte místo smazáním některých souborů."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Síť může být monitorována"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Já"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Možnosti tabletu"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Možnosti telefonu"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zabránění přepínání aplikací"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Zabrání uživateli přepnout na jinou aplikaci."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"získat informace o aktuální aplikaci"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Umožňuje držiteli získat soukromé informace o aktuální aplikaci a službách na popředí obrazovky."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Umožňuje držiteli získat soukromé informace o aktuální aplikaci na popředí obrazovky."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"sledování a řízení spouštění všech aplikací"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Umožňuje aplikaci sledovat a řídit spouštění činností systémem. Škodlivé aplikace mohou systém zcela ovládnout. Toto oprávnění je požadováno pouze pro účely vývoje, nikdy pro běžné použití."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"odeslání vysílání o odstranění balíčku"</string>
@@ -328,7 +333,7 @@
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"vynucení zavření aplikací na pozadí"</string>
<string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"Umožňuje aplikaci ovládat, zda budou činnosti po přechodu na pozadí vždy ukončeny. Běžné aplikace toto oprávnění nikdy nepožadují."</string>
<string name="permlab_batteryStats" msgid="2789610673514103364">"čtení statistických údajů o baterii"</string>
- <string name="permdesc_batteryStats" msgid="5897346582882915114">"Umožňuje aplikaci číst aktuální podrobné údaje o využití baterie. Aplikace to může využít k získání podrobných informací o tom, které aplikace používáte."</string>
+ <string name="permdesc_batteryStats" msgid="5897346582882915114">"Umožňuje aplikaci číst aktuální podrobné údaje o využívání baterie. Aplikace to může využít k získání podrobných informací o tom, které aplikace používáte."</string>
<string name="permlab_updateBatteryStats" msgid="3719689764536379557">"změna statistických údajů o baterii"</string>
<string name="permdesc_updateBatteryStats" msgid="6862817857178025002">"Umožňuje aplikaci upravit shromážděné statistiky o baterii. Toto oprávnění není určeno pro běžné aplikace."</string>
<string name="permlab_getAppOpsStats" msgid="1508779687436585744">"načtení statistik operací aplikace"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Povoluje aplikaci ovládat základní funkce displejů přes Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"zachytit výstup zvuku"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Umožní aplikaci zachytit a přesměrovat výstup zvuku."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detekce klíčových slov"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Umožní aplikaci zaznamenávat zvuk za účelem detekce klíčových slov. Záznam může probíhat na pozadí a nebrání jinému zaznamenávání zvuku (například videokamerou)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"zachytit výstup videa"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Umožní aplikaci zachytit a přesměrovat výstup videa."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"zachytit zabezpečený výstup videa"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"bránění přechodu telefonu do režimu spánku"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Umožňuje aplikaci zabránit přechodu tabletu do režimu spánku."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Umožňuje aplikaci zabránit přechodu telefonu do režimu spánku."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infračervený přenos"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Umožňuje aplikaci využívat infračervený vysílač tabletu."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Umožňuje aplikaci využívat infračervený vysílač telefonu."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"zapnutí či vypnutí tabletu"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"zapnutí či vypnutí telefonu"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Umožňuje aplikaci zapnout či vypnout tablet."</string>
@@ -573,7 +583,7 @@
<string name="permdesc_manageAccounts" msgid="8698295625488292506">"Umožňuje aplikaci provádět operace, jako je přidávání nebo odebírání účtů nebo mazání jejich hesel."</string>
<string name="permlab_useCredentials" msgid="235481396163877642">"používání účtů v zařízení"</string>
<string name="permdesc_useCredentials" msgid="7984227147403346422">"Umožňuje aplikaci požadovat ověřovací tokeny."</string>
- <string name="permlab_accessNetworkState" msgid="4951027964348974773">"zobrazení síťových připojení"</string>
+ <string name="permlab_accessNetworkState" msgid="4951027964348974773">"zobrazování síťových připojení"</string>
<string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Umožňuje aplikaci zobrazit informace o síťových připojeních, například o tom, které sítě jsou k dispozici a které jsou připojené."</string>
<string name="permlab_createNetworkSockets" msgid="8018758136404323658">"úplný přístup k síti"</string>
<string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Umožňuje aplikaci vytvářet síťové sokety a používat vlastní síťové protokoly. K odesílání údajů na internet toto oprávnění není nutné, protože údaje lze na internet odesílat prostřednictvím prohlížečů a dalších aplikací."</string>
@@ -1582,6 +1592,6 @@
<item quantity="other" msgid="4730868920742952817">"Zkuste to znovu za <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Zkuste to znovu později"</string>
- <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Panel zobrazíte přejetím kraje obr."</string>
+ <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Panel zobrazíte přejetím přes kraje obrazovky"</string>
<string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Systémový panel zobrazíte přejetím přes okraj obrazovky"</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 7536252..3a9da60 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"For mange <xliff:g id="CONTENT_TYPE">%s</xliff:g> sletninger"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Din tablets lager er fuldt. Slet nogle filer for at frigøre plads."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonens lager er fuldt. Slet nogle filer for at frigøre plads."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netværket kan være overvåget"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Af en ukendt tredjepart"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Af <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Mig"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Valgmuligheder for tabletcomputeren"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefonvalgmuligheder"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"undgå programskift"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Forhindrer brugeren i at skifte til en anden app."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"få aktuelle app-oplysninger"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Tillader, at brugeren henter private oplysninger om den aktuelle applikation og de aktuelle tjenester i forgrunden af skærmen."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Tillader, at brugeren henter private oplysninger om den aktuelle applikation i forgrunden på skærmen."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"overvåge og kontrollere åbning af alle apps"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Tillader, at appen kan overvåge og kontrollere, hvordan systemet starter aktiviteter. Ondsindede apps kan fuldstændig kompromittere systemet. Denne tilladelse er kun nødvendig til udvikling, aldrig til normal brug."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"send udsendelse om fjernet pakke"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Tillader, at appen kontrollerer Wi-Fi-skærmfunktioner på lavt niveau."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"opfang et lydoutput"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Tillader, at appen opfanger og omdirigerer et lydoutput."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Registrering af kommandoord"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Tillader, at appen optager lyd til registrering af kommandoord. Optagelsen kan ske i baggrunden, men forhindrer ikke andre lydoptagelser (f.eks. videokamera)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"opfang et videooutput"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Tillader, at appen opfanger og omdirigerer et videooutput."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"opfang et sikkert videooutput"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"afholde telefonen fra at gå i dvale"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Tillader, at appen kan forhindre tabletten i at gå i dvale."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Tillader, at appen kan forhindre, at telefonen går i dvale."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"send infrarød"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Tillader, at appen bruger tablettens infrarøde sender."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Tillader, at appen bruger telefonens infrarøde sender."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"tænd eller sluk for tabletcomputeren"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"tænd eller sluk for telefonen"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Tillader, at appen kan slukke og tænde din tablet."</string>
@@ -573,7 +581,7 @@
<string name="permdesc_manageAccounts" msgid="8698295625488292506">"Tillader, at appen kan foretage handlinger såsom at tilføje og fjerne konti og slette adgangskoden."</string>
<string name="permlab_useCredentials" msgid="235481396163877642">"bruge konti på enheden"</string>
<string name="permdesc_useCredentials" msgid="7984227147403346422">"Tillader, at appen kan anmode om godkendelsestokens."</string>
- <string name="permlab_accessNetworkState" msgid="4951027964348974773">"få vist netværksforbindelser"</string>
+ <string name="permlab_accessNetworkState" msgid="4951027964348974773">"se netværksforbindelser"</string>
<string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Tillader, at appen kan læse oplysninger om netværksforbindelser, f.eks. eksisterende og forbundne netværk."</string>
<string name="permlab_createNetworkSockets" msgid="8018758136404323658">"fuld netværksadgang"</string>
<string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Tillader, at appen kan oprette netværkssockets og bruge tilpassede netværksprotokoller. Browseren og andre applikationer indeholder midler til at sende data til internettet, så med denne tilladelse er der ingen forpligtelse til at sende data til internettet."</string>
@@ -585,7 +593,7 @@
<string name="permdesc_changeTetherState" msgid="1524441344412319780">"Tillader, at appen kan ændre tilstand for en netværksforbindelse via netdeling."</string>
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"skift brugerindstilling for baggrundsdata"</string>
<string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Tillader, at appen kan ændre indstillingen for brug af baggrundsdata."</string>
- <string name="permlab_accessWifiState" msgid="5202012949247040011">"få vist Wi-Fi-forbindelser"</string>
+ <string name="permlab_accessWifiState" msgid="5202012949247040011">"se Wi-Fi-forbindelser"</string>
<string name="permdesc_accessWifiState" msgid="5002798077387803726">"Tillader, at appen kan læse oplysninger om Wi-Fi-netværk, f.eks. hvorvidt Wi-Fi er aktiveret og navnet på forbundne Wi-Fi-enheder."</string>
<string name="permlab_changeWifiState" msgid="6550641188749128035">"oprette og afbryde Wi-Fi-forbindelse"</string>
<string name="permdesc_changeWifiState" msgid="7137950297386127533">"Tillader, at appen kan oprette og afbryde forbindelsen fra Wi-Fi-adgangspunkter og foretage ændringer i enhedskonfigurationen for Wi-Fi-netværk."</string>
@@ -690,13 +698,13 @@
<string-array name="emailAddressTypes">
<item msgid="8073994352956129127">"Hjem"</item>
<item msgid="7084237356602625604">"Arbejde"</item>
- <item msgid="1112044410659011023">"Andre"</item>
+ <item msgid="1112044410659011023">"Andet"</item>
<item msgid="2374913952870110618">"Tilpasset"</item>
</string-array>
<string-array name="postalAddressTypes">
<item msgid="6880257626740047286">"Hjem"</item>
<item msgid="5629153956045109251">"Arbejde"</item>
- <item msgid="4966604264500343469">"Andre"</item>
+ <item msgid="4966604264500343469">"Andet"</item>
<item msgid="4932682847595299369">"Tilpasset"</item>
</string-array>
<string-array name="imAddressTypes">
@@ -707,7 +715,7 @@
</string-array>
<string-array name="organizationTypes">
<item msgid="7546335612189115615">"Arbejde"</item>
- <item msgid="4378074129049520373">"Andre"</item>
+ <item msgid="4378074129049520373">"Andet"</item>
<item msgid="3455047468583965104">"Tilpasset"</item>
</string-array>
<string-array name="imProtocols">
@@ -727,7 +735,7 @@
<string name="phoneTypeFaxWork" msgid="3517792160008890912">"Arbejdsfax"</string>
<string name="phoneTypeFaxHome" msgid="2067265972322971467">"Hjemmefax"</string>
<string name="phoneTypePager" msgid="7582359955394921732">"Personsøger"</string>
- <string name="phoneTypeOther" msgid="1544425847868765990">"Andre"</string>
+ <string name="phoneTypeOther" msgid="1544425847868765990">"Andet"</string>
<string name="phoneTypeCallback" msgid="2712175203065678206">"Tilbagekald"</string>
<string name="phoneTypeCar" msgid="8738360689616716982">"Bil"</string>
<string name="phoneTypeCompanyMain" msgid="540434356461478916">"Virksomhed (hovednummer)"</string>
@@ -744,20 +752,20 @@
<string name="eventTypeCustom" msgid="7837586198458073404">"Tilpasset"</string>
<string name="eventTypeBirthday" msgid="2813379844211390740">"Fødselsdato"</string>
<string name="eventTypeAnniversary" msgid="3876779744518284000">"Årsdag"</string>
- <string name="eventTypeOther" msgid="7388178939010143077">"Andre"</string>
+ <string name="eventTypeOther" msgid="7388178939010143077">"Andet"</string>
<string name="emailTypeCustom" msgid="8525960257804213846">"Tilpasset"</string>
<string name="emailTypeHome" msgid="449227236140433919">"Hjem"</string>
<string name="emailTypeWork" msgid="3548058059601149973">"Arbejde"</string>
- <string name="emailTypeOther" msgid="2923008695272639549">"Andre"</string>
+ <string name="emailTypeOther" msgid="2923008695272639549">"Andet"</string>
<string name="emailTypeMobile" msgid="119919005321166205">"Mobil"</string>
<string name="postalTypeCustom" msgid="8903206903060479902">"Tilpasset"</string>
<string name="postalTypeHome" msgid="8165756977184483097">"Hjem"</string>
<string name="postalTypeWork" msgid="5268172772387694495">"Arbejde"</string>
- <string name="postalTypeOther" msgid="2726111966623584341">"Andre"</string>
+ <string name="postalTypeOther" msgid="2726111966623584341">"Andet"</string>
<string name="imTypeCustom" msgid="2074028755527826046">"Tilpasset"</string>
<string name="imTypeHome" msgid="6241181032954263892">"Hjem"</string>
<string name="imTypeWork" msgid="1371489290242433090">"Arbejde"</string>
- <string name="imTypeOther" msgid="5377007495735915478">"Andre"</string>
+ <string name="imTypeOther" msgid="5377007495735915478">"Andet"</string>
<string name="imProtocolCustom" msgid="6919453836618749992">"Tilpasset"</string>
<string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
<string name="imProtocolMsn" msgid="144556545420769442">"Windows Live"</string>
@@ -769,7 +777,7 @@
<string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
<string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
<string name="orgTypeWork" msgid="29268870505363872">"Arbejde"</string>
- <string name="orgTypeOther" msgid="3951781131570124082">"Andre"</string>
+ <string name="orgTypeOther" msgid="3951781131570124082">"Andet"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"Tilpasset"</string>
<string name="relationTypeCustom" msgid="3542403679827297300">"Tilpasset"</string>
<string name="relationTypeAssistant" msgid="6274334825195379076">"Assistent"</string>
@@ -789,7 +797,7 @@
<string name="sipAddressTypeCustom" msgid="2473580593111590945">"Tilpasset"</string>
<string name="sipAddressTypeHome" msgid="6093598181069359295">"Hjem"</string>
<string name="sipAddressTypeWork" msgid="6920725730797099047">"Arbejde"</string>
- <string name="sipAddressTypeOther" msgid="4408436162950119849">"Andre"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Andet"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Indtast pinkode"</string>
<string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Indtast PUK- og pinkode"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK-kode"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 2185a42..8853b37 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zu viele <xliff:g id="CONTENT_TYPE">%s</xliff:g> gelöscht."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Der Tablet-Speicher ist voll. Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Der Handyspeicher ist voll! Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Das Netzwerk wird möglicherweise überwacht."</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Von einem unbekannten Dritten"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Von <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Eigene"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tablet-Optionen"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefonoptionen"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"App-Wechsel verhindern"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Hindert den Nutzer daran, zu einer anderen App zu wechseln"</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"Informationen zur aktuellen App abrufen"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Ermöglicht es dem Inhaber, private Informationen zur aktuellen App und zu aktuellen Diensten im Vordergrund des Bildschirms abzurufen"</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Ermöglicht es dem Inhaber, private Informationen zur aktuellen App im Vordergrund des Bildschirms abzurufen"</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"Start von Apps überwachen und steuern"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Ermöglicht der App, den Start von Systemaktivitäten zu überwachen und zu steuern. Schädliche Apps können so das gesamte System beeinträchtigen. Diese Berechtigung wird nur zu Entwicklungszwecken und nie für die normale Nutzung benötigt."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"Broadcast ohne Paket senden"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Erlaubt der App, untergeordnete Funktionen von WLAN-Anzeigen zu steuern"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"Audioausgabe erfassen"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Ermöglicht der App die Erfassung und Weiterleitung von Audioausgaben"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword-Erkennung"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"App darf Audio für die Hotword-Erkennung erfassen. Dies kann im Hintergrund durchgeführt werden und beeinflusst die Erfassung von Audio über andere Funktionen (z. B. Camcorder) nicht."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"Videoausgabe erfassen"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Ermöglicht der App die Erfassung und Weiterleitung von Videoausgaben"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"Sichere Videoausgabe erfassen"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Ruhezustand deaktivieren"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ermöglicht der App, den Ruhezustand des Tablets zu deaktivieren"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Ermöglicht der App, den Ruhezustand des Telefons zu deaktivieren"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"Infrarotübertragung"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"App darf das System zur Infrarotübertragung des Tablets verwenden."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"App darf das System zur Infrarotübertragung des Telefons verwenden."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Tablet ein- oder ausschalten"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"Gerät ein- oder ausschalten"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Ermöglicht der App, das Tablet ein- oder auszuschalten"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 9fb21e6..d0cd8da 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Πάρα πολλές <xliff:g id="CONTENT_TYPE">%s</xliff:g> διαγραφές."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Ο αποθηκευτικός χώρος του tablet είναι πλήρης. Διαγράψτε μερικά αρχεία για να δημιουργήσετε ελεύθερο χώρο."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Ο αποθηκευτικός χώρος του τηλεφώνου είναι πλήρης. Διαγράψτε μερικά αρχεία για να δημιουργήσετε ελεύθερο χώρο."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Από ένα άγνωστο τρίτο μέρος"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Από <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Για εμένα"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Επιλογές tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Επιλογές τηλεφώνου"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"αποτροπή εναλλαγών εφαρμογών"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Δεν επιτρέπει στο χρήστη να μεταβεί σε άλλη εφαρμογή."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"λήψη πληροφοριών σχετικά με την τρέχουσα εφαρμογή"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Επιτρέπει στον κάτοχό του να ανακτήσει ιδιωτικές πληροφορίες σχετικά με την τρέχουσα εφαρμογή και τις υπηρεσίες στο προσκήνιο της οθόνης."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Δίνει στον κάτοχο τη δυνατότητα ανάκτησης απόρρητων πληροφοριών σχετικά με την τρέχουσα εφαρμογή στο προσκήνιο της οθόνης."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"παρακολούθηση και έλεγχος όλων των εκκινήσεων εφαρμογών"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Επιτρέπει στην εφαρμογή να παρακολουθεί και να ελέγχει τον τρόπο με τον οποίο το σύστημα εκκινεί δραστηριότητες. Τυχόν κακόβουλες εφαρμογές ενδέχεται να θέσουν σε κίνδυνο το σύστημα. Αυτή η άδεια είναι απαραίτητη μόνο για σκοπούς ανάπτυξης και ποτέ για συνήθη χρήση."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"αποστολή εκπομπής χωρίς πακέτο"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Επιτρέπει στην εφαρμογή τον έλεγχο των λειτουργιών χαμηλού επιπέδου των οθονών Wifi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"έγγραφή εξόδου ήχου"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Δίνει στην εφαρμογή τη δυνατότητα εγγραφής και ανακατεύθυνσης εξόδου ήχου."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Ανίχνευση ενεργών λέξεων"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Επιτρέπει στην εφαρμογή την εγγραφή ήχου για ανίχνευση ενεργών λέξεων. Η εγγραφή μπορεί να πραγματοποιηθεί στο παρασκήνιο, αλλά δεν εμποδίζει την εγγραφή ήχου από άλλες πηγές (π.χ. βιντεοκάμερα)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"έγγραφή εξόδου βίντεο"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Δίνει στην εφαρμογή τη δυνατότητα εγγραφής και ανακατεύθυνσης εξόδου βίντεο."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"έγγραφή ασφαλούς εξόδου βίντεο"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"παρεμπόδιση μετάβασης του τηλεφώνου σε κατάσταση αδράνειας"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του tablet σε κατάσταση αδράνειας."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του τηλεφώνου σε κατάσταση αδράνειας."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"μετάδοση υπερύθρων"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τον πομπό υπερύθρων του tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τον πομπό υπερύθρων του τηλεφώνου."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"ενεργοποίηση και απενεργοποίηση tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"ενεργοποίηση και απενεργοποίηση τηλεφώνου"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Επιτρέπει στην εφαρμογή να ενεργοποιήσει ή να απενεργοποιήσει το tablet."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 936062b..d5ed353 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Too many <xliff:g id="CONTENT_TYPE">%s</xliff:g> deletions."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet storage is full. Delete some files to free space."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Phone storage is full. Delete some files to free space."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Network may be monitored"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"By an unknown third party"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"By <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Me"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tablet options"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Phone options"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"prevent app switches"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Prevents the user from switching to another app."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"get current app info"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Allows the holder to retrieve private information about the current application and services in the foreground of the screen."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Allows the holder to retrieve private information about the current application in the foreground of the screen."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitor and control all app launching"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Allows the app to monitor and control how the system launches activities. Malicious apps may completely compromise the system. This permission is only needed for development, never for normal use."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"send package removed broadcast"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Allows the app to control low-level features of Wi-Fi displays."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capture audio output"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Allows the app to capture and redirect audio output."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword detection"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Allows the app to capture audio for Hotword detection. The capture can happen in the background but does not prevent other audio capture (e.g. Camcorder)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capture video output"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Allows the app to capture and redirect video output."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capture secure video output"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"prevent phone from sleeping"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Allows the app to prevent the tablet from going to sleep."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Allows the app to prevent the phone from going to sleep."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmit infrared"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Allows the app to use the tablet\'s infrared transmitter."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Allows the app to use the phone\'s infrared transmitter."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"turn tablet on or off"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"turn phone on or off"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Allows the app to turn the tablet on or off."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 936062b..d5ed353 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Too many <xliff:g id="CONTENT_TYPE">%s</xliff:g> deletions."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet storage is full. Delete some files to free space."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Phone storage is full. Delete some files to free space."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Network may be monitored"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"By an unknown third party"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"By <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Me"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tablet options"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Phone options"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"prevent app switches"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Prevents the user from switching to another app."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"get current app info"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Allows the holder to retrieve private information about the current application and services in the foreground of the screen."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Allows the holder to retrieve private information about the current application in the foreground of the screen."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitor and control all app launching"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Allows the app to monitor and control how the system launches activities. Malicious apps may completely compromise the system. This permission is only needed for development, never for normal use."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"send package removed broadcast"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Allows the app to control low-level features of Wi-Fi displays."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capture audio output"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Allows the app to capture and redirect audio output."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword detection"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Allows the app to capture audio for Hotword detection. The capture can happen in the background but does not prevent other audio capture (e.g. Camcorder)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capture video output"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Allows the app to capture and redirect video output."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capture secure video output"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"prevent phone from sleeping"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Allows the app to prevent the tablet from going to sleep."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Allows the app to prevent the phone from going to sleep."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmit infrared"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Allows the app to use the tablet\'s infrared transmitter."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Allows the app to use the phone\'s infrared transmitter."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"turn tablet on or off"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"turn phone on or off"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Allows the app to turn the tablet on or off."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index b91438d..9222e70 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Se ha agotado el espacio de almacenamiento de la tablet. Elimina algunos archivos para liberar espacio."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Se ha agotado el espacio de almacenamiento del dispositivo. Elimina algunos archivos para liberar espacio."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Es posible que la red esté supervisada."</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por un tercero desconocido"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Yo"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opciones de tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opciones de dispositivo"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedir conmutadores de aplicación"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Evita que el usuario cambie a otra aplicación."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"obtener información de aplicación actual"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Permite que el titular recupere información privada sobre los servicios y la aplicación actuales en el primer plano de la pantalla."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permite que el titular recupere información privada sobre la aplicación actual en el primer plano de la pantalla."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"supervisar y controlar la ejecución de todas las aplicaciones"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permite que la aplicación supervise y controle la manera en la que el sistema inicia actividades. Las aplicaciones maliciosas pueden comprometer el sistema por completo. Este permiso es necesario solo para el desarrollo, nunca para el uso habitual."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar emisión de paquete eliminado"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que la aplicación controle funciones de bajo nivel de las pantallas Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"Capturar salida de audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite que la aplicación capture y redirija la salida de audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detectar palabras activas"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permite que la aplicación capture audio para la detección de palabras activas. La captura puede ocurrir en segundo plano, pero no impide otras capturas de audio (por ejemplo, de la videocámara)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"Capturar salida de video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite que la aplicación capture y redirija la salida de video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"Capturar salida de video segura"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar que el dispositivo entre en estado de inactividad"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que la aplicación evite que la tablet entre en estado de inactividad."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permite que la aplicación evite que el dispositivo entre en estado de inactividad."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"Transmitir por infrarrojos"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permite que la aplicación utilice el transmisor infrarrojo de la tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permite que la aplicación utilice el transmisor infrarrojo del teléfono."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"apagar o encender el tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"apagar o encender el dispositivo"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permite que la aplicación encienda o apague la tablet."</string>
@@ -812,7 +820,7 @@
<string name="lockscreen_password_wrong" msgid="5737815393253165301">"Volver a intentarlo"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se superó el máximo de intentos permitido para el desbloqueo facial del dispositivo."</string>
<string name="lockscreen_plugged_in" msgid="8057762828355572315">"Cargando <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="lockscreen_charged" msgid="321635745684060624">"Cargado"</string>
+ <string name="lockscreen_charged" msgid="321635745684060624">"Cargada"</string>
<string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta tu cargador."</string>
<string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Sin tarjeta SIM"</string>
@@ -1581,7 +1589,7 @@
<item quantity="one" msgid="311050995198548675">"Intentar en 1 s"</item>
<item quantity="other" msgid="4730868920742952817">"Intentar en <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
- <string name="restr_pin_try_later" msgid="973144472490532377">"Volver a intentar más tarde"</string>
+ <string name="restr_pin_try_later" msgid="973144472490532377">"Vuelve a intentar más tarde."</string>
<string name="transient_navigation_confirmation" msgid="4907844043611123426">"Desliza el borde para ver la barra."</string>
<string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Desliza el dedo desde el borde de la pantalla para mostrar la barra del sistema."</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 620410e..6191dc1 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Se ha agotado el espacio de almacenamiento del tablet. Elimina algunos archivos para liberar espacio."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Se ha agotado el espacio de almacenamiento del teléfono. Elimina algunos archivos para liberar espacio."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Es posible que la red esté supervisada"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"De un tercero desconocido"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"De <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Yo"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opciones del tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opciones del teléfono"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"evitar cambios de aplicación"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Evita que el usuario cambie a otra aplicación."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"obtener información de la aplicación actual"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Permite recuperar información privada sobre los servicios y la aplicación actuales en el primer plano de la pantalla."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permite que el titular recupere información privada sobre la aplicación actual en el primer plano de la pantalla."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"supervisar y controlar la ejecución de todas las aplicaciones"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permite que la aplicación supervise y controle la ejecución de las actividades del sistema. Las aplicaciones malintencionadas pueden vulnerar la seguridad del sistema. Este permiso es necesario únicamente para tareas de desarrollo, nunca para el uso habitual."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar emisión eliminada de paquete"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que la aplicación controle funciones de bajo nivel de pantallas Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capturar salida de audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite que la aplicación capture y redirija la salida de audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detectar palabras activas"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permite que la aplicación grabe audio para detectar palabras activas. La grabación se puede realizar en segundo plano pero no impide que se grabe otro tipo de audio (p.ej. la videocámara)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capturar salida de vídeo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite que la aplicación capture y redirija la salida de vídeo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capturar salida de vídeo segura"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir que el teléfono entre en modo de suspensión"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que la aplicación impida que el tablet entre en modo de suspensión."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permite que la aplicación impida que el teléfono entre en modo de suspensión."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmitir infrarrojos"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permite que la aplicación utilice el transmisor de infrarrojos del tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permite que la aplicación utilice el transmisor de infrarrojos del teléfono."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"encender o apagar el tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"encender o apagar el teléfono"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permite que la aplicación encienda o apague el tablet."</string>
@@ -778,7 +786,7 @@
<string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Pareja de hecho"</string>
<string name="relationTypeFather" msgid="5228034687082050725">"Padre"</string>
<string name="relationTypeFriend" msgid="7313106762483391262">"Amigo/a"</string>
- <string name="relationTypeManager" msgid="6365677861610137895">"Manager"</string>
+ <string name="relationTypeManager" msgid="6365677861610137895">"Jefe"</string>
<string name="relationTypeMother" msgid="4578571352962758304">"Madre"</string>
<string name="relationTypeParent" msgid="4755635567562925226">"Padre/madre"</string>
<string name="relationTypePartner" msgid="7266490285120262781">"Pareja"</string>
@@ -812,7 +820,7 @@
<string name="lockscreen_password_wrong" msgid="5737815393253165301">"Vuelve a intentarlo"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se ha superado el número máximo de intentos de desbloqueo facial."</string>
<string name="lockscreen_plugged_in" msgid="8057762828355572315">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="321635745684060624">"Cargado"</string>
+ <string name="lockscreen_charged" msgid="321635745684060624">"Cargada"</string>
<string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta el cargador"</string>
<string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Falta la tarjeta SIM."</string>
@@ -1568,9 +1576,9 @@
<string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelado"</string>
<string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Error al escribir contenido"</string>
<string name="reason_unknown" msgid="6048913880184628119">"desconocido"</string>
- <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"Introducir PIN de administrador"</string>
+ <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"Introduce el PIN del administrador"</string>
<string name="restr_pin_enter_pin" msgid="3395953421368476103">"Introducir PIN"</string>
- <string name="restr_pin_incorrect" msgid="8571512003955077924">"Incorrecta"</string>
+ <string name="restr_pin_incorrect" msgid="8571512003955077924">"Incorrecto"</string>
<string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN actual"</string>
<string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"PIN nuevo"</string>
<string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Confirma tu nuevo PIN"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index a74334d..8e93ec1 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Liiga palju üksuse <xliff:g id="CONTENT_TYPE">%s</xliff:g> kustutusi."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tahvelarvuti mäluruum on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonimälu on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Võrku võidakse jälgida"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Tundmatu kolmas osapool:"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Domeen: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Mina"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tahvelarvuti valikud"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefonivalikud"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"väldi rakenduste ümberlülitamist"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Takistab kasutaja lülitumist teisele rakendusele."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"aktiivse rakenduse teabe hankimine"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Lubab õiguse omanikul hankida privaatset teavet ekraani esiplaanil oleva aktiivse rakenduse ja teenuste kohta."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Lubab õiguste saajal hankida privaatset teavet ekraanil esiplaanil oleva aktiivse rakenduse kohta."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"Kõigi rakenduste käivitumise jälgimine ja juhtimine"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Võimaldab rakendusel jälgida ja juhtida, kuidas süsteem tegevusi käivitab. Pahatahtlikud rakendused võivad süsteemi täielikult rikkuda. Seda õigust on vaja ainult arenduseks, mitte tavakasutuse korral."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"saada paketist eemaldatud saade"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Lubab rakendusel juhtida WiFi-ekraanide madala taseme funktsioone."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"heliväljundi jäädvustamine"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Lubab rakendusel jäädvustada ja ümber suunata heliväljundit."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Otsetee sõna tuvastamine"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Lubab rakendusel jäädvustada heli otsetee sõna tuvastamiseks. Jäädvustamine võib toimuda taustal, kuid see ei takista muud heli jäädvustamist (nt videokaameraga)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"videoväljundi jäädvustamine"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Lubab rakendusel jäädvustada ja ümber suunata videoväljundit."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"kaitstud videoväljundi jäädvustamine"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"väldi telefoni uinumist"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Võimaldab rakendusel vältida tahvelarvuti uinumist."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Võimaldab rakendusel vältida telefoni uinumist."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infrapunaedastus"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Lubab rakendusel kasutada tahvelarvuti infrapunasaatjat."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Lubab rakendusel kasutada telefoni infrapunasaatjat."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"lülita tahvelarvuti sisse või välja"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"lülita telefon sisse või välja"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Võimaldab rakendusel tahvelarvutit sisse või välja lülitada."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 0193475..74c904f 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"تعداد موارد حذف شده <xliff:g id="CONTENT_TYPE">%s</xliff:g> بسیار زیاد است."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"حافظه رایانهٔ لوحی پر است! برخی از فایلها را حذف کنید تا فضا آزاد شود."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"حافظه تلفن پر است. بعضی از فایلها را حذف کنید تا فضا آزاد شود."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ممکن است شبکه نظارت شده باشد"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"من"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"گزینههای رایانهٔ لوحی"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"گزینههای تلفن"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ممانعت از جابجایی برنامه"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"اجازه نمیدهد کاربر به برنامه دیگری برود."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"دریافت اطلاعات برنامه فعلی"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"به دارنده اجازه میدهد اطلاعات خصوصی مربوط به خدمات و برنامه فعلی را در پیشزمینه صفحه بازیابی کند."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"به دارنده اجازه میدهد اطلاعات خصوصی مربوط به برنامه فعلی را در پیش زمینه صفحه بازیابی کند."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"نظارت و کنترل راهاندازی همه برنامه"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"به برنامه اجازه میدهد تا نحوه راهاندازی فعالیتهای سیستم را کنترل کند. برنامههای مخرب میتوانند کاملا با سیستم سازگار شوند. این مجوز فقط برای توسعه نیاز است و برای استفاده عادی نیست."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"ارسال پخش بسته حذف شده"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"به برنامه اجازه میدهد که ویژگیهای سطح پایین صفحههای نمایش Wi‑Fi را کنترل کند."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ضبط خروجی صدا"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"به برنامه امکان میدهد خروجی صدا را ضبط و هدایت کند."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"تشخیص کلیدگفته"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"به برنامه اجازه میدهد تا صدا را برای تشخیص کلیدگفته ضبط کند. ضبط صدا میتواند در پسزمینه رخ دهد اما از ضبط صداهای دیگر (مثلاً دوربین فیلمبرداری) جلوگیری نمیکند."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"ضبط خروجی ویدیو"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"به برنامه امکان میدهد خروجی ویدیو را ضبط و هدایت کند."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ضبط خروجی ویدیوی ایمن"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ممانعت از به خواب رفتن تلفن"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"به برنامه اجازه میدهد تا از غیرفعال شدن رایانهٔ لوحی جلوگیری کند."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"به برنامه اجازه میدهد تا از غیرفعال شدن تلفن جلوگیری کند."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"ارسال مادون قرمز"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"به برنامه اجازه میدهد تا از فرستنده مادون قرمز رایانه لوحی استفاده کند."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"به برنامه اجازه میدهد تا از فرستنده مادون قرمز تلفن استفاده کند."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"روشن/خاموش کردن رایانهٔ لوحی"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"روشن/خاموش کردن تلفن"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"به برنامه اجازه میدهد رایانهٔ لوحی را روشن یا خاموش کند."</string>
@@ -600,7 +610,7 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"تغییر وضعیت WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"به برنامه امکان میدهد رایانهٔ لوحی را به شبکههای وایمکس متصل کرده یا اتصال آن را از این شبکهها قطع کند."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"به برنامه امکان میدهد تا تلفن را به شبکههای وایمکس متصل کرده یا اتصال آنرا از این شبکهها قطع کند."</string>
- <string name="permlab_bluetooth" msgid="6127769336339276828">"مرتبط سازی با دستگاههای بلوتوث"</string>
+ <string name="permlab_bluetooth" msgid="6127769336339276828">"جفت کردن با دستگاههای بلوتوث"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"به برنامه اجازه میدهد تا پیکربندی بلوتوث در رایانهٔ لوحی را مشاهده کند و اتصال با دستگاههای مرتبط را برقرار کرده و بپذیرد."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"به برنامه اجازه میدهد تا پیکربندی بلوتوث در تلفن را مشاهده کند، و اتصالات دستگاههای مرتبط را برقرار کرده و بپذیرد."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"کنترل ارتباط راه نزدیک"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index dbd77e0..9c05971 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Liikaa <xliff:g id="CONTENT_TYPE">%s</xliff:g>-poistoja."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet-laitteen tallennustila on täynnä. Vapauta tilaa poistamalla tiedostoja."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Puhelimen tallennustila on täynnä. Vapauta tilaa poistamalla tiedostoja."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Verkkoa saatetaan valvoa"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Valvoja on tuntematon kolmas osapuoli."</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Valvoja on <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>."</string>
<string name="me" msgid="6545696007631404292">"Minä"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tablet-laitteen asetukset"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Puhelimen asetukset"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"estä sovellusten vaihto"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Estää käyttäjää siirtymästä toiseen sovellukseen."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"hae nykyisen sovelluksen tiedot"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Antaa sovellukselle luvan noutaa nykyistä sovellusta ja nykyisiä palveluita koskevia yksityisiä tietoja ruudun etualalla."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Antaa sovellukselle luvan noutaa nykyistä sovellusta koskevia yksityisiä tietoja ruudun etualalla."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"kaikkien sovellusten käynnistämisen valvonta ja hallinta"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Antaa sovelluksen valvoa ja hallita sitä, miten laite käynnistää toimintoja. Haitalliset sovellukset voivat vaarantaa laitteen käytön. Tätä oikeutta tarvitaan vain kehityskäyttöön eikä koskaan tavalliseen käyttöön."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"lähetä paketeista poistettuja lähetyksiä"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Antaa sovelluksen hallita wifi-näyttöjen matalan tason ominaisuuksia."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"äänentoiston kaappaus"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Antaa sovellukselle luvan äänentoiston kaappaamiseen ja uudelleenohjaamiseen."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Toimintosanan tunnistus"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Antaa sovelluksen siepata ääntä toimintosanojen tunnistusta varten. Sieppaus voi tapahtua taustalla, mutta se ei estä muita laitteita, kuten videokameraa, käyttämästä ääntä."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"videokuvan kaappaus"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Antaa sovellukselle luvan videokuvan kaappaamiseen ja uudelleenohjaamiseen"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"suojatun videokuvan kaappaus"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"estä puhelinta menemästä virransäästötilaan"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Antaa sovelluksen estää tablet-laitetta siirtymästä virransäästötilaan."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Antaa sovelluksen estää puhelinta siirtymästä virransäästötilaan."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infrapunalähetys"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Antaa sovelluksen käyttää tablet-laitteen infrapunalähetintä."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Antaa sovelluksen käyttää puhelimen infrapunalähetintä."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"käynnistä tai sammuta tablet-laite"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"sammutta tai käynnistä puhelin"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Antaa sovelluksen sammuttaa tai käynnistää tablet-laitteen."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 47df2d0..832a34e 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"La mémoire de la tablette est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"La mémoire du téléphone est pleine. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Le réseau peut être surveillé"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Moi"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Options de la tablette"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Options du téléphone"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"empêcher les changements d\'applications"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Empêche l\'utilisateur de changer d\'application."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"récupérer des informations sur l\'application actuelle"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Permet à l\'application autorisée de récupérer des données privées à propos de l\'application exécutée au premier plan sur l\'écran."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permet à l\'application autorisée de récupérer des informations confidentielles à propos de l\'application exécutée au premier plan sur l\'écran."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"suivre et gérer le lancement de toutes les applications"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permet à l\'application de suivre et de gérer la façon dont le système lance les activités. Des applications malveillantes peuvent utiliser cette fonctionnalité pour entièrement compromettre l\'intégrité du système. Cette autorisation est uniquement destinée aux concepteurs. Elle ne doit jamais être activée dans le cadre d\'une utilisation standard."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"envoyer une diffusion sans paquet"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permet à l\'application de contrôler les fonctionnalités de base des écrans Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capturer la sortie audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Autoriser l\'application à capturer et à rediriger la sortie audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Détection de mots clés"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permet à l\'application de capturer de l\'audio pour la détection de mots clés. La capture peut s\'effectuer en arrière-plan, et n\'empêche pas les autres opérations de capture audio (par exemple, avec un caméscope)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capturer la sortie vidéo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Autoriser l\'application à capturer et à rediriger la sortie vidéo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capturer la sortie vidéo sécurisée"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"empêcher le téléphone de passer en mode veille"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet à l\'application d\'empêcher la tablette de passer en mode veille."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permet à l\'application d\'empêcher le téléphone de passer en mode veille."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmettre des signaux infrarouges"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permet à l\'application d\'utiliser l\'émetteur infrarouge de la tablette."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permet à l\'application d\'utiliser l\'émetteur infrarouge du téléphone."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"éteindre ou allumer la tablette"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"éteindre ou allumer le téléphone"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permet à l\'application d\'éteindre et d\'allumer la tablette."</string>
@@ -1578,8 +1588,8 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Les NIP ne correspondent pas. Essayez à nouveau."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"Le NIP est trop court. Il doit comporter au moins 4 chiffres."</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="311050995198548675">"Dans 1 seconde"</item>
- <item quantity="other" msgid="4730868920742952817">"Dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
+ <item quantity="one" msgid="311050995198548675">"Réessayer dans 1 s"</item>
+ <item quantity="other" msgid="4730868920742952817">"Réessayer dans <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Réessayez plus tard"</string>
<string name="transient_navigation_confirmation" msgid="4907844043611123426">"Gliss. doigt sur côté écr. aff. barre"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index d639f49..563ed73 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"La mémoire de la tablette est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"La mémoire du téléphone est pleine. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Il est possible que le réseau soit surveillé."</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Par un tiers inconnu"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Par <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Moi"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Options de la tablette"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Options du téléphone"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"empêcher les changements d\'applications"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Empêche l\'utilisateur de changer d\'application."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"Récupérer des informations sur l\'application actuelle"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Permet à l\'application autorisée de récupérer des informations confidentielles à propos de l\'application et des services exécutés au premier plan sur l\'écran."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permet à l\'application autorisée de récupérer des informations confidentielles à propos de l\'application exécutée au premier plan sur l\'écran."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"suivre et contrôler le lancement de toutes les applications"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permet à l\'application de surveiller et de contrôler la façon dont le système lance les activités. Des applications malveillantes peuvent exploiter cette fonctionnalité pour totalement compromettre le système. Cette autorisation est uniquement destinée aux développeurs. Elle ne doit jamais être activée dans le cadre d\'une utilisation standard."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"Envoyer une diffusion sans paquet"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permet à l\'application de contrôler les fonctionnalités de base des écrans Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"enregistrer les sorties audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Autoriser l\'application à enregistrer et à rediriger les sorties audio"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Détection de mot clé"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permet à l\'application de capturer du contenu audio pour détecter des mots clés. L\'enregistrement peut se produire en arrière-plan, sans désactiver les autres services de capture audio (tels que ceux d\'un caméscope)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"enregistrer les sorties vidéo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Autoriser l\'application à enregistrer et à rediriger les sorties vidéo"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"enregistrer les sorties vidéo sécurisées"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"empêcher le téléphone de passer en mode veille"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet à l\'application d\'empêcher la tablette de passer en mode veille."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permet à l\'application d\'empêcher le téléphone de passer en mode veille."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmettre des signaux infrarouges"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permet à l\'application d\'utiliser l\'émetteur infrarouge de la tablette."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permet à l\'application d\'utiliser l\'émetteur infrarouge du téléphone."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"éteindre ou allumer la tablette"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"Éteindre ou allumer le téléphone"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permet à l\'application d\'éteindre et d\'allumer la tablette."</string>
@@ -1578,8 +1586,8 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Les codes PIN ne correspondent pas. Veuillez réessayer."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"Le code PIN est trop court. Il doit comporter au moins 4 chiffres."</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="311050995198548675">"Essay. dans 1 s"</item>
- <item quantity="other" msgid="4730868920742952817">"Essay. dans <xliff:g id="COUNT">%d</xliff:g> s"</item>
+ <item quantity="one" msgid="311050995198548675">"Réessayer dans 1 s"</item>
+ <item quantity="other" msgid="4730868920742952817">"Réessayer dans <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Veuillez réessayer ultérieurement."</string>
<string name="transient_navigation_confirmation" msgid="4907844043611123426">"Faire glisser côté pour voir barre."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 9f4927b..8c18c58 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"बहुत से <xliff:g id="CONTENT_TYPE">%s</xliff:g> हटाए जाते हैं."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"टेबलेट संग्रहण भर गया है. स्थान रिक्त करने के लिए कुछ फ़ाइलें हटाएं."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"फ़ोन संग्रहण भर गया है. स्थान रिक्त करने के लिए कुछ फ़ाइलें हटाएं."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"नेटवर्क को मॉनिटर किया जा सकता है"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"किसी अज्ञात तृतीय पक्ष के द्वारा"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g> के द्वारा"</string>
<string name="me" msgid="6545696007631404292">"मैं"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"टेबलेट विकल्प"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"फ़ोन विकल्प"</string>
@@ -147,9 +150,9 @@
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"आपका फ़ोन शट डाउन हो जाएगा."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"क्या आप शट डाउन करना चाहते हैं?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"सुरक्षित मोड में रीबूट करें"</string>
- <string name="reboot_safemode_confirm" msgid="55293944502784668">"क्या आप सुरक्षित मोड में रीबूट करना चाहते हैं? इससे आपके इंस्टॉल किए हुए सभी तृतीय पक्ष एप्लिकेशन अक्षम हो जाएंगे. जब आप फिर से रीबूट करेंगे तो वे पुनर्स्थापित हो जाएंगे."</string>
+ <string name="reboot_safemode_confirm" msgid="55293944502784668">"क्या आप सुरक्षित मोड में रीबूट करना चाहते हैं? इससे आपके इंस्टॉल किए हुए सभी तृतीय पक्ष एप्स अक्षम हो जाएंगे. जब आप फिर से रीबूट करेंगे तो वे पुनर्स्थापित हो जाएंगे."</string>
<string name="recent_tasks_title" msgid="3691764623638127888">"हाल के"</string>
- <string name="no_recent_tasks" msgid="8794906658732193473">"कोई हाल ही के एप्लिकेशन नहीं."</string>
+ <string name="no_recent_tasks" msgid="8794906658732193473">"कोई हाल ही के एप्स नहीं."</string>
<string name="global_actions" product="tablet" msgid="408477140088053665">"टेबलेट विकल्प"</string>
<string name="global_actions" product="default" msgid="2406416831541615258">"फ़ोन विकल्प"</string>
<string name="global_action_lock" msgid="2844945191792119712">"स्क्रीन लॉक"</string>
@@ -202,8 +205,8 @@
<string name="permgroupdesc_camera" msgid="2933667372289567714">"चित्र या वीडियो कैप्चर के लिए कैमरे पर सीधी पहुंच."</string>
<string name="permgrouplab_screenlock" msgid="8275500173330718168">"स्क्रीन लॉक करें"</string>
<string name="permgroupdesc_screenlock" msgid="7067497128925499401">"आपके उपकरण की लॉक स्क्रीन का व्यवहार प्रभावित करने की क्षमता."</string>
- <string name="permgrouplab_appInfo" msgid="8028789762634147725">"आपके एप्लिकेशन की जानकारी"</string>
- <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"अपने उपकरण पर अन्य एप्लिकेशन के व्यवहार को प्रभावित करने की क्षमता."</string>
+ <string name="permgrouplab_appInfo" msgid="8028789762634147725">"आपके एप्स की जानकारी"</string>
+ <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"अपने उपकरण पर अन्य एप्स के व्यवहार को प्रभावित करने की क्षमता."</string>
<string name="permgrouplab_wallpaper" msgid="3850280158041175998">"वॉलपेपर"</string>
<string name="permgroupdesc_wallpaper" msgid="5630417854750540154">"उपकरण की वॉलपेपर सेटिंग बदलें."</string>
<string name="permgrouplab_systemClock" msgid="406535759236612992">"घड़ी"</string>
@@ -221,9 +224,9 @@
<string name="permgrouplab_systemTools" msgid="4652191644082714048">"सिस्टम टूल"</string>
<string name="permgroupdesc_systemTools" msgid="8162102602190734305">"सिस्टम का निम्न-स्तर पहुंच और नियंत्रण."</string>
<string name="permgrouplab_developmentTools" msgid="3446164584710596513">"डेवलपमेंट टूल"</string>
- <string name="permgroupdesc_developmentTools" msgid="7058828032358142018">"सुविधाएं जो केवल एप्लिकेशन डेवलपर के लिए आवश्यक हैं."</string>
- <string name="permgrouplab_display" msgid="4279909676036402636">"अन्य एप्लिकेशन UI"</string>
- <string name="permgroupdesc_display" msgid="6051002031933013714">"अन्य एप्लिकेशन के UI को प्रभावित करें."</string>
+ <string name="permgroupdesc_developmentTools" msgid="7058828032358142018">"सुविधाएं जो केवल एप्स डेवलपर के लिए आवश्यक हैं."</string>
+ <string name="permgrouplab_display" msgid="4279909676036402636">"अन्य एप्स UI"</string>
+ <string name="permgroupdesc_display" msgid="6051002031933013714">"अन्य एप्स के UI को प्रभावित करें."</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"संग्रहण"</string>
<string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"USB संग्रहण में पहुंचें."</string>
<string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"SD कार्ड में पहुंचें."</string>
@@ -234,427 +237,432 @@
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"स्पर्श द्वारा एक्सप्लोर करें को चालू करें"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"स्पर्श किए गए आइटम ज़ोर से बोले जाएंगे और स्क्रीन को जेस्चर के उपयोग से एक्सप्लोर किया जा सकेगा."</string>
<string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"एन्हांस की गई वेब पहुंच-योग्यता चालू करें"</string>
- <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"एप्लिकेशन सामग्री को अधिक पहुंच-योग्य बनाने के लिए स्क्रिप्ट इंस्टॉल किए जा सकते हैं."</string>
+ <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"एप्स सामग्री को अधिक पहुंच-योग्य बनाने के लिए स्क्रिप्ट इंस्टॉल किए जा सकते हैं."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"आपके द्वारा लिखे हुए पाठ को ध्यान से देखें"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"क्रेडिट कार्ड नंबर और पासवर्ड जैसा व्यक्तिगत डेटा शामिल होता है."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"स्थिति बार अक्षम या बदलें"</string>
- <string name="permdesc_statusBar" msgid="8434669549504290975">"एप्लिकेशन को स्थिति बार अक्षम करने या सिस्टम आइकन को जोड़ने या निकालने देता है."</string>
+ <string name="permdesc_statusBar" msgid="8434669549504290975">"एप्स को स्थिति बार अक्षम करने या सिस्टम आइकन को जोड़ने या निकालने देता है."</string>
<string name="permlab_statusBarService" msgid="7247281911387931485">"स्थिति बार"</string>
- <string name="permdesc_statusBarService" msgid="716113660795976060">"एप्लिकेशन को स्थिति बार होने देता है."</string>
+ <string name="permdesc_statusBarService" msgid="716113660795976060">"एप्स को स्थिति बार होने देता है."</string>
<string name="permlab_expandStatusBar" msgid="1148198785937489264">"स्थिति बार विस्तृत/संक्षिप्त करें"</string>
- <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"एप्लिकेशन को स्थिति बार को विस्तृत या संक्षिप्त करने देता है."</string>
+ <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"एप्स को स्थिति बार को विस्तृत या संक्षिप्त करने देता है."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"आउटगोइंग कॉल को कहीं और भेजें"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"एप्लिकेशन को आउटगोइंग कॉल संसाधित करने और डायल किए जाने वाला नंबर बदलने देता है. यह अनुमति एप्लिकेशन को आउटगोइंग कॉल की निगरानी करने, रीडायरेक्ट करने, या उन्हें रोकने देती है."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"एप्स को आउटगोइंग कॉल संसाधित करने और डायल किए जाने वाला नंबर बदलने देता है. यह अनुमति एप्स को आउटगोइंग कॉल की निगरानी करने, रीडायरेक्ट करने, या उन्हें रोकने देती है."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"पाठ संदेश (SMS) प्राप्त करें"</string>
- <string name="permdesc_receiveSms" msgid="6424387754228766939">"एप्लिकेशन को SMS संदेशों को प्राप्त और संसाधित करने देता है. इसका अर्थ है कि एप्लिकेशन आपके उपकरण पर भेजे गए संदेशों की निगरानी आपको दिखाए बिना कर सकता है और उन्हें हटा सकता है."</string>
+ <string name="permdesc_receiveSms" msgid="6424387754228766939">"एप्स को SMS संदेशों को प्राप्त और संसाधित करने देता है. इसका अर्थ है कि एप्स आपके उपकरण पर भेजे गए संदेशों की निगरानी आपको दिखाए बिना कर सकता है और उन्हें हटा सकता है."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"पाठ संदेश (MMS) प्राप्त करें"</string>
- <string name="permdesc_receiveMms" msgid="533019437263212260">"एप्लिकेशन को MMS संदेशों को प्राप्त और संसाधित करने देता है. इसका अर्थ है कि एप्लिकेशन आपके उपकरण पर भेजे गए संदेशों की निगरानी आपको दिखाए बिना कर सकता है और उन्हें हटा सकता है."</string>
+ <string name="permdesc_receiveMms" msgid="533019437263212260">"एप्स को MMS संदेशों को प्राप्त और संसाधित करने देता है. इसका अर्थ है कि एप्स आपके उपकरण पर भेजे गए संदेशों की निगरानी आपको दिखाए बिना कर सकता है और उन्हें हटा सकता है."</string>
<string name="permlab_receiveEmergencyBroadcast" msgid="1803477660846288089">"आपातकालीन प्रसारण प्राप्त करें"</string>
- <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"एप्लिकेशन को आपातकालीन प्रसारण संदेशों को प्राप्त करने और संसाधित करने देता है. यह अनुमति केवल सिस्टम एप्लिकेशन में उपलब्ध है."</string>
+ <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"एप्स को आपातकालीन प्रसारण संदेशों को प्राप्त करने और संसाधित करने देता है. यह अनुमति केवल सिस्टम एप्स में उपलब्ध है."</string>
<string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"सेल प्रसारण संदेश पढ़ें"</string>
- <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"एप्लिकेशन को आपके उपकरण द्वारा प्राप्त सेल प्रसारण संदेशों को पढ़ने देता है. कुछ स्थानों पर आपको आपातकालीन स्थितियों की चेतावनी देने के लिए सेल प्रसारण अलर्ट वितरित किए जाते हैं. आपातकालीन सेल प्रसारण प्राप्त होने पर दुर्भावनापूर्ण एप्लिकेशन आपके उपकरण के निष्पादन या संचालन में हस्तक्षेप कर सकते हैं."</string>
+ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"एप्स को आपके उपकरण द्वारा प्राप्त सेल प्रसारण संदेशों को पढ़ने देता है. कुछ स्थानों पर आपको आपातकालीन स्थितियों की चेतावनी देने के लिए सेल प्रसारण अलर्ट वितरित किए जाते हैं. आपातकालीन सेल प्रसारण प्राप्त होने पर दुर्भावनापूर्ण एप्स आपके उपकरण के निष्पादन या संचालन में हस्तक्षेप कर सकते हैं."</string>
<string name="permlab_sendSms" msgid="5600830612147671529">"SMS संदेश भेजें"</string>
- <string name="permdesc_sendSms" msgid="7094729298204937667">"एप्लिकेशन को SMS संदेशों को भेजने देता है. इसके परिणामस्वरूप अप्रत्याशित शुल्क लागू हो सकते हैं. दुर्भावनापूर्ण एप्लिकेशन आपकी पुष्टि के बिना संदेश भेजकर आपका धन व्यय कर सकते हैं."</string>
+ <string name="permdesc_sendSms" msgid="7094729298204937667">"एप्स को SMS संदेशों को भेजने देता है. इसके परिणामस्वरूप अप्रत्याशित शुल्क लागू हो सकते हैं. दुर्भावनापूर्ण एप्स आपकी पुष्टि के बिना संदेश भेजकर आपका धन व्यय कर सकते हैं."</string>
<string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"संदेश-द्वारा-जवाब भेजें ईवेंट"</string>
- <string name="permdesc_sendRespondViaMessageRequest" msgid="7107648548468778734">"इनकमिंग कॉल के संदेश-द्वारा-जवाब देने के ईवेंट प्रबंधित करने के लिए, एप्लिकेशन को अन्य संदेश सेवा एप्लिकेशन को अनुरोध भेजने देती है."</string>
+ <string name="permdesc_sendRespondViaMessageRequest" msgid="7107648548468778734">"इनकमिंग कॉल के संदेश-द्वारा-जवाब देने के ईवेंट प्रबंधित करने के लिए, एप्स को अन्य संदेश सेवा एप्स को अनुरोध भेजने देती है."</string>
<string name="permlab_readSms" msgid="8745086572213270480">"अपने पाठ संदेश (SMS या MMS) पढ़ें"</string>
- <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"एप्लिकेशन को आपके टेबलेट या SIM कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या गोपनीयता पर ध्यान दिए बिना, एप्लिकेशन सभी SMS संदेश पढ़ सकता है."</string>
- <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"एप्लिकेशन को आपके फ़ोन या SIM कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या गोपनीयता पर ध्यान दिए बिना, एप्लिकेशन सभी SMS संदेश पढ़ सकता है."</string>
+ <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"एप्स को आपके टेबलेट या SIM कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या गोपनीयता पर ध्यान दिए बिना, एप्स सभी SMS संदेश पढ़ सकता है."</string>
+ <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"एप्स को आपके फ़ोन या SIM कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या गोपनीयता पर ध्यान दिए बिना, एप्स सभी SMS संदेश पढ़ सकता है."</string>
<string name="permlab_writeSms" msgid="3216950472636214774">"अपने पाठ संदेश (SMS या MMS) संपादित करें"</string>
- <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"एप्लिकेशन को आपके टेबलेट या सिम कार्ड में संग्रहीत SMS संदेशों में लिखने देता है. दुर्भावनापूर्ण एप्लिकेशन आपके संदेशों को हटा सकते हैं."</string>
- <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"एप्लिकेशन को आपके फ़ोन या सिम कार्ड में संग्रहीत SMS संदेशों को लिखने देता है. दुर्भावनापूर्ण एप्लिकेशन आपके संदेशों को हटा सकते हैं."</string>
+ <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"एप्स को आपके टेबलेट या सिम कार्ड में संग्रहीत SMS संदेशों में लिखने देता है. दुर्भावनापूर्ण एप्स आपके संदेशों को हटा सकते हैं."</string>
+ <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"एप्स को आपके फ़ोन या सिम कार्ड में संग्रहीत SMS संदेशों को लिखने देता है. दुर्भावनापूर्ण एप्स आपके संदेशों को हटा सकते हैं."</string>
<string name="permlab_receiveWapPush" msgid="5991398711936590410">"पाठ संदेश (WAP) प्राप्त करें"</string>
- <string name="permdesc_receiveWapPush" msgid="748232190220583385">"एप्लिकेशन को WAP संदेशों को प्राप्त और संसाधित करने देता है. इस अनुमति में आपको भेजे गए संदेशों की निगरानी आपको दिखाए बिना करने और हटाने की क्षमता शामिल है."</string>
- <string name="permlab_getTasks" msgid="6466095396623933906">"चल रहे एप्लिकेशन पुनर्प्राप्त करें"</string>
- <string name="permdesc_getTasks" msgid="7454215995847658102">"एप्लिकेशन को वर्तमान में और हाल ही में चल रहे कार्यों के बारे में जानकारी को पुन: प्राप्त करने देता है. इससे एप्लिकेशन उपकरण पर उपयोग किए गए एप्लिकेशन के बारे में जानकारी खोज सकता है."</string>
+ <string name="permdesc_receiveWapPush" msgid="748232190220583385">"एप्स को WAP संदेशों को प्राप्त और संसाधित करने देता है. इस अनुमति में आपको भेजे गए संदेशों की निगरानी आपको दिखाए बिना करने और हटाने की क्षमता शामिल है."</string>
+ <string name="permlab_getTasks" msgid="6466095396623933906">"चल रहे एप्स पुनर्प्राप्त करें"</string>
+ <string name="permdesc_getTasks" msgid="7454215995847658102">"एप्स को वर्तमान में और हाल ही में चल रहे कार्यों के बारे में जानकारी को पुन: प्राप्त करने देता है. इससे एप्स उपकरण पर उपयोग किए गए एप्स के बारे में जानकारी खोज सकता है."</string>
<string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"उपयोगकर्ताओं के बीच सहभागिता करें"</string>
- <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"एप्लिकेशन को उपकरण पर भिन्न उपयोगकर्ताओं के बीच कार्य निष्पादित करने देता है. दुर्भावनापूर्ण एप्लिकेशन उपयोगकर्ताओं के बीच सुरक्षा का उल्लंघन करने के लिए इसका उपयोग कर सकते हैं."</string>
+ <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"एप्स को उपकरण पर भिन्न उपयोगकर्ताओं के बीच कार्य निष्पादित करने देता है. दुर्भावनापूर्ण एप्स उपयोगकर्ताओं के बीच सुरक्षा का उल्लंघन करने के लिए इसका उपयोग कर सकते हैं."</string>
<string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"उपयोगकर्ताओं के बीच सहभागिता करने के लिए पूर्ण लाइसेंस"</string>
<string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"उपयोगकर्ताओं के बीच सभी संभव सहभागिता करने देता है."</string>
<string name="permlab_manageUsers" msgid="1676150911672282428">"उपयोगकर्ता प्रबंधित करें"</string>
- <string name="permdesc_manageUsers" msgid="8409306667645355638">"एप्लिकेशन को उपकरण पर क्वेरी, निर्माण और हटाने सहित उपयोगकर्ताओं को प्रबंधित करने की सुविधा देता है."</string>
- <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"चल रहे एप्लिकेशन के विवरण प्राप्त करें"</string>
- <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"एप्लिकेशन को वर्तमान में और हाल ही में चल रहे कार्यों की जानकारी प्राप्त करने देता है. दुर्भावनापूर्ण एप्लिकेशन अन्य एप्लिकेशन के बारे में निजी जानकारी खोज सकते हैं."</string>
- <string name="permlab_reorderTasks" msgid="2018575526934422779">"चल रहे एप्लिकेशन पुन: क्रमित करें"</string>
- <string name="permdesc_reorderTasks" msgid="7734217754877439351">"एप्लिकेशन को कार्यों को अग्रभूमि और पृष्ठभूमि पर ले जाने देता है. एप्लिकेशन आपके इनपुट के बिना यह कर सकता है."</string>
- <string name="permlab_removeTasks" msgid="6821513401870377403">"चलने वाले एप्लिकेशन रोकें"</string>
- <string name="permdesc_removeTasks" msgid="1394714352062635493">"किसी एप्लिकेशन को कार्यों को निकालने और उनके एप्लिकेशन समाप्त करने देता है. दुर्भावनापूर्ण एप्लिकेशन अन्य एप्लिकेशन का व्यवहार बाधित कर सकते हैं."</string>
+ <string name="permdesc_manageUsers" msgid="8409306667645355638">"एप्स को उपकरण पर क्वेरी, निर्माण और हटाने सहित उपयोगकर्ताओं को प्रबंधित करने की सुविधा देता है."</string>
+ <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"चल रहे एप्स के विवरण प्राप्त करें"</string>
+ <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"एप्स को वर्तमान में और हाल ही में चल रहे कार्यों की जानकारी प्राप्त करने देता है. दुर्भावनापूर्ण एप्स अन्य एप्स के बारे में निजी जानकारी खोज सकते हैं."</string>
+ <string name="permlab_reorderTasks" msgid="2018575526934422779">"चल रहे एप्स पुन: क्रमित करें"</string>
+ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"एप्स को कार्यों को अग्रभूमि और पृष्ठभूमि पर ले जाने देता है. एप्स आपके इनपुट के बिना यह कर सकता है."</string>
+ <string name="permlab_removeTasks" msgid="6821513401870377403">"चलने वाले एप्स रोकें"</string>
+ <string name="permdesc_removeTasks" msgid="1394714352062635493">"किसी एप्स को कार्यों को निकालने और उनके एप्स समाप्त करने देता है. दुर्भावनापूर्ण एप्स अन्य एप्स का व्यवहार बाधित कर सकते हैं."</string>
<string name="permlab_manageActivityStacks" msgid="7391191384027303065">"गतिविधि स्टैक प्रबंधित करें"</string>
- <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"एप्लिकेशन को ऐसे गतिविधि स्टैक जोड़ने, निकालने, और बदलने देता है जिनमें अन्य एप्लिकेशन चलते हों. दुर्भावनापूर्ण एप्लिकेशन अन्य एप्लिकेशन के व्यवहार में बाधा डाल सकते हैं."</string>
+ <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"एप्स को ऐसे गतिविधि स्टैक जोड़ने, निकालने, और बदलने देता है जिनमें अन्य एप्स चलते हों. दुर्भावनापूर्ण एप्स अन्य एप्स के व्यवहार में बाधा डाल सकते हैं."</string>
<string name="permlab_startAnyActivity" msgid="2918768238045206456">"कोई गतिविधि प्रारंभ करें"</string>
- <string name="permdesc_startAnyActivity" msgid="997823695343584001">"अनुमति सुरक्षा या निर्यात की स्थिति पर ध्यान दिए बिना, एप्लिकेशन को कोई गतिविधि प्रारंभ करने देता है."</string>
+ <string name="permdesc_startAnyActivity" msgid="997823695343584001">"अनुमति सुरक्षा या निर्यात की स्थिति पर ध्यान दिए बिना, एप्स को कोई गतिविधि प्रारंभ करने देता है."</string>
<string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"स्क्रीन संगतता सेट करें"</string>
- <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"एप्लिकेशन को अन्य एप्लिकेशन के स्क्रीन संगतता मोड को नियंत्रित करने देता है. दुर्भावनापूर्ण एप्लिकेशन अन्य एप्लिकेशन का व्यवहार बाधित कर सकते हैं."</string>
- <string name="permlab_setDebugApp" msgid="3022107198686584052">"एप्लिकेशन डीबग करना सक्षम करें"</string>
- <string name="permdesc_setDebugApp" msgid="4474512416299013256">"एप्लिकेशन को अन्य एप्लिकेशन के लिए डीबग किया जाना चालू करने देता है. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग अन्य एप्लिकेशन को समाप्त करने के लिए कर सकते हैं."</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"एप्स को अन्य एप्स के स्क्रीन संगतता मोड को नियंत्रित करने देता है. दुर्भावनापूर्ण एप्स अन्य एप्स का व्यवहार बाधित कर सकते हैं."</string>
+ <string name="permlab_setDebugApp" msgid="3022107198686584052">"एप्स डीबग करना सक्षम करें"</string>
+ <string name="permdesc_setDebugApp" msgid="4474512416299013256">"एप्स को अन्य एप्स के लिए डीबग किया जाना चालू करने देता है. दुर्भावनापूर्ण एप्स इसका उपयोग अन्य एप्स को समाप्त करने के लिए कर सकते हैं."</string>
<string name="permlab_changeConfiguration" msgid="4162092185124234480">"सिस्टम प्रदर्शन सेटिंग बदलें"</string>
- <string name="permdesc_changeConfiguration" msgid="4372223873154296076">"एप्लिकेशन को वर्तमान कॉन्फ़िगरेशन, जैसे स्थान या समग्र अक्षरों का आकार, बदलने देता है."</string>
+ <string name="permdesc_changeConfiguration" msgid="4372223873154296076">"एप्स को वर्तमान कॉन्फ़िगरेशन, जैसे स्थान या समग्र अक्षरों का आकार, बदलने देता है."</string>
<string name="permlab_enableCarMode" msgid="5684504058192921098">"कार मोड सक्षम करें"</string>
- <string name="permdesc_enableCarMode" msgid="4853187425751419467">"एप्लिकेशन को कार मोड सक्षम करने देता है."</string>
- <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"अन्य एप्लिकेशन बंद करें"</string>
- <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"एप्लिकेशन को अन्य एप्लिकेशन की पृष्ठभूमि प्रक्रियाओं को समाप्त करने देता है. यह अन्य एप्लिकेशन का चलना रोक सकता है."</string>
- <string name="permlab_forceStopPackages" msgid="2329627428832067700">"अन्य एप्लिकेशन बलपूर्वक बंद करें"</string>
- <string name="permdesc_forceStopPackages" msgid="5253157296183940812">"एप्लिकेशन को अन्य एप्लिकेशन बलपूर्वक बंद करने देता है."</string>
- <string name="permlab_forceBack" msgid="652935204072584616">"एप्लिकेशन को बलपूर्वक बंद करें"</string>
- <string name="permdesc_forceBack" msgid="3892295830419513623">"एप्लिकेशन को अग्रभूमि में चल रही कोई भी गतिविधि बलपूर्वक बंद करने और वापस जाने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_enableCarMode" msgid="4853187425751419467">"एप्स को कार मोड सक्षम करने देता है."</string>
+ <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"अन्य एप्स बंद करें"</string>
+ <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"एप्स को अन्य एप्स की पृष्ठभूमि प्रक्रियाओं को समाप्त करने देता है. यह अन्य एप्स का चलना रोक सकता है."</string>
+ <string name="permlab_forceStopPackages" msgid="2329627428832067700">"अन्य एप्स बलपूर्वक बंद करें"</string>
+ <string name="permdesc_forceStopPackages" msgid="5253157296183940812">"एप्स को अन्य एप्स बलपूर्वक बंद करने देता है."</string>
+ <string name="permlab_forceBack" msgid="652935204072584616">"एप्स को बलपूर्वक बंद करें"</string>
+ <string name="permdesc_forceBack" msgid="3892295830419513623">"एप्स को अग्रभूमि में चल रही कोई भी गतिविधि बलपूर्वक बंद करने और वापस जाने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_dump" msgid="1681799862438954752">"सिस्टम की आंतरिक स्थिति पुनर्प्राप्त करें"</string>
- <string name="permdesc_dump" msgid="1778299088692290329">"एप्लिकेशन को सिस्टम की आंतरिक स्थिति पुनर्प्राप्त करने देता है. दुर्भावनापूर्ण एप्लिकेशन विभिन्न प्रकार की निजी और सुरक्षा जानकारी प्राप्त कर सकते हैं जिनकी उन्हें सामान्यत: आवश्यकता नहीं होती."</string>
+ <string name="permdesc_dump" msgid="1778299088692290329">"एप्स को सिस्टम की आंतरिक स्थिति पुनर्प्राप्त करने देता है. दुर्भावनापूर्ण एप्स विभिन्न प्रकार की निजी और सुरक्षा जानकारी प्राप्त कर सकते हैं जिनकी उन्हें सामान्यत: आवश्यकता नहीं होती."</string>
<string name="permlab_retrieve_window_content" msgid="8022588608994589938">"स्क्रीन सामग्री पुनर्प्राप्त करें"</string>
- <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"एप्लिकेशन को सक्रिय विंडो की सामग्री पुनर्प्राप्त करने देता है. दुर्भावनापूर्ण एप्लिकेशन विंडो की संपूर्ण सामग्री प्राप्त कर सकते हैं और पासवर्ड को छोड़कर इसके सभी पाठ जांच सकते हैं."</string>
+ <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"एप्स को सक्रिय विंडो की सामग्री पुनर्प्राप्त करने देता है. दुर्भावनापूर्ण एप्स विंडो की संपूर्ण सामग्री प्राप्त कर सकते हैं और पासवर्ड को छोड़कर इसके सभी पाठ जांच सकते हैं."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"पहुंच-योग्यता को अस्थायी रूप से सक्षम करें"</string>
- <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"एप्लिकेशन को उपकरण पर पहुंच-योग्यता को अस्थायी रूप से सक्षम करने देता है. दुर्भावनापूर्ण एप्लिकेशन उपयोगकर्ता की सहमति के बिना पहुंच-योग्यता को सक्षम कर सकते हैं."</string>
+ <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"एप्स को उपकरण पर पहुंच-योग्यता को अस्थायी रूप से सक्षम करने देता है. दुर्भावनापूर्ण एप्स उपयोगकर्ता की सहमति के बिना पहुंच-योग्यता को सक्षम कर सकते हैं."</string>
<string name="permlab_retrieve_window_info" msgid="8532295199112519378">"विंडो जानकारी प्राप्त करें"</string>
- <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"एप्लिकेशन को विंडो प्रबंधक से windows के बारे में जानकारी प्राप्त करने देता है. दुर्भावनापूर्ण एप्लिकेशन आंतरिक सिस्टम उपयोग के लिए अभिप्रेत जानकारी को प्राप्त कर सकते हैं."</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"एप्स को विंडो प्रबंधक से windows के बारे में जानकारी प्राप्त करने देता है. दुर्भावनापूर्ण एप्स आंतरिक सिस्टम उपयोग के लिए अभिप्रेत जानकारी को प्राप्त कर सकते हैं."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"ईवेंट फ़िल्टर करें"</string>
- <string name="permdesc_filter_events" msgid="8006236315888347680">"एप्लिकेशन को इनपुट फ़िल्टर पंजीकृत करने देता है, जो सभी उपयोगकर्ता ईवेंट के स्ट्रीम को भेजे जाने से पहले फ़िल्टर करता है. दुर्भावनापूर्ण एप्लिकेशन उपयोगकर्ता के हस्तक्षेप के बिना सिस्टम UI को नियंत्रित कर सकता है."</string>
+ <string name="permdesc_filter_events" msgid="8006236315888347680">"एप्स को इनपुट फ़िल्टर पंजीकृत करने देता है, जो सभी उपयोगकर्ता ईवेंट के स्ट्रीम को भेजे जाने से पहले फ़िल्टर करता है. दुर्भावनापूर्ण एप्स उपयोगकर्ता के हस्तक्षेप के बिना सिस्टम UI को नियंत्रित कर सकता है."</string>
<string name="permlab_magnify_display" msgid="5973626738170618775">"डिस्प्ले को आवर्धित करें"</string>
- <string name="permdesc_magnify_display" msgid="7121235684515003792">"एप्लिकेशन को डिस्प्ले की सामग्री आवर्धित करने देता है. दुर्भावनापूर्ण एप्लिकेशन डिस्प्ले सामग्री को इस तरह से बदल सकते हैं कि उपकरण अनुपयोगी रेंडर होता है."</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"एप्स को डिस्प्ले की सामग्री आवर्धित करने देता है. दुर्भावनापूर्ण एप्स डिस्प्ले सामग्री को इस तरह से बदल सकते हैं कि उपकरण अनुपयोगी रेंडर होता है."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"आंशिक शटडाउन"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"गतिविधि प्रबंधक को शटडाउन स्थिति में रखता है. पूर्ण शटडाउन निष्पादित नहीं करता है."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"एप्लिकेशन स्विच करने से रोकता है"</string>
- <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"उपयोगकर्ता को दूसरे एप्लिकेशन पर स्विच करने से रोकता है."</string>
- <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"वर्तमान एप्लिकेशन की जानकारी प्राप्त करें"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"धारक को स्क्रीन की अग्रभूमि में वर्तमान एप्लिकेशन और सेवाओं की निजी जानकारी प्राप्त करने देती है."</string>
- <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"सभी एप्लिकेशन की लॉन्चिंग की निगरानी करें और उसे नियंत्रित करें"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"एप्लिकेशन को यह निगरानी और नियंत्रित करने देता है कि सिस्टम कैसे गतिविधियां लॉन्च करता है. दुर्भावनापूर्ण एप्लिकेशन सिस्टम को पूरी तरह से जोखिम में डाल सकते हैं. इस अनुमति की आवश्यकता केवल विकास के लिए है, सामान्य उपयोग के लिए कभी नहीं."</string>
+ <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"एप्स स्विच करने से रोकता है"</string>
+ <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"उपयोगकर्ता को दूसरे एप्स पर स्विच करने से रोकता है."</string>
+ <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"वर्तमान एप्स की जानकारी प्राप्त करें"</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"धारक को स्क्रीन के अग्रभाग में स्थित वर्तमान एप्स के बारे में निजी जानकारी प्राप्त करने देती है."</string>
+ <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"सभी एप्स की लॉन्चिंग की निगरानी करें और उसे नियंत्रित करें"</string>
+ <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"एप्स को यह निगरानी और नियंत्रित करने देता है कि सिस्टम कैसे गतिविधियां लॉन्च करता है. दुर्भावनापूर्ण एप्स सिस्टम को पूरी तरह से जोखिम में डाल सकते हैं. इस अनुमति की आवश्यकता केवल विकास के लिए है, सामान्य उपयोग के लिए कभी नहीं."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"पैकेज निकाले गए प्रसारण भेजें"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"एप्लिकेशन को कोई ऐसी सूचना प्रसारित करने देता है जिसे किसी एप्लिकेशन पैकेज ने निकाल दिया गया हो. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग चल रहे अन्य एप्लिकेशन को समाप्त करने के लिए कर सकते हैं."</string>
+ <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"एप्स को कोई ऐसी सूचना प्रसारित करने देता है जिसे किसी एप्स पैकेज ने निकाल दिया गया हो. दुर्भावनापूर्ण एप्स इसका उपयोग चल रहे अन्य एप्स को समाप्त करने के लिए कर सकते हैं."</string>
<string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"SMS-प्राप्त प्रसार भेजें"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"एप्लिकेशन को वह सूचना प्रसारित करने देता है जो SMS संदेश ने प्राप्त की है. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग नकली इनकमिंग संदेश गढ़ने के लिए कर सकते हैं."</string>
+ <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"एप्स को वह सूचना प्रसारित करने देता है जो SMS संदेश ने प्राप्त की है. दुर्भावनापूर्ण एप्स इसका उपयोग नकली इनकमिंग संदेश गढ़ने के लिए कर सकते हैं."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-प्राप्त प्रसारण भेजें"</string>
- <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"एप्लिकेशन को वह सूचना प्रसारित करने देता है जो WAP PUSH संदेश को प्राप्त हुआ है. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग नकली MMS संदेश प्राप्त करने या किसी वेबपृष्ठ की सामग्री को दुर्भावनापूर्ण दूसरे रूप से चुपचाप प्रतिस्थापित करने के लिए कर सकते हैं."</string>
+ <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"एप्स को वह सूचना प्रसारित करने देता है जो WAP PUSH संदेश को प्राप्त हुआ है. दुर्भावनापूर्ण एप्स इसका उपयोग नकली MMS संदेश प्राप्त करने या किसी वेबपृष्ठ की सामग्री को दुर्भावनापूर्ण दूसरे रूप से चुपचाप प्रतिस्थापित करने के लिए कर सकते हैं."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"चल रही प्रक्रियाओं की संख्या सीमित करें"</string>
- <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"एप्लिकेशन को चलाई जाने वाली अधिकतम प्रक्रियाओं को नियंत्रित करने देता है. सामान्य एप्लिकेशन के लिए कभी आवश्यक नहीं होती."</string>
- <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"पृष्ठभूमि एप्लिकेशन को बलपूर्वक बंद करें"</string>
- <string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"एप्लिकेशन को यह नियंत्रित करने देता है कि पृष्ठभूमि में जाते ही गतिविधियां पूर्ण हो जाती है या नही. सामान्य एप्लिकेशन के लिए कभी आवश्यकता नहीं होती."</string>
+ <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"एप्स को चलाई जाने वाली अधिकतम प्रक्रियाओं को नियंत्रित करने देता है. सामान्य एप्स के लिए कभी आवश्यक नहीं होती."</string>
+ <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"पृष्ठभूमि एप्स को बलपूर्वक बंद करें"</string>
+ <string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"एप्स को यह नियंत्रित करने देता है कि पृष्ठभूमि में जाते ही गतिविधियां पूर्ण हो जाती है या नही. सामान्य एप्स के लिए कभी आवश्यकता नहीं होती."</string>
<string name="permlab_batteryStats" msgid="2789610673514103364">"बैटरी के आंकड़े पढ़ें"</string>
- <string name="permdesc_batteryStats" msgid="5897346582882915114">"एप्लिकेशन को वर्तमान निम्न-स्तरीय बैटरी उपयोग डेटा पढ़ने देती है. एप्लिकेशन को आपके द्वारा उपयोग किए जाने वाले एप्लिकेशन के बारे में विस्तृत जानकारी ढूंढने दे सकती है."</string>
+ <string name="permdesc_batteryStats" msgid="5897346582882915114">"एप्स को वर्तमान निम्न-स्तरीय बैटरी उपयोग डेटा पढ़ने देती है. एप्स को आपके द्वारा उपयोग किए जाने वाले एप्स के बारे में विस्तृत जानकारी ढूंढने दे सकती है."</string>
<string name="permlab_updateBatteryStats" msgid="3719689764536379557">"बैटरी के आंकड़े संशोधित करें"</string>
- <string name="permdesc_updateBatteryStats" msgid="6862817857178025002">"एप्लिकेशन को बैटरी के संकलित आंकड़ों को संशोधित करने देती है. सामान्य एप्लिकेशन के द्वारा उपयोग करने के लिए नहीं."</string>
- <string name="permlab_getAppOpsStats" msgid="1508779687436585744">"एप्लिकेशन संचालन आंकड़े प्राप्त करें"</string>
- <string name="permdesc_getAppOpsStats" msgid="6243887041577912877">"एप्लिकेशन को संकलित एप्लिकेशन संचालन आंकड़े प्राप्त करने देता है. सामान्य एप्लिकेशन के द्वारा उपयोग के लिए नहीं."</string>
- <string name="permlab_updateAppOpsStats" msgid="8829097373851521505">"एप्लिकेशन कार्यवाही के आंकड़े बदलें"</string>
- <string name="permdesc_updateAppOpsStats" msgid="50784596594403483">"एप्लिकेशन को एप्लिकेशन कार्यवाही के एकत्रित आंकड़े बदलने देता है. सामान्य एप्लिकेशन के द्वारा उपयोग करने के लिए नहीं."</string>
- <string name="permlab_backup" msgid="470013022865453920">"सिस्टम बैकअप नियंत्रित और पुनर्स्थापित करें"</string>
- <string name="permdesc_backup" msgid="6912230525140589891">"एप्लिकेशन को सिस्टम के बैकअप को नियंत्रित और क्रियाविधि को पुर्नस्थापित करने देता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
- <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"पूर्ण बैकअप या पुनर्स्थापना कार्यवाही की पुष्टि करें"</string>
- <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"एप्लिकेशन को पूर्ण बैकअप पुष्टिकरण UI लॉन्च करने देता है. किसी एप्लिकेशन द्वारा उपयोग के लिए नहीं."</string>
+ <string name="permdesc_updateBatteryStats" msgid="6862817857178025002">"एप्स को बैटरी के संकलित आंकड़ों को संशोधित करने देती है. सामान्य एप्स के द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permlab_getAppOpsStats" msgid="1508779687436585744">"एप्स संचालन आंकड़े प्राप्त करें"</string>
+ <string name="permdesc_getAppOpsStats" msgid="6243887041577912877">"एप्स को संकलित एप्स संचालन आंकड़े प्राप्त करने देता है. सामान्य एप्स के द्वारा उपयोग के लिए नहीं."</string>
+ <string name="permlab_updateAppOpsStats" msgid="8829097373851521505">"एप्स कार्यवाही के आंकड़े बदलें"</string>
+ <string name="permdesc_updateAppOpsStats" msgid="50784596594403483">"एप्स को एप्स कार्यवाही के एकत्रित आंकड़े बदलने देता है. सामान्य एप्स के द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permlab_backup" msgid="470013022865453920">"सिस्टम सुरक्षा नियंत्रित और पुनर्स्थापित करें"</string>
+ <string name="permdesc_backup" msgid="6912230525140589891">"एप्स को सिस्टम के बैकअप को नियंत्रित और क्रियाविधि को पुर्नस्थापित करने देता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"पूर्ण सुरक्षा या पुनर्स्थापना कार्यवाही की पुष्टि करें"</string>
+ <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"एप्स को पूर्ण बैकअप पुष्टिकरण UI लॉन्च करने देता है. किसी एप्स द्वारा उपयोग के लिए नहीं."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"अनधिकृत विंडो दिखाएं"</string>
- <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"किसी एप्लिकेशन को ऐसी विंडो बनाने देता है जिनका उपयोग आंतरिक सिस्टम उपयोगकर्ता इंटरफ़ेस द्वारा किया जाना है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
- <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"अन्य एप्लिकेशन पर खींचें"</string>
- <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"एप्लिकेशन को अन्य एप्लिकेशन के शीर्ष पर या उपयोगकर्ता इंटरफ़ेस के हिस्सों पर आने देती है. वे किसी भी एप्लिकेशन में इंटरफ़ेस के आपके उपयोग में हस्तक्षेप कर सकते हैं, या उस चीज को बदल सकती है जिसके बारे में आपको लगता है कि आप उसे अन्य एप्लिकेशन में देख रहे हैं."</string>
+ <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"किसी एप्स को ऐसी विंडो बनाने देता है जिनका उपयोग आंतरिक सिस्टम उपयोगकर्ता इंटरफ़ेस द्वारा किया जाना है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"अन्य एप्स पर खींचें"</string>
+ <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"एप्स को अन्य एप्स के शीर्ष पर या उपयोगकर्ता इंटरफ़ेस के हिस्सों पर आने देती है. वे किसी भी एप्स में इंटरफ़ेस के आपके उपयोग में हस्तक्षेप कर सकते हैं, या उस चीज को बदल सकती है जिसके बारे में आपको लगता है कि आप उसे अन्य एप्स में देख रहे हैं."</string>
<string name="permlab_setAnimationScale" msgid="2805103241153907174">"वैश्विक एनिमेशन गति बदलें"</string>
- <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"एप्लिकेशन को किसी भी समय वैश्विक एनिमेशन गति (तेज़ या धीमे एनिमेशन) बदलने देता है."</string>
- <string name="permlab_manageAppTokens" msgid="1286505717050121370">"एप्लिकेशन टोकन प्रबंधित करें"</string>
- <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"एप्लिकेशन को उनके सामान्य Z-क्रमों पर न पहुंचते हुए उनके स्वयं के टोकन बनाने और प्रबंधित करने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"एप्स को किसी भी समय वैश्विक एनिमेशन गति (तेज़ या धीमे एनिमेशन) बदलने देता है."</string>
+ <string name="permlab_manageAppTokens" msgid="1286505717050121370">"एप्स टोकन प्रबंधित करें"</string>
+ <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"एप्स को उनके सामान्य Z-क्रमों पर न पहुंचते हुए उनके स्वयं के टोकन बनाने और प्रबंधित करने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_freezeScreen" msgid="4708181184441880175">"स्क्रीन को स्थिर करें"</string>
- <string name="permdesc_freezeScreen" msgid="8558923789222670064">"पूर्ण-स्क्रीन संक्रमण के लिए एप्लिकेशन को अस्थायी रूप से स्क्रीन को स्थिर करने देता है."</string>
+ <string name="permdesc_freezeScreen" msgid="8558923789222670064">"पूर्ण-स्क्रीन संक्रमण के लिए एप्स को अस्थायी रूप से स्क्रीन को स्थिर करने देता है."</string>
<string name="permlab_injectEvents" msgid="1378746584023586600">"कुंजियों और नियंत्रण बटन को दबाएं"</string>
- <string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"एप्लिकेशन को स्वयं के इनपुट ईवेंट (कुंजी दबाना, आदि) को अन्य एप्लिकेशन को वितरित करने देता है. दुर्भावनापूर्ण एप्लिकेशन टेबलेट को टेक ओवर करने में इसका उपयोग कर सकते हैं."</string>
- <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"एप्लिकेशन को स्वयं के इनपुट ईवेंट (कुंजी दबाना, आदि) अन्य एप्लिकेशन को वितरित करने देता है. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग फ़ोन को टेक ओवर करने में कर सकते हैं."</string>
+ <string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"एप्स को स्वयं के इनपुट ईवेंट (कुंजी दबाना, आदि) को अन्य एप्स को वितरित करने देता है. दुर्भावनापूर्ण एप्स टेबलेट को टेक ओवर करने में इसका उपयोग कर सकते हैं."</string>
+ <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"एप्स को स्वयं के इनपुट ईवेंट (कुंजी दबाना, आदि) अन्य एप्स को वितरित करने देता है. दुर्भावनापूर्ण एप्स इसका उपयोग फ़ोन को टेक ओवर करने में कर सकते हैं."</string>
<string name="permlab_readInputState" msgid="469428900041249234">"आप जो भी लिखते हैं और जो कार्यवाहियां करते हैं उन्हें रिकॉर्ड करें"</string>
- <string name="permdesc_readInputState" msgid="8387754901688728043">"एप्लिकेशन को अन्य एप्लिकेशन के साथ सहभागिता करते समय भी आपके द्वारा दबाई जाने वाली कुंजियां देखने देता है (जैसे कोई पासवर्ड लिखना). सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_readInputState" msgid="8387754901688728043">"एप्स को अन्य एप्स के साथ सहभागिता करते समय भी आपके द्वारा दबाई जाने वाली कुंजियां देखने देता है (जैसे कोई पासवर्ड लिखना). सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"किसी इनपुट विधि से आबद्ध करें"</string>
- <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"धारक को किसी इनपुट विधि के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"धारक को किसी इनपुट विधि के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"पहुंच-योग्यता सेवा से आबद्ध करें"</string>
- <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"धारक को किसी पहुंच-योग्यता सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"धारक को किसी पहुंच-योग्यता सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindPrintService" msgid="8462815179572748761">"प्रिंट सेवा से आबद्ध करें"</string>
- <string name="permdesc_bindPrintService" msgid="7960067623209111135">"धारक को किसी प्रिंट सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindPrintService" msgid="7960067623209111135">"धारक को किसी प्रिंट सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindPrintSpoolerService" msgid="6807762783744125954">"प्रिंट स्पूलर सेवा से आबद्ध करें"</string>
- <string name="permdesc_bindPrintSpoolerService" msgid="3680552285933318372">"धारक को प्रिंट स्पूलर सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindPrintSpoolerService" msgid="3680552285933318372">"धारक को प्रिंट स्पूलर सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindNfcService" msgid="2752731300419410724">"NFC सेवा से आबद्ध रहें"</string>
- <string name="permdesc_bindNfcService" msgid="6120647629174066862">"धारक को ऐसे एप्लिकेशन से आबद्ध रहने देता है जो NFC कार्ड का अनुकरण कर रहे हैं. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindNfcService" msgid="6120647629174066862">"धारक को ऐसे एप्स से आबद्ध रहने देता है जो NFC कार्ड का अनुकरण कर रहे हैं. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindTextService" msgid="7358378401915287938">"किसी पाठ सेवा पर बने रहें"</string>
- <string name="permdesc_bindTextService" msgid="8151968910973998670">"धारक को किसी पाठ सेवा (उदा. SpellCheckerService) के शीर्ष-स्तर इंटरफ़ेस पर आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindTextService" msgid="8151968910973998670">"धारक को किसी पाठ सेवा (उदा. SpellCheckerService) के शीर्ष-स्तर इंटरफ़ेस पर आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindVpnService" msgid="4708596021161473255">"किसी VPN सेवा से आबद्ध करें"</string>
- <string name="permdesc_bindVpnService" msgid="2067845564581693905">"धारक को किसी Vpn सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"धारक को किसी Vpn सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"वॉलपेपर से आबद्ध करें"</string>
- <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"धारक को किसी वॉलपेपर के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"धारक को किसी वॉलपेपर के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"किसी विजेट सेवा से आबद्ध करें"</string>
- <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"किसी उपकरण व्यवस्थापक के साथ सहभागिता करें"</string>
- <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"धारक को किसी उपकरण व्यवस्थापक को उद्देश्य भेजने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
- <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"उपकरण व्यवस्थापक को जोड़ें या निकालें"</string>
- <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"धारक को सक्रिय डिवाइस व्यवस्थापकों को जोड़ने या निकालने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"धारक को किसी उपकरण व्यवस्थापक को उद्देश्य भेजने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"उपकरण उपकरण सुचारू ढ़ंग से चलाने वाले को जोड़ें या निकालें"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"धारक को सक्रिय डिवाइस व्यवस्थापकों को जोड़ने या निकालने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"स्क्रीन अभिविन्यास बदलें"</string>
- <string name="permdesc_setOrientation" msgid="3046126619316671476">"एप्लिकेशन को किसी भी समय स्क्रीन का रोटेशन बदलने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_setOrientation" msgid="3046126619316671476">"एप्स को किसी भी समय स्क्रीन का रोटेशन बदलने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"सूचक गति बदलें"</string>
- <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"एप्लिकेशन को माउस या ट्रैकपैड सूचक गति को किसी भी समय बदलने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"एप्स को माउस या ट्रैकपैड सूचक गति को किसी भी समय बदलने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"कीबोर्ड लेआउट बदलें"</string>
- <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"एप्लिकेशन को कीबोर्ड लेआउट बदलने देता है. सामान्य एप्लिकेशन के लिए कभी आवश्यक नहीं है."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"एप्लिकेशन को Linux सिग्नल भेजें"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"एप्लिकेशन को यह अनुरोध करने देता है कि दिया गया सिग्नल सभी जारी प्रक्रियाओं को भेजा जाए."</string>
- <string name="permlab_persistentActivity" msgid="8841113627955563938">"एप्लिकेशन को हमेशा चलने वाला बनाएं"</string>
- <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"एप्लिकेशन को स्मृति में स्वयं के कुछ हिस्सों को लगातार बनाने की अनुमति देता है. यह अन्य एप्लिकेशन के लिए उपलब्ध स्मृति को सीमित कर टेबलेट को धीमा कर सकता है."</string>
- <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"एप्लिकेशन को स्मृति में स्वयं के कुछ हिस्सों को लगातार बनाने देता है. यह अन्य एप्लिकेशन के लिए उपलब्ध स्मृति को सीमित कर फ़ोन को धीमा कर सकता है."</string>
- <string name="permlab_deletePackages" msgid="184385129537705938">"एप्लिकेशन हटाएं"</string>
- <string name="permdesc_deletePackages" msgid="7411480275167205081">"एप्लिकेशन को Android पैकेज हटाने देता है. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग महत्वपूर्ण एप्लिकेशन हटाने के लिए कर सकते हैं."</string>
- <string name="permlab_clearAppUserData" msgid="274109191845842756">"अन्य एप्लिकेशन का डेटा हटाएं"</string>
- <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"एप्लिकेशन को उपयोगकर्ता डेटा साफ़ करने देता है."</string>
- <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"अन्य एप्लिकेशन के संचय हटाएं"</string>
- <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"एप्लिकेशन को संचय फ़ाइलें हटाने देता है."</string>
- <string name="permlab_getPackageSize" msgid="7472921768357981986">"एप्लिकेशन संग्रहण स्थान मापें"</string>
- <string name="permdesc_getPackageSize" msgid="3921068154420738296">"एप्लिकेशन को उसका कोड, डेटा, और संचय आकारों को प्राप्त करने देता है"</string>
- <string name="permlab_installPackages" msgid="2199128482820306924">"सीधे एप्लिकेशन इंस्टॉल करें"</string>
- <string name="permdesc_installPackages" msgid="5628530972548071284">"एप्लिकेशन को नए या अपडेट किए गए Android पैकेज इंस्टॉल करने देता है. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग अनियंत्रित रूप से सशक्त अनुमतियों वाले नए एप्लिकेशन जोड़ने में कर सकते हैं."</string>
- <string name="permlab_clearAppCache" msgid="7487279391723526815">"सभी एप्लिकेशन संचय डेटा हटाएं"</string>
- <string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"एप्लिकेशन को अन्य एप्लिकेशन की संचय निर्देशिकाओं में से फ़ाइलें हटाकर टेबलेट संग्रहण को खाली करने देती है. इससे अन्य एप्लिकेशन अधिक धीमे प्रारंभ हो सकते हैं क्योंकि उन्हें अपना डेटा पुनर्प्राप्त करने की आवश्यकता होती है."</string>
- <string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"एप्लिकेशन को अन्य एप्लिकेशन की संचय निर्देशिकाओं में से फ़ाइलें हटाकर फ़ोन संग्रहण को खाली करने देती है. इससे अन्य एप्लिकेशन अधिक धीमे प्रारंभ हो सकते हैं क्योंकि उन्हें अपना डेटा पुनर्प्राप्त करने की आवश्यकता होती है."</string>
- <string name="permlab_movePackage" msgid="3289890271645921411">"एप्लिकेशन संसाधनों को ले जाएं"</string>
- <string name="permdesc_movePackage" msgid="319562217778244524">"एप्लिकेशन को एप्लिकेशन संसाधनों को आंतरिक से बाहरी मीडिया में और इसके विपरीत ले जाने देता है."</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"एप्स को कीबोर्ड लेआउट बदलने देता है. सामान्य एप्स के लिए कभी आवश्यक नहीं है."</string>
+ <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"एप्स को Linux सिग्नल भेजें"</string>
+ <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"एप्स को यह अनुरोध करने देता है कि दिया गया सिग्नल सभी जारी प्रक्रियाओं को भेजा जाए."</string>
+ <string name="permlab_persistentActivity" msgid="8841113627955563938">"एप्स को हमेशा चलने वाला बनाएं"</string>
+ <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"एप्स को स्मृति में स्वयं के कुछ हिस्सों को लगातार बनाने की अनुमति देता है. यह अन्य एप्स के लिए उपलब्ध स्मृति को सीमित कर टेबलेट को धीमा कर सकता है."</string>
+ <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"एप्स को स्मृति में स्वयं के कुछ हिस्सों को लगातार बनाने देता है. यह अन्य एप्स के लिए उपलब्ध स्मृति को सीमित कर फ़ोन को धीमा कर सकता है."</string>
+ <string name="permlab_deletePackages" msgid="184385129537705938">"एप्स हटाएं"</string>
+ <string name="permdesc_deletePackages" msgid="7411480275167205081">"एप्स को Android पैकेज हटाने देता है. दुर्भावनापूर्ण एप्स इसका उपयोग महत्वपूर्ण एप्स हटाने के लिए कर सकते हैं."</string>
+ <string name="permlab_clearAppUserData" msgid="274109191845842756">"अन्य एप्स का डेटा हटाएं"</string>
+ <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"एप्स को उपयोगकर्ता डेटा साफ़ करने देता है."</string>
+ <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"अन्य एप्स के संचय हटाएं"</string>
+ <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"एप्स को संचय फ़ाइलें हटाने देता है."</string>
+ <string name="permlab_getPackageSize" msgid="7472921768357981986">"एप्स संग्रहण स्थान मापें"</string>
+ <string name="permdesc_getPackageSize" msgid="3921068154420738296">"एप्स को उसका कोड, डेटा, और संचय आकारों को प्राप्त करने देता है"</string>
+ <string name="permlab_installPackages" msgid="2199128482820306924">"सीधे एप्स इंस्टॉल करें"</string>
+ <string name="permdesc_installPackages" msgid="5628530972548071284">"एप को नए या नई जानकारी वाले Android पैकेज इंस्टॉल करने देता है. दुर्भावनापूर्ण एप्स इसका उपयोग अनियंत्रित रूप से सशक्त अनुमतियों वाले नए एप्स जोड़ने में कर सकते हैं."</string>
+ <string name="permlab_clearAppCache" msgid="7487279391723526815">"सभी एप्स संचय डेटा हटाएं"</string>
+ <string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"एप्स को अन्य एप्स की संचय निर्देशिकाओं में से फ़ाइलें हटाकर टेबलेट संग्रहण को खाली करने देती है. इससे अन्य एप्स अधिक धीमे प्रारंभ हो सकते हैं क्योंकि उन्हें अपना डेटा पुनर्प्राप्त करने की आवश्यकता होती है."</string>
+ <string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"एप्स को अन्य एप्स की संचय निर्देशिकाओं में से फ़ाइलें हटाकर फ़ोन संग्रहण को खाली करने देती है. इससे अन्य एप्स अधिक धीमे प्रारंभ हो सकते हैं क्योंकि उन्हें अपना डेटा पुनर्प्राप्त करने की आवश्यकता होती है."</string>
+ <string name="permlab_movePackage" msgid="3289890271645921411">"एप्स संसाधनों को ले जाएं"</string>
+ <string name="permdesc_movePackage" msgid="319562217778244524">"एप्स को एप्स संसाधनों को आंतरिक से बाहरी मीडिया में और इसके विपरीत ले जाने देता है."</string>
<string name="permlab_readLogs" msgid="6615778543198967614">"संवेदनशील लॉग डेटा पढ़ें"</string>
- <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"किसी एप्लिकेशन को सिस्टम की विभिन्न लॉग फ़ाइलों से पढ़ने देता है. संभावित रूप से व्यक्तिगत या निजी जानकारी शामिल करते हुए, टेबलेट के साथ आप क्या कर रहे हैं इस बारे में सामान्य जानकारी खोजने देता है."</string>
- <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"एप्लिकेशन को सिस्टम की विभिन्न लॉग फ़ाइलें पढ़ने देता है. संभावित रूप से व्यक्तिगत या निजी जानकारी सहित, यह इसे इस बारे में सामान्य जानकारी खोजने देता है कि आप फ़ोन से क्या कर रहे हैं."</string>
+ <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"किसी एप्स को सिस्टम की विभिन्न लॉग फ़ाइलों से पढ़ने देता है. संभावित रूप से व्यक्तिगत या निजी जानकारी शामिल करते हुए, टेबलेट के साथ आप क्या कर रहे हैं इस बारे में सामान्य जानकारी खोजने देता है."</string>
+ <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"एप्स को सिस्टम की विभिन्न लॉग फ़ाइलें पढ़ने देता है. संभावित रूप से व्यक्तिगत या निजी जानकारी सहित, यह इसे इस बारे में सामान्य जानकारी खोजने देता है कि आप फ़ोन से क्या कर रहे हैं."</string>
<string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"प्लेबैक के लिए किसी भी मीडिया डीकोडर का उपयोग करें"</string>
- <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"एप्लिकेशन को प्लेबैक डीकोड करने के लिए किसी भी इंस्टॉल किए गए डीकोडर का उपयोग करने देता है."</string>
+ <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"एप्स को प्लेबैक डीकोड करने के लिए किसी भी इंस्टॉल किए गए डीकोडर का उपयोग करने देता है."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"विश्वसनीय क्रेडेंशियल प्रबंधित करें"</string>
- <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"एप्लिकेशन को CA प्रमाणपत्रों को विश्वसनीय क्रेडेंशियल के रूप में इंस्टॉल और अनइंस्टॉल करने दें"</string>
+ <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"एप्स को CA प्रमाणपत्रों को विश्वसनीय क्रेडेंशियल के रूप में इंस्टॉल और अनइंस्टॉल करने दें"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"निदान के स्वामित्व वाले संसाधनों को पढ़ें/लिखें"</string>
- <string name="permdesc_diagnostic" msgid="6608295692002452283">"एप्लिकेशन को diag समूह के स्वामित्व वाले किसी संसाधन को पढ़ने और उसमें लिखने देता है; उदाहरण के लिए, /dev की फ़ाइलें. यह सिस्टम की स्थिरता और सुरक्षा को संभावित रूप से प्रभावित कर सकता है. इसका उपयोग निर्माता या ऑपरेटर द्वारा केवल हार्डवेयर-विशिष्ट निदान के लिए किया जाना चाहिए."</string>
- <string name="permlab_changeComponentState" msgid="6335576775711095931">"एप्लिकेशन घटकों को सक्षम या अक्षम करें"</string>
- <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"एप्लिकेशन को यह बदलने देता है कि किसी अन्य एप्लिकेशन का घटक सक्षम है या नहीं. दुर्भावनापूर्ण एप्लिकेशन महत्वपूर्ण फ़ोन क्षमताओं को अक्षम करने में इसका उपयोग कर सकते हैं. इस अनुमति का उपयोग सावधानी के साथ करना चाहिए, क्योंकि इससे एप्लिकेशन घटकों के अनुपयोगी, असंगत, या अस्थिर स्थिति में जाने की संभावना है."</string>
- <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"एप्लिकेशन को यह बदलने देता है कि किसी अन्य एप्लिकेशन का घटक सक्षम है या नहीं. दुर्भावनापूर्ण एप्लिकेशन महत्वपूर्ण फ़ोन क्षमताओं को अक्षम करने में इसका उपयोग कर सकते हैं. इस अनुमति का उपयोग सावधानी के साथ करना चाहिए, क्योंकि इससे एप्लिकेशन घटकों के अनुपयोगी, असंगत, या अस्थिर स्थिति में जाने की संभावना है."</string>
+ <string name="permdesc_diagnostic" msgid="6608295692002452283">"एप्स को diag समूह के स्वामित्व वाले किसी संसाधन को पढ़ने और उसमें लिखने देता है; उदाहरण के लिए, /dev की फ़ाइलें. यह सिस्टम की स्थिरता और सुरक्षा को संभावित रूप से प्रभावित कर सकता है. इसका उपयोग निर्माता या ऑपरेटर द्वारा केवल हार्डवेयर-विशिष्ट निदान के लिए किया जाना चाहिए."</string>
+ <string name="permlab_changeComponentState" msgid="6335576775711095931">"एप्स घटकों को सक्षम या अक्षम करें"</string>
+ <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"एप्स को यह बदलने देता है कि किसी अन्य एप्स का घटक सक्षम है या नहीं. दुर्भावनापूर्ण एप्स महत्वपूर्ण फ़ोन क्षमताओं को अक्षम करने में इसका उपयोग कर सकते हैं. इस अनुमति का उपयोग सावधानी के साथ करना चाहिए, क्योंकि इससे एप्स घटकों के अनुपयोगी, असंगत, या अस्थिर स्थिति में जाने की संभावना है."</string>
+ <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"एप्स को यह बदलने देता है कि किसी अन्य एप्स का घटक सक्षम है या नहीं. दुर्भावनापूर्ण एप्स महत्वपूर्ण फ़ोन क्षमताओं को अक्षम करने में इसका उपयोग कर सकते हैं. इस अनुमति का उपयोग सावधानी के साथ करना चाहिए, क्योंकि इससे एप्स घटकों के अनुपयोगी, असंगत, या अस्थिर स्थिति में जाने की संभावना है."</string>
<string name="permlab_grantRevokePermissions" msgid="4627315351093508795">"अनुमति दें या रद्द करें"</string>
- <string name="permdesc_grantRevokePermissions" msgid="4088642654085850662">"एप्लिकेशन को उसके या अन्य एप्लिकेशन के लिए विशेष अनुमतियां देने या रद्द करने देता है. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग उन सुविधाओं तक पहुंचने के लिए कर सकते हैं जो आपने उन्हें नहीं दी हैं."</string>
- <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"पसंदीदा एप्लिकेशन सेट करें"</string>
- <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"एप्लिकेशन को आपके पसंदीदा एप्लिकेशन को संशोधित करने देता है. दुर्भावनापूर्ण एप्लिकेशन आपसे निजी डेटा एकत्रित करने के लिए आपके मौजूदा एप्लिकेशन को स्पूफ़ करके, चलाए जाने वाले एप्लिकेशन को चुपचाप बदल सकते हैं."</string>
+ <string name="permdesc_grantRevokePermissions" msgid="4088642654085850662">"एप्स को उसके या अन्य एप्स के लिए विशेष अनुमतियां देने या रद्द करने देता है. दुर्भावनापूर्ण एप्स इसका उपयोग उन सुविधाओं तक पहुंचने के लिए कर सकते हैं जो आपने उन्हें नहीं दी हैं."</string>
+ <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"पसंदीदा एप्स सेट करें"</string>
+ <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"एप्स को आपके पसंदीदा एप्स को संशोधित करने देता है. दुर्भावनापूर्ण एप्स आपसे निजी डेटा एकत्रित करने के लिए आपके मौजूदा एप्स को स्पूफ़ करके, चलाए जाने वाले एप्स को चुपचाप बदल सकते हैं."</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"सिस्टम सेटिंग बदलें"</string>
- <string name="permdesc_writeSettings" msgid="7775723441558907181">"एप्लिकेशन को सिस्टम सेटिंग डेटा संशोधित करने देता है. दुर्भावनापूर्ण एप्लिकेशन आपके सिस्टम के कॉन्फ़िगरेशन को दूषित कर सकते हैं."</string>
+ <string name="permdesc_writeSettings" msgid="7775723441558907181">"एप्स को सिस्टम सेटिंग डेटा संशोधित करने देता है. दुर्भावनापूर्ण एप्स आपके सिस्टम के कॉन्फ़िगरेशन को दूषित कर सकते हैं."</string>
<string name="permlab_writeSecureSettings" msgid="204676251876718288">"सुरक्षित सिस्टम सेटिंग बदलें"</string>
- <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"एप्लिकेशन को सिस्टम के सुरक्षित सेटिंग डेटा को संशोधित करने देता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"Google सेवाएं मैप बदलें"</string>
- <string name="permdesc_writeGservices" msgid="1287309437638380229">"एप्लिकेशन को Google सेवाओं का मानचित्र संशोधित करने देता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"एप्स को सिस्टम के सुरक्षित सेटिंग डेटा को संशोधित करने देता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permlab_writeGservices" msgid="2149426664226152185">"Google सेवाएं नक्शा बदलें"</string>
+ <string name="permdesc_writeGservices" msgid="1287309437638380229">"एप्स को Google सेवाओं का नक्शे संशोधित करने देता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"प्रारंभ होने पर चलाएं"</string>
- <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"एप्लिकेशन को सिस्टम द्वारा बूटिंग पूर्ण करते ही स्वतः आरंभ करने देता है. इससे टेबलेट को आरंभ होने में अधिक समय लग सकता है और एप्लिकेशन को निरंतर चलाकर संपूर्ण टेबलेट को धीमा करने देता है."</string>
- <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"एप्लिकेशन को सिस्टम द्वारा बूटिंग पूर्ण करते ही स्वतः प्रारंभ होने देता है. इससे फ़ोन को प्रारंभ होने में अधिक समय लग सकता है और एप्लिकेशन के निरंतर चलते रहने से संपूर्ण फ़ोन प्रक्रियाएं धीमी हो सकती हैं."</string>
+ <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"एप्स को सिस्टम द्वारा बूटिंग पूर्ण करते ही स्वतः आरंभ करने देता है. इससे टेबलेट को आरंभ होने में अधिक समय लग सकता है और एप्स को निरंतर चलाकर संपूर्ण टेबलेट को धीमा करने देता है."</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"एप्स को सिस्टम द्वारा बूटिंग पूर्ण करते ही स्वतः प्रारंभ होने देता है. इससे फ़ोन को प्रारंभ होने में अधिक समय लग सकता है और एप्स के निरंतर चलते रहने से संपूर्ण फ़ोन प्रक्रियाएं धीमी हो सकती हैं."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"स्टिकी प्रसारण भेजें"</string>
- <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"एप्लिकेशन को स्टिकी प्रसारण भेजने देता है, जो प्रसारण समाप्त होने के बाद भी बने रहते हैं. अत्यधिक उपयोग, टेबलेट की बहुत अधिक स्मृति का उपयोग करके उसे धीमा या अस्थिर कर सकता है."</string>
- <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"एप्लिकेशन को स्टिकी प्रसारण भेजने देता है, जो प्रसारण समाप्त होने के बाद भी बने रहते हैं. अत्यधिक उपयोग, फ़ोन की बहुत अधिक स्मृति का उपयोग करके उसे धीमा या अस्थिर कर सकता है."</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"एप्स को स्टिकी प्रसारण भेजने देता है, जो प्रसारण समाप्त होने के बाद भी बने रहते हैं. अत्यधिक उपयोग, टेबलेट की बहुत अधिक स्मृति का उपयोग करके उसे धीमा या अस्थिर कर सकता है."</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"एप्स को स्टिकी प्रसारण भेजने देता है, जो प्रसारण समाप्त होने के बाद भी बने रहते हैं. अत्यधिक उपयोग, फ़ोन की बहुत अधिक स्मृति का उपयोग करके उसे धीमा या अस्थिर कर सकता है."</string>
<string name="permlab_readContacts" msgid="8348481131899886131">"अपने संपर्क पढ़ें"</string>
- <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"एप्लिकेशन को आपके टेबलेट में संग्रहीत संपर्कों के डेटा को, साथ ही आपके द्वारा विशिष्ट व्यक्तियों को कॉल करने, ईमेल करने, या अन्य तरीके से संवाद करने की आवृत्ति को पढ़ने देता है. यह अनुमति एप्लिकेशन को आपके संपर्क डेटा को सहेजने देती है, और दुर्भावनापूर्ण एप्लिकेशन आपकी जानकारी के बिना संपर्क डेटा को साझा कर सकते हैं."</string>
- <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"एप्लिकेशन को आपके फ़ोन में संग्रहीत संपर्कों के डेटा को, साथ ही आपके द्वारा विशिष्ट व्यक्तियों को कॉल करने, ईमेल करने, या अन्य तरीके से संवाद करने की आवृत्ति को पढ़ने देता है. यह अनुमति एप्लिकेशन को आपके संपर्क डेटा को सहेजने देती है, और दुर्भावनापूर्ण एप्लिकेशन आपकी जानकारी के बिना संपर्क डेटा को साझा कर सकते हैं."</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"एप्स को आपके टेबलेट में संग्रहीत संपर्कों के डेटा को, साथ ही आपके द्वारा विशिष्ट व्यक्तियों को कॉल करने, ईमेल करने, या अन्य तरीके से संवाद करने की आवृत्ति को पढ़ने देता है. यह अनुमति एप्स को आपके संपर्क डेटा को सहेजने देती है, और दुर्भावनापूर्ण एप्स आपकी जानकारी के बिना संपर्क डेटा को साझा कर सकते हैं."</string>
+ <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"एप्स को आपके फ़ोन में संग्रहीत संपर्कों के डेटा को, साथ ही आपके द्वारा विशिष्ट व्यक्तियों को कॉल करने, ईमेल करने, या अन्य तरीके से संवाद करने की आवृत्ति को पढ़ने देता है. यह अनुमति एप्स को आपके संपर्क डेटा को सहेजने देती है, और दुर्भावनापूर्ण एप्स आपकी जानकारी के बिना संपर्क डेटा को साझा कर सकते हैं."</string>
<string name="permlab_writeContacts" msgid="5107492086416793544">"अपने संपर्क बदलें"</string>
- <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"एप्लिकेशन को आपके टेबलेट में संग्रहीत संपर्कों के डेटा को, साथ ही आपके द्वारा विशिष्ट व्यक्तियों को कॉल करने, ईमेल करने, या अन्य तरीके से संवाद करने की आवृत्ति को संशोधित करने देता है. यह अनुमति एप्लिकेशन को आपके संपर्क डेटा को हटाने देती है."</string>
- <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"एप्लिकेशन को आपके फ़ोन में संग्रहीत संपर्कों के डेटा को, साथ ही आपके द्वारा विशिष्ट व्यक्तियों को कॉल करने, ईमेल करने, या अन्य तरीके से संवाद करने की आवृत्ति को संशोधित करने देता है. यह अनुमति एप्लिकेशन को आपके संपर्क डेटा को हटाने देती है."</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"एप्स को आपके टेबलेट में संग्रहीत संपर्कों के डेटा को, साथ ही आपके द्वारा विशिष्ट व्यक्तियों को कॉल करने, ईमेल करने, या अन्य तरीके से संवाद करने की आवृत्ति को संशोधित करने देता है. यह अनुमति एप्स को आपके संपर्क डेटा को हटाने देती है."</string>
+ <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"एप्स को आपके फ़ोन में संग्रहीत संपर्कों के डेटा को, साथ ही आपके द्वारा विशिष्ट व्यक्तियों को कॉल करने, ईमेल करने, या अन्य तरीके से संवाद करने की आवृत्ति को संशोधित करने देता है. यह अनुमति एप्स को आपके संपर्क डेटा को हटाने देती है."</string>
<string name="permlab_readCallLog" msgid="3478133184624102739">"कॉल लॉग पढ़ें"</string>
- <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"एप्लिकेशन को आपके फ़ोन का कॉल लॉग पढ़ने देता है, जिसमें इनकमिंग और आउटगोइंग कॉल का डेटा शामिल है. यह अनुमति एप्लिकेशन को आपके कॉल लॉग डेटा को सहेजने देती है, और दुर्भावनापूर्ण एप्लिकेशन आपकी जानकारी के बिना कॉल लॉग डेटा को साझा कर सकते हैं."</string>
- <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"एप्लिकेशन को आपके फ़ोन का कॉल लॉग पढ़ने देता है, जिसमें इनकमिंग और आउटगोइंग कॉल का डेटा शामिल है. यह अनुमति एप्लिकेशन को आपके कॉल लॉग डेटा को सहेजने देती है, और दुर्भावनापूर्ण एप्लिकेशन आपकी जानकारी के बिना कॉल लॉग डेटा को साझा कर सकते हैं."</string>
+ <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"एप्स को आपके फ़ोन का कॉल लॉग पढ़ने देता है, जिसमें इनकमिंग और आउटगोइंग कॉल का डेटा शामिल है. यह अनुमति एप्स को आपके कॉल लॉग डेटा को सहेजने देती है, और दुर्भावनापूर्ण एप्स आपकी जानकारी के बिना कॉल लॉग डेटा को साझा कर सकते हैं."</string>
+ <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"एप्स को आपके फ़ोन का कॉल लॉग पढ़ने देता है, जिसमें इनकमिंग और आउटगोइंग कॉल का डेटा शामिल है. यह अनुमति एप्स को आपके कॉल लॉग डेटा को सहेजने देती है, और दुर्भावनापूर्ण एप्स आपकी जानकारी के बिना कॉल लॉग डेटा को साझा कर सकते हैं."</string>
<string name="permlab_writeCallLog" msgid="8552045664743499354">"कॉल लॉग लिखें"</string>
- <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"एप्लिकेशन को इनकमिंग और आउटगोइंग कॉल के डेटा सहित, आपके टेबलेट का कॉल लॉग संशोधित करने देता है. दुर्भावनापूर्ण एप्लिकेशन आपके कॉल लॉग को मिटाने या संशोधित करने के लिए इसका उपयोग कर सकते हैं."</string>
- <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"एप्लिकेशन को इनकमिंग और आउटगोइंग कॉल के डेटा सहित, आपके फ़ोन का कॉल लॉग संशोधित करने देता है. दुर्भावनापूर्ण एप्लिकेशन आपके कॉल लॉग को मिटाने या संशोधित करने के लिए इसका उपयोग कर सकते हैं."</string>
+ <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"एप्स को इनकमिंग और आउटगोइंग कॉल के डेटा सहित, आपके टेबलेट का कॉल लॉग संशोधित करने देता है. दुर्भावनापूर्ण एप्स आपके कॉल लॉग को मिटाने या संशोधित करने के लिए इसका उपयोग कर सकते हैं."</string>
+ <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"एप्स को इनकमिंग और आउटगोइंग कॉल के डेटा सहित, आपके फ़ोन का कॉल लॉग संशोधित करने देता है. दुर्भावनापूर्ण एप्स आपके कॉल लॉग को मिटाने या संशोधित करने के लिए इसका उपयोग कर सकते हैं."</string>
<string name="permlab_readProfile" msgid="4701889852612716678">"स्वयं का संपर्क कार्ड पढ़ें"</string>
- <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"एप्लिकेशन को आपके उपकरण में संग्रहीत व्यक्तिगत प्रोफ़ाइल जानकारी, जैसे आपका नाम और संपर्क जानकारी, पढ़ने देता है. इसका अर्थ है कि एप्लिकेशन आपको पहचान सकता है और आपकी प्रोफ़ाइल जानकारी अन्य लोगों को भेज सकता है."</string>
+ <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"एप्स को आपके उपकरण में संग्रहीत व्यक्तिगत प्रोफ़ाइल जानकारी, जैसे आपका नाम और संपर्क जानकारी, पढ़ने देता है. इसका अर्थ है कि एप्स आपको पहचान सकता है और आपकी प्रोफ़ाइल जानकारी अन्य लोगों को भेज सकता है."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"स्वयं का संपर्क कार्ड बदलें"</string>
- <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"एप्लिकेशन को आपके उपकरण में संग्रहीत निजी प्रोफ़ाइल जानकारी, जैसे आपका नाम और संपर्क जानकारी को बदलने या उसमें कुछ जोड़ने देता है. इसका अर्थ है कि एप्लिकेशन आपको पहचान सकता है और आपकी प्रोफ़ाइल जानकारी अन्य लोगों को भेज सकता है."</string>
+ <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"एप्स को आपके उपकरण में संग्रहीत निजी प्रोफ़ाइल जानकारी, जैसे आपका नाम और संपर्क जानकारी को बदलने या उसमें कुछ जोड़ने देता है. इसका अर्थ है कि एप्स आपको पहचान सकता है और आपकी प्रोफ़ाइल जानकारी अन्य लोगों को भेज सकता है."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"अपनी सामाजिक स्ट्रीम पढ़ें"</string>
- <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"एप्लिकेशन को आपके और आपके मित्रों के सामाजिक अपडेट तक पहुंचने और उन्हें समन्वयित करने देता है. जानकारी साझा करते समय सावधान रहें - इससे गोपनीयता पर ध्यान दिए बिना, एप्लिकेशन सामाजिक नेटवर्क पर आपके और आपके मित्रों के बीच संचारों को पढ़ सकता है. ध्यान दें: यह अनुमति सभी सामाजिक नेटवर्क पर लागू नहीं की जा सकती."</string>
+ <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"एप को आपके और आपके मित्रों की नई सामाजिक जानकारी तक पहुंचने और उन्हें समन्वयित करने देता है. जानकारी साझा करते समय सावधान रहें - इससे गोपनीयता पर ध्यान दिए बिना, एप सामाजिक नेटवर्क पर आपके और आपके मित्रों के बीच संचारों को पढ़ सकता है. ध्यान दें: यह अनुमति सभी सामाजिक नेटवर्क पर लागू नहीं की जा सकती."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"सामाजिक स्ट्रीम में लिखें"</string>
- <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"एप्लिकेशन को आपके मित्रों के सामाजिक अपडेट प्रदर्शित करने देता है. जानकारी साझा करते समय सावधान रहें - इससे एप्लिकेशन ऐसे संदेश बना सकता है जो किसी मित्र की ओर से आते दिखाई देते हैं. ध्यान दें: यह अनुमति सभी सामाजिक नेटवर्क पर लागू नहीं की जा सकती."</string>
+ <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"एप को आपके मित्रों की नई सामाजिक जानकारी प्रदर्शित करने देता है. जानकारी साझा करते समय सावधान रहें - इससे एप्स ऐसे संदेश बना सकता है जो किसी मित्र की ओर से आते दिखाई देते हैं. ध्यान दें: यह अनुमति सभी सामाजिक नेटवर्क पर लागू नहीं की जा सकती."</string>
<string name="permlab_readCalendar" msgid="5972727560257612398">"केलैंडर ईवेंट के साथ-साथ गोपनीय जानकारी पढ़ें"</string>
- <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"एप्लिकेशन को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके टेबलेट पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे गोपनीयता या संवेदनशीलता पर ध्यान दिए बिना, एप्लिकेशन आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
- <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"एप्लिकेशन को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके फ़ोन पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे गोपनीयता या संवेदनशीलता पर ध्यान दिए बिना, एप्लिकेशन आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
- <string name="permlab_writeCalendar" msgid="8438874755193825647">"स्वामी की जानकारी के बिना कैलेंडर ईवेंट जोड़ें या संशोधित करें और अतिथियों को ईमेल भेजें"</string>
- <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"एप्लिकेशन को मित्रों या सहकर्मियों के ईवेंट के साथ ही वे ईवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने टेबलेट पर संशोधित कर सकते हैं. इससे एप्लिकेशन, स्वामी की जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या ईवेंट संशोधित कर सकता है."</string>
- <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"एप्लिकेशन को मित्रों या सहकर्मियों के ईवेंट के साथ ही वे ईवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने फ़ोन पर संशोधित कर सकते हैं. इससे एप्लिकेशन, स्वामी की जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या ईवेंट संशोधित कर सकता है."</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"एप्स को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके टेबलेट पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे गोपनीयता या संवेदनशीलता पर ध्यान दिए बिना, एप्स आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
+ <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"एप्स को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके फ़ोन पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे गोपनीयता या संवेदनशीलता पर ध्यान दिए बिना, एप्स आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
+ <string name="permlab_writeCalendar" msgid="8438874755193825647">"अपनी जानकारी के बिना कैलेंडर ईवेंट जोड़ें या संशोधित करें और अतिथियों को ईमेल भेजें"</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"एप्स को मित्रों या सहकर्मियों के ईवेंट के साथ ही वे ईवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने टेबलेट पर संशोधित कर सकते हैं. इससे एप्स,अपनी जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या ईवेंट संशोधित कर सकता है."</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"एप्स को मित्रों या सहकर्मियों के ईवेंट के साथ ही वे ईवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने फ़ोन पर संशोधित कर सकते हैं. इससे एप्स, अपनी जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या ईवेंट संशोधित कर सकता है."</string>
<string name="permlab_accessMockLocation" msgid="8688334974036823330">"परीक्षण के लिए नकली स्थान स्रोत"</string>
- <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"परीक्षण के लिए कृत्रिम स्थान स्रोत बनाएं या एक नया स्थान प्रदाता इंस्टॉल करें. यह एप्लिकेशन को स्थान और/या अन्य स्थान स्रोतों जैसे GPS या स्थान प्रदाताओं द्वारा लौटाई गई स्थिति को ओवरराइड करने देता है."</string>
+ <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"परीक्षण के लिए कृत्रिम स्थान स्रोत बनाएं या एक नया स्थान प्रदाता इंस्टॉल करें. यह एप्स को स्थान और/या अन्य स्थान स्रोतों जैसे GPS या स्थान प्रदाताओं द्वारा लौटाई गई स्थिति को ओवरराइड करने देता है."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"अतिरिक्त स्थान प्रदाता आदेशों में पहुंचे"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"एप्लिकेशन को अतिरिक्त स्थान प्रदाता आदेशों पर पहुंचने देता है. यह एप्लिकेशन को GPS या अन्य स्थान स्रोतों के संचालन में बाधा पहुंचाने दे सकता है."</string>
+ <string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"एप्स को अतिरिक्त स्थान प्रदाता आदेशों पर पहुंचने देता है. यह एप्स को GPS या अन्य स्थान स्रोतों के संचालन में बाधा पहुंचाने दे सकता है."</string>
<string name="permlab_installLocationProvider" msgid="6578101199825193873">"किसी स्थान प्रदाता को इंस्टॉल करने की अनुमति"</string>
- <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"परीक्षण के लिए कृत्रिम स्थान स्रोत बनाएं या एक नए स्थान प्रदाता को इंस्टॉल करें. यह एप्लिकेशन को स्थान और/या अन्य स्थान स्रोतों जैसे GPS या स्थान प्रदाताओं द्वारा लौटाई गई स्थिति को ओवरराइड करने देता है."</string>
+ <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"परीक्षण के लिए कृत्रिम स्थान स्रोत बनाएं या एक नए स्थान प्रदाता को इंस्टॉल करें. यह एप्स को स्थान और/या अन्य स्थान स्रोतों जैसे GPS या स्थान प्रदाताओं द्वारा लौटाई गई स्थिति को ओवरराइड करने देता है."</string>
<string name="permlab_accessFineLocation" msgid="1191898061965273372">"सटीक स्थान (GPS और नेटवर्क-आधारित)"</string>
- <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"एप्लिकेशन को ग्लोबल पोज़िशनिंग सिस्टम (GPS) या सेल टॉवर और Wi-Fi जैसे नेटवर्क स्थान स्रोतों का उपयोग करके आपका सटीक स्थान प्राप्त करने देती है. एप्लिकेशन द्वारा इन स्थान सेवाओं का उपयोग किए जाने के लिए इन्हें चालू होना चाहिए और आपके उपकरण पर उपलब्ध होना चाहिए. एप्लिकेशन इसका उपयोग यह पता करने में कर सकते हैं कि आप कहां पर हैं, और अतिरिक्त बैटरी की खपत कर सकते हैं."</string>
+ <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"एप्स को ग्लोबल पोज़िशनिंग सिस्टम (GPS) या सेल टॉवर और Wi-Fi जैसे नेटवर्क स्थान स्रोतों का उपयोग करके आपका सटीक स्थान प्राप्त करने देती है. एप्स द्वारा इन स्थान सेवाओं का उपयोग किए जाने के लिए इन्हें चालू होना चाहिए और आपके उपकरण पर उपलब्ध होना चाहिए. एप्स इसका उपयोग यह पता करने में कर सकते हैं कि आप कहां पर हैं, और अतिरिक्त बैटरी की खपत कर सकते हैं."</string>
<string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"अनुमानित स्थान (नेटवर्क-आधारित)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"एप्लिकेशन को आपका अनुमानित स्थान प्राप्त करने देती है. इस स्थान को सेल टॉवर और Wi-Fi जैसे नेटवर्क स्थान स्रोतों का उपयोग करके स्थान सेवाओं द्वारा प्राप्त किया गया है. एप्लिकेशन द्वारा इन स्थान सेवाओं का उपयोग करने के लिए इन्हें चालू होना चाहिए और आपके उपकरण में उपलब्ध होना चाहिए. एप्लिकेशन इसका उपयोग यह पता लगाने में कर सकते हैं कि आप लगभग कहां पर हैं."</string>
+ <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"एप्स को आपका अनुमानित स्थान प्राप्त करने देती है. इस स्थान को सेल टॉवर और Wi-Fi जैसे नेटवर्क स्थान स्रोतों का उपयोग करके स्थान सेवाओं द्वारा प्राप्त किया गया है. एप्स द्वारा इन स्थान सेवाओं का उपयोग करने के लिए इन्हें चालू होना चाहिए और आपके उपकरण में उपलब्ध होना चाहिए. एप्स इसका उपयोग यह पता लगाने में कर सकते हैं कि आप लगभग कहां पर हैं."</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"SurfaceFlinger में पहुंचें"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"एप्लिकेशन को SurfaceFlinger निम्न-स्तर सुविधाएं उपयोग करने देता है."</string>
+ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"एप्स को SurfaceFlinger निम्न-स्तर सुविधाएं उपयोग करने देता है."</string>
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"फ़्रेम बफ़र पढ़ें"</string>
- <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"एप्लिकेशन को फ़्रेम बफ़र की सामग्री पढ़ने देता है."</string>
+ <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"एप्स को फ़्रेम बफ़र की सामग्री पढ़ने देता है."</string>
<string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Wifi डिस्प्ले को कॉन्फ़िगर करें"</string>
- <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"एप्लिकेशन को कॉन्फ़िगर करने देता है और Wifi डिस्प्ले से कनेक्ट करता है."</string>
+ <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"एप्स को कॉन्फ़िगर करने देता है और Wifi डिस्प्ले से कनेक्ट करता है."</string>
<string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wifi डिस्प्ले को नियंत्रित करें"</string>
- <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"एप्लिकेशन को Wifi डिस्प्ले की निम्न-स्तर की सुविधाएं नियंत्रित करने देता है."</string>
+ <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"एप्स को Wifi डिस्प्ले की निम्न-स्तर की सुविधाएं नियंत्रित करने देता है."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ऑडियो आउटपुट को कैप्चर करें"</string>
- <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"एप्लिकेशन को ऑडियो आउटपुट को कैप्चर और रीडायरेक्ट करने देता है."</string>
+ <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"एप्स को ऑडियो आउटपुट को कैप्चर और रीडायरेक्ट करने देता है."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"हॉटवर्ड पहचान"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"एप्लिकेशन को हॉटवर्ड पहचान के लिए ऑडियो कैप्चर करने देती है. कैप्चर पृष्ठभूमि में हो सकता है लेकिन वह अन्य ऑडियो कैप्चर (उदा. कैमकॉर्डर) को नहीं रोकता."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"वीडियो आउटपुट को कैप्चर करें"</string>
- <string name="permdesc_captureVideoOutput" msgid="359481658034149860">"एप्लिकेशन को वीडियो आउटपुट को कैप्चर और रीडायरेक्ट करने देता है."</string>
+ <string name="permdesc_captureVideoOutput" msgid="359481658034149860">"एप्स को वीडियो आउटपुट को कैप्चर और रीडायरेक्ट करने देता है."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"सुरक्षित वीडियो आउटपुट को कैप्चर करें"</string>
- <string name="permdesc_captureSecureVideoOutput" msgid="2779793064709350289">"एप्लिकेशन को सुरक्षित वीडियो आउटपुट को कैप्चर और रीडायरेक्ट करने देता है."</string>
+ <string name="permdesc_captureSecureVideoOutput" msgid="2779793064709350289">"एप्स को सुरक्षित वीडियो आउटपुट को कैप्चर और रीडायरेक्ट करने देता है."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"अपनी ऑडियो सेटिंग बदलें"</string>
- <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"एप्लिकेशन को वैश्विक ऑडियो सेटिंग, जैसे वॉल्यूम और कौन-सा स्पीकर आउटपुट के लिए उपयोग किया गया, संशोधित करने देता है."</string>
+ <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"एप्स को वैश्विक ऑडियो सेटिंग, जैसे वॉल्यूम और कौन-सा स्पीकर आउटपुट के लिए उपयोग किया गया, संशोधित करने देता है."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"ऑडियो रिकॉर्ड करें"</string>
- <string name="permdesc_recordAudio" msgid="4906839301087980680">"एप्लिकेशन को माइक्रोफ़ोन द्वारा ऑडियो रिकार्ड करने देता है. यह अनुमति एप्लिकेशन को आपकी पुष्टि के बिना किसी भी समय ऑडियो रिकार्ड करने देती है."</string>
+ <string name="permdesc_recordAudio" msgid="4906839301087980680">"एप्स को माइक्रोफ़ोन द्वारा ऑडियो रिकार्ड करने देता है. यह अनुमति एप्स को आपकी पुष्टि के बिना किसी भी समय ऑडियो रिकार्ड करने देती है."</string>
<string name="permlab_camera" msgid="3616391919559751192">"चित्र और वीडियो लें"</string>
- <string name="permdesc_camera" msgid="8497216524735535009">"एप्लिकेशन को कैमरे से चित्र और वीडियो लेने देता है. यह अनुमति एप्लिकेशन को किसी भी समय आपकी पुष्टि के बिना कैमरे का उपयोग करने देती है."</string>
+ <string name="permdesc_camera" msgid="8497216524735535009">"एप्स को कैमरे से चित्र और वीडियो लेने देता है. यह अनुमति एप्स को किसी भी समय आपकी पुष्टि के बिना कैमरे का उपयोग करने देती है."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"कैमरा उपयोग में होने पर संचारण संकेतक LED अक्षम करें"</string>
- <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"पहले से इंस्टॉल किए गए सिस्टम एप्लिकेशन को कैमरे को संकेतक LED का उपयोग करने से अक्षम करती है."</string>
+ <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"पहले से इंस्टॉल किए गए सिस्टम एप्स को कैमरे को संकेतक LED का उपयोग करने से अक्षम करती है."</string>
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"स्थायी रूप से टेबलेट अक्षम करें"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"फ़ोन को स्थायी रूप से अक्षम करें"</string>
- <string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"एप्लिकेशन को संपूर्ण टेबलेट को स्थायी रूप से अक्षम करने देता है. यह बहुत खतरनाक है."</string>
- <string name="permdesc_brick" product="default" msgid="5788903297627283099">"एप्लिकेशन को संपूर्ण फ़ोन को स्थायी रूप से अक्षम करने देता है. यह बहुत खतरनाक है."</string>
+ <string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"एप्स को संपूर्ण टेबलेट को स्थायी रूप से अक्षम करने देता है. यह बहुत खतरनाक है."</string>
+ <string name="permdesc_brick" product="default" msgid="5788903297627283099">"एप्स को संपूर्ण फ़ोन को स्थायी रूप से अक्षम करने देता है. यह बहुत खतरनाक है."</string>
<string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"टेबलेट रीबूट के लिए बाध्य करें"</string>
<string name="permlab_reboot" product="default" msgid="2898560872462638242">"फ़ोन रीबूट के लिए बाध्य करें"</string>
- <string name="permdesc_reboot" product="tablet" msgid="8172056180063700741">"एप्लिकेशन को टेबलेट रीबूट करने के लिए बाध्य करने देता है."</string>
- <string name="permdesc_reboot" product="default" msgid="5326008124289989969">"एप्लिकेशन को फ़ोन बलपूर्वक रीबूट करने देता है."</string>
+ <string name="permdesc_reboot" product="tablet" msgid="8172056180063700741">"एप्स को टेबलेट रीबूट करने के लिए बाध्य करने देता है."</string>
+ <string name="permdesc_reboot" product="default" msgid="5326008124289989969">"एप्स को फ़ोन बलपूर्वक रीबूट करने देता है."</string>
<string name="permlab_mount_unmount_filesystems" product="nosdcard" msgid="2927361537942591841">"USB संग्रहण फ़ाइल सिस्टम पर पहुंचें"</string>
<string name="permlab_mount_unmount_filesystems" product="default" msgid="4402305049890953810">"SD कार्ड फ़ाइल सिस्टम पर पहुंचें"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="1829290701658992347">"एप्लिकेशन को निकाले जाने योग्य संग्रहण के लिए फ़ाइल सिस्टम माउंट और अनमाउंट करने देता है."</string>
+ <string name="permdesc_mount_unmount_filesystems" msgid="1829290701658992347">"एप्स को निकाले जाने योग्य संग्रहण के लिए फ़ाइल सिस्टम माउंट और अनमाउंट करने देता है."</string>
<string name="permlab_mount_format_filesystems" product="nosdcard" msgid="6227819582624904972">"USB संग्रहण मिटाएं"</string>
<string name="permlab_mount_format_filesystems" product="default" msgid="262582698639274056">"SD कार्ड मिटाएं"</string>
- <string name="permdesc_mount_format_filesystems" msgid="8784268246779198627">"एप्लिकेशन को निकालने योग्य संग्रहण फ़ॉर्मेट करने देता है."</string>
+ <string name="permdesc_mount_format_filesystems" msgid="8784268246779198627">"एप्स को निकालने योग्य संग्रहण फ़ॉर्मेट करने देता है."</string>
<string name="permlab_asec_access" msgid="3411338632002193846">"मोबाइल संग्रहण पर जानकारी प्राप्त करें"</string>
- <string name="permdesc_asec_access" msgid="3094563844593878548">"एप्लिकेशन को मोबाइल संग्रहण की जानकारी प्राप्त करने देता है."</string>
+ <string name="permdesc_asec_access" msgid="3094563844593878548">"एप्स को मोबाइल संग्रहण की जानकारी प्राप्त करने देता है."</string>
<string name="permlab_asec_create" msgid="6414757234789336327">"मोबाइल संग्रहण बनाएं"</string>
- <string name="permdesc_asec_create" msgid="4558869273585856876">"एप्लिकेशन को मोबाइल संग्रहण बनाने देता है."</string>
+ <string name="permdesc_asec_create" msgid="4558869273585856876">"एप्स को मोबाइल संग्रहण बनाने देता है."</string>
<string name="permlab_asec_destroy" msgid="526928328301618022">"मोबाइल संग्रहण नष्ट करें"</string>
- <string name="permdesc_asec_destroy" msgid="7218749286145526537">"एप्लिकेशन को मोबाइल संग्रहण नष्ट करने देता है."</string>
+ <string name="permdesc_asec_destroy" msgid="7218749286145526537">"एप्स को मोबाइल संग्रहण नष्ट करने देता है."</string>
<string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"मोबाइल संग्रहण माउंट/अनमाउंट करें"</string>
- <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"एप्लिकेशन को मोबाइल संग्रहण माउंट/अनमाउंट करने देता है."</string>
+ <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"एप्स को मोबाइल संग्रहण माउंट/अनमाउंट करने देता है."</string>
<string name="permlab_asec_rename" msgid="7496633954080472417">"मोबाइल संग्रहण का नाम बदलें"</string>
- <string name="permdesc_asec_rename" msgid="1794757588472127675">"एप्लिकेशन को मोबाइल संग्रहण का नाम बदलने देता है."</string>
+ <string name="permdesc_asec_rename" msgid="1794757588472127675">"एप्स को मोबाइल संग्रहण का नाम बदलने देता है."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"कंपन नियंत्रित करें"</string>
- <string name="permdesc_vibrate" msgid="6284989245902300945">"एप्लिकेशन को कंपनकर्ता नियंत्रित करने देता है."</string>
+ <string name="permdesc_vibrate" msgid="6284989245902300945">"एप्स को कंपनकर्ता नियंत्रित करने देता है."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"फ़्लैशलाइट नियंत्रित करें"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"एप्लिकेशन को फ़्लैशलाइट नियंत्रित करने देता है."</string>
+ <string name="permdesc_flashlight" msgid="6522284794568368310">"एप्स को फ़्लैशलाइट नियंत्रित करने देता है."</string>
<string name="permlab_manageUsb" msgid="1113453430645402723">"USB उपकरणों की प्राथमिकताएं और अनुमतियां प्रबंधित करें"</string>
- <string name="permdesc_manageUsb" msgid="7776155430218239833">"एप्लिकेशन को USB उपकरणों की प्राथमिकताओं और अनुमतियों को प्रबंधित करने देता है."</string>
+ <string name="permdesc_manageUsb" msgid="7776155430218239833">"एप्स को USB उपकरणों की प्राथमिकताओं और अनुमतियों को प्रबंधित करने देता है."</string>
<string name="permlab_accessMtp" msgid="4953468676795917042">"MTP प्रोटोकॉल लागू करें"</string>
<string name="permdesc_accessMtp" msgid="6532961200486791570">"MTP USB प्रोटोकॉल लागू करने के लिए कर्नेल MTP ड्राइवर में पहुंच की अनुमति देता है."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"परीक्षण हार्डवेयर"</string>
- <string name="permdesc_hardware_test" msgid="6597964191208016605">"एप्लिकेशन को हार्डवेयर परीक्षण के लिए विविध सहायक उपकरणों को नियंत्रित करने देता है."</string>
+ <string name="permdesc_hardware_test" msgid="6597964191208016605">"एप्स को हार्डवेयर परीक्षण के लिए विविध सहायक उपकरणों को नियंत्रित करने देता है."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"फ़ोन नंबर पर सीधे कॉल करें"</string>
- <string name="permdesc_callPhone" msgid="3740797576113760827">"एप्लिकेशन को आपके हस्तक्षेप के बिना फ़ोन नंबर पर कॉल करने देता है. इसके परिणाम अप्रत्याशित शुल्क या कॉल हो सकते हैं. ध्यान दें कि यह एप्लिकेशन को आपातकालीन नंबर पर कॉल नहीं करने देता. दुर्भावनापूर्ण एप्लिकेशन आपकी पुष्टि के बिना कॉल करके आपका धन व्यय कर सकते हैं."</string>
+ <string name="permdesc_callPhone" msgid="3740797576113760827">"एप्स को आपके हस्तक्षेप के बिना फ़ोन नंबर पर कॉल करने देता है. इसके परिणाम अप्रत्याशित शुल्क या कॉल हो सकते हैं. ध्यान दें कि यह एप्स को आपातकालीन नंबर पर कॉल नहीं करने देता. दुर्भावनापूर्ण एप्स आपकी पुष्टि के बिना कॉल करके आपका धन व्यय कर सकते हैं."</string>
<string name="permlab_callPrivileged" msgid="4198349211108497879">"किसी भी फ़ोन नंबर पर सीधे कॉल करें"</string>
- <string name="permdesc_callPrivileged" msgid="1689024901509996810">"एप्लिकेशन को आपके हस्तक्षेप के बिना आपातकालीन नंबरों सहित, किसी भी फ़ोन नंबर पर कॉल करने देता है. दुर्भावनापूर्ण एप्लिकेशन आपातकालीन सेवाओं पर अनावश्यक और अवैध कॉल कर सकते हैं."</string>
+ <string name="permdesc_callPrivileged" msgid="1689024901509996810">"एप्स को आपके हस्तक्षेप के बिना आपातकालीन नंबरों सहित, किसी भी फ़ोन नंबर पर कॉल करने देता है. दुर्भावनापूर्ण एप्स आपातकालीन सेवाओं पर अनावश्यक और अवैध कॉल कर सकते हैं."</string>
<string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"सीधे CDMA टेबलेट सेटअप प्रारंभ करें"</string>
<string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"सीधे CDMA फ़ोन सेटअप प्रारंभ करें"</string>
- <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"एप्लिकेशन को CDMA प्रावधान प्रारंभ करने देता है. दुर्भावनापूर्ण एप्लिकेशन अनावश्यक रूप से CDMA प्रावधान प्रारंभ कर सकते हैं."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"स्थान अपडेट सूचनाएं नियंत्रित करें"</string>
- <string name="permdesc_locationUpdates" msgid="1120741557891438876">"एप्लिकेशन को रेडियो से स्थान अपडेट सूचनाएं सक्षम/अक्षम करने देता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"एप्स को CDMA प्रावधान प्रारंभ करने देता है. दुर्भावनापूर्ण एप्स अनावश्यक रूप से CDMA प्रावधान प्रारंभ कर सकते हैं."</string>
+ <string name="permlab_locationUpdates" msgid="7785408253364335740">"स्थान के बारे में नई जानकारी की सूचनाओं को नियंत्रित करें"</string>
+ <string name="permdesc_locationUpdates" msgid="1120741557891438876">"एप को रेडियो से स्थान के बारे में नई जानकारी की सूचनाएं सक्षम/अक्षम करने देता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_checkinProperties" msgid="7855259461268734914">"चेकइन गुणों में पहुंचें"</string>
- <string name="permdesc_checkinProperties" msgid="4024526968630194128">"एप्लिकेशन को चेकइन सेवा द्वारा अपलोड किए गए गुणों पर पढ़ें/लिखें पहुंच देता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permdesc_checkinProperties" msgid="4024526968630194128">"एप्स को चेकइन सेवा द्वारा अपलोड किए गए गुणों पर पढ़ें/लिखें पहुंच देता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_bindGadget" msgid="776905339015863471">"विजेट चुनें"</string>
- <string name="permdesc_bindGadget" msgid="8261326938599049290">"एप्लिकेशन को सिस्टम को यह बताने देता है कि किस एप्लिकेशन द्वारा कौन से विजेट का उपयोग किया जा सकता है. कोई एप्लिकेशन, इस अनुमति के साथ अन्य एप्लिकेशन के निजी डेटा पर पहुंच सकते हैं. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permdesc_bindGadget" msgid="8261326938599049290">"एप्स को सिस्टम को यह बताने देता है कि किस एप्स द्वारा कौन से विजेट का उपयोग किया जा सकता है. कोई एप्स, इस अनुमति के साथ अन्य एप्स के निजी डेटा पर पहुंच सकते हैं. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_modifyPhoneState" msgid="8423923777659292228">"फ़ोन स्थिति बदलें"</string>
- <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"एप्लिकेशन को उपकरण की फ़ोन सुविधाएं नियंत्रित करने देता है. इस अनुमति वाला कोई एप्लिकेशन आपको सूचित किए बिना नेटवर्क स्विच कर सकता है, फ़ोन का रेडियो चालू और बंद कर सकता है और ऐसे ही अन्य कार्य कर सकता है."</string>
+ <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"एप्स को उपकरण की फ़ोन सुविधाएं नियंत्रित करने देता है. इस अनुमति वाला कोई एप्स आपको सूचित किए बिना नेटवर्क स्विच कर सकता है, फ़ोन का रेडियो चालू और बंद कर सकता है और ऐसे ही अन्य कार्य कर सकता है."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"फ़ोन की स्थिति और पहचान पढ़ें"</string>
- <string name="permdesc_readPhoneState" msgid="1639212771826125528">"एप्लिकेशन को उपकरण की फ़ोन सुविधाओं तक पहुंचने देता है. यह अनुमति एप्लिकेशन को फ़ोन नंबर और उपकरण आईडी, कॉल सक्रिय है या नहीं, और कॉल द्वारा कनेक्ट किया गया दूरस्थ नंबर निर्धारित करने देती है."</string>
+ <string name="permdesc_readPhoneState" msgid="1639212771826125528">"एप्स को उपकरण की फ़ोन सुविधाओं तक पहुंचने देता है. यह अनुमति एप्स को फ़ोन नंबर और उपकरण आईडी, कॉल सक्रिय है या नहीं, और कॉल द्वारा कनेक्ट किया गया दूरस्थ नंबर निर्धारित करने देती है."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"टेबलेट को निष्क्रिय होने से रोकें"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"फ़ोन को निष्क्रिय होने से रोकें"</string>
- <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"एप्लिकेशन को टेबलेट को प्रयोग में नहीं हो जाने से रोकता है."</string>
- <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"एप्लिकेशन को फ़ोन को प्रयोग में नहीं होने से रोकता है."</string>
+ <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"एप्स को टेबलेट को प्रयोग में नहीं हो जाने से रोकता है."</string>
+ <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"एप्स को फ़ोन को प्रयोग में नहीं होने से रोकता है."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"इंफ़्रारेड संचारित करें"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"एप्लिकेशन को टेबलेट के इंफ़्रारेड ट्रांसमीटर का उपयोग करने देती है."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"एप्लिकेशन को फ़ोन के इंफ़्रारेड ट्रांसमीटर का उपयोग करने देती है."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"टेबलेट चालू या बंद करें"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"फ़ोन चालू या बंद करें"</string>
- <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"एप्लिकेशन को टेबलेट चालू या बंद करने देता है."</string>
- <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"एप्लिकेशन को फ़ोन चालू या बंद करने देता है."</string>
+ <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"एप्स को टेबलेट चालू या बंद करने देता है."</string>
+ <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"एप्स को फ़ोन चालू या बंद करने देता है."</string>
<string name="permlab_factoryTest" msgid="3715225492696416187">"फ़ैक्ट्री परीक्षण मोड में चलाएं"</string>
<string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"टेबलेट हार्डवेयर में पूर्ण पहुंच की अनुमति देते हुए निम्न-स्तर निर्माता परीक्षण के रूप में चलाएं. केवल तभी उपलब्ध जब कोई टेबलेट निर्माता परीक्षण मोड में चल रहा हो."</string>
<string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"फ़ोन हार्डवेयर में पूर्ण पहुंच की अनुमति देते हुए निम्न-स्तर निर्माता परीक्षण के रूप में चलाएं. केवल तभी उपलब्ध जब कोई फ़ोन निर्माता परीक्षण मोड में चल रहा हो."</string>
<string name="permlab_setWallpaper" msgid="6627192333373465143">"वॉलपेपर सेट करें"</string>
- <string name="permdesc_setWallpaper" msgid="7373447920977624745">"एप्लिकेशन को सिस्टम वॉलपेपर सेट करने देता है."</string>
+ <string name="permdesc_setWallpaper" msgid="7373447920977624745">"एप्स को सिस्टम वॉलपेपर सेट करने देता है."</string>
<string name="permlab_setWallpaperHints" msgid="3278608165977736538">"अपने वॉलपेपर का आकार एडजस्ट करें"</string>
- <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"एप्लिकेशन को सिस्टम वॉलपेपर आकार संकेत सेट करने देता है."</string>
+ <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"एप्स को सिस्टम वॉलपेपर आकार संकेत सेट करने देता है."</string>
<string name="permlab_masterClear" msgid="2315750423139697397">"फ़ैक्ट्री डिफ़ॉल्ट पर सिस्टम रीसेट करें"</string>
- <string name="permdesc_masterClear" msgid="3665380492633910226">"एप्लिकेशन को सभी डेटा, कॉन्फ़िगरेशन, और इंस्टॉल एप्लिकेशन मिटाकर, सिस्टम को पूरी तरह उसकी फ़ैक्टरी सेटिंग पर रीसेट करने देता है."</string>
+ <string name="permdesc_masterClear" msgid="3665380492633910226">"एप्स को सभी डेटा, कॉन्फ़िगरेशन, और इंस्टॉल एप्स मिटाकर, सिस्टम को पूरी तरह उसकी फ़ैक्टरी सेटिंग पर रीसेट करने देता है."</string>
<string name="permlab_setTime" msgid="2021614829591775646">"समय सेट करें"</string>
- <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"एप्लिकेशन को टेबलेट की घड़ी का समय बदलने देता है."</string>
- <string name="permdesc_setTime" product="default" msgid="1855702730738020">"एप्लिकेशन को फ़ोन की घड़ी का समय बदलने देता है."</string>
+ <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"एप्स को टेबलेट की घड़ी का समय बदलने देता है."</string>
+ <string name="permdesc_setTime" product="default" msgid="1855702730738020">"एप्स को फ़ोन की घड़ी का समय बदलने देता है."</string>
<string name="permlab_setTimeZone" msgid="2945079801013077340">"समय क्षेत्र सेट करें"</string>
- <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"एप्लिकेशन को टेबलेट का समय क्षेत्र बदलने देता है."</string>
- <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"एप्लिकेशन को टेबलेट का समय क्षेत्र बदलने देता है."</string>
+ <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"एप्स को टेबलेट का समय क्षेत्र बदलने देता है."</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"एप्स को टेबलेट का समय क्षेत्र बदलने देता है."</string>
<string name="permlab_accountManagerService" msgid="4829262349691386986">"खाता प्रबंधक सेवा के रूप में कार्य करें"</string>
- <string name="permdesc_accountManagerService" msgid="1948455552333615954">"एप्लिकेशन को खाता प्रमाणकों को कॉल करने देता है."</string>
+ <string name="permdesc_accountManagerService" msgid="1948455552333615954">"एप्स को खाता प्रमाणकों को कॉल करने देता है."</string>
<string name="permlab_getAccounts" msgid="1086795467760122114">"उपकरण पर खाते ढूंढें"</string>
- <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"एप्लिकेशन को टेबलेट द्वारा ज्ञात खातों की सूची प्राप्त करने देता है. इसमें वे खाते शामिल हो सकते हैं जिन्हें आपके द्वारा इंस्टॉल किए गए एप्लिकेशन ने बनाया है."</string>
- <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"एप्लिकेशन को फ़ोन द्वारा ज्ञात खातों की सूची प्राप्त करने देता है. इसमें वे खाते शामिल हो सकते हैं जिन्हें आपके द्वारा इंस्टॉल किए गए एप्लिकेशन ने बनाया है."</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"एप्स को टेबलेट द्वारा ज्ञात खातों की सूची प्राप्त करने देता है. इसमें वे खाते शामिल हो सकते हैं जिन्हें आपके द्वारा इंस्टॉल किए गए एप्स ने बनाया है."</string>
+ <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"एप्स को फ़ोन द्वारा ज्ञात खातों की सूची प्राप्त करने देता है. इसमें वे खाते शामिल हो सकते हैं जिन्हें आपके द्वारा इंस्टॉल किए गए एप्स ने बनाया है."</string>
<string name="permlab_authenticateAccounts" msgid="5265908481172736933">"खाते बनाएं और पासवर्ड सेट करें"</string>
<string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"एप्िलकेशन को खाता बनाने और उनके पासवर्ड प्राप्त करने और सेट करने सहित, खाता प्रबंधक की खाता प्रमाणक क्षमताओं का उपयोग करने देता है."</string>
<string name="permlab_manageAccounts" msgid="4983126304757177305">"खाते जोडें या निकालें"</string>
- <string name="permdesc_manageAccounts" msgid="8698295625488292506">"एप्लिकेशन को खाते जोड़ना और निकालना और उनके पासवर्ड हटाने जैसे कार्य करने देता है."</string>
+ <string name="permdesc_manageAccounts" msgid="8698295625488292506">"एप्स को खाते जोड़ना और निकालना और उनके पासवर्ड हटाने जैसे कार्य करने देता है."</string>
<string name="permlab_useCredentials" msgid="235481396163877642">"उपकरण पर खातों का उपयोग करें"</string>
- <string name="permdesc_useCredentials" msgid="7984227147403346422">"एप्लिकेशन को प्रमाणीकरण टोकन का अनुरोध करने देता है."</string>
+ <string name="permdesc_useCredentials" msgid="7984227147403346422">"एप्स को प्रमाणीकरण टोकन का अनुरोध करने देता है."</string>
<string name="permlab_accessNetworkState" msgid="4951027964348974773">"नेटवर्क कनेक्शन देखें"</string>
- <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"एप्लिकेशन को नेटवर्क कनेक्शन के बारे में जानकारी देखने देता है जैसे कौन से नेटवर्क मौजूद हैं और कनेक्ट हैं."</string>
+ <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"एप्स को नेटवर्क कनेक्शन के बारे में जानकारी देखने देता है जैसे कौन से नेटवर्क मौजूद हैं और कनेक्ट हैं."</string>
<string name="permlab_createNetworkSockets" msgid="8018758136404323658">"पूर्ण नेटवर्क पहुंच"</string>
- <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"एप्लिकेशन को नेटवर्क सॉकेट बनाने और कस्टम नेटवर्क प्रोटोकॉल का उपयोग करने देता है. ब्राउज़र और अन्य एप्लिकेशन इंटरनेट को डेटा भेजने के साधन उपलब्ध कराते हैं, ताकि इंटरनेट को डेटा भेजने के लिए इस अनुमति की आवश्यकता नहीं हो."</string>
+ <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"एप्स को नेटवर्क सॉकेट बनाने और कस्टम नेटवर्क प्रोटोकॉल का उपयोग करने देता है. ब्राउज़र और अन्य एप्स इंटरनेट को डेटा भेजने के साधन उपलब्ध कराते हैं, ताकि इंटरनेट को डेटा भेजने के लिए इस अनुमति की आवश्यकता नहीं हो."</string>
<string name="permlab_writeApnSettings" msgid="505660159675751896">"नेटवर्क सेटिंग और ट्रैफ़िक बदलें/रोकें"</string>
- <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"एप्लिकेशन को नेटवर्क सेटिंग बदलने और सभी ट्रैफ़िक नेटवर्क को बाधित और निरीक्षण करने देता है, उदाहरण के लिए किसी APN का प्रॉक्सी और पोर्ट बदलना. दुर्भावनापूर्ण एप्लिकेशन आपकी जानकारी के बिना नेटवर्क पैकेट की निगरानी कर सकते हैं, उन्हें रीडायरेक्ट, या संशोधित कर सकते हैं."</string>
+ <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"एप्स को नेटवर्क सेटिंग बदलने और सभी ट्रैफ़िक नेटवर्क को बाधित और निरीक्षण करने देता है, उदाहरण के लिए किसी APN का प्रॉक्सी और पोर्ट बदलना. दुर्भावनापूर्ण एप्स आपकी जानकारी के बिना नेटवर्क पैकेट की निगरानी कर सकते हैं, उन्हें रीडायरेक्ट, या संशोधित कर सकते हैं."</string>
<string name="permlab_changeNetworkState" msgid="958884291454327309">"नेटवर्क कनेक्टिविटी बदलें"</string>
- <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"एप्लिकेशन को नेटवर्क कनेक्टिविटी की स्थिति बदलने देता है."</string>
+ <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"एप्स को नेटवर्क कनेक्टिविटी की स्थिति बदलने देता है."</string>
<string name="permlab_changeTetherState" msgid="5952584964373017960">"टेदर की गई कनेक्टिविटी बदलें"</string>
- <string name="permdesc_changeTetherState" msgid="1524441344412319780">"एप्लिकेशन को टेदर की गई नेटवर्क कनेक्टिविटी की स्थिति बदलने देता है."</string>
+ <string name="permdesc_changeTetherState" msgid="1524441344412319780">"एप्स को टेदर की गई नेटवर्क कनेक्टिविटी की स्थिति बदलने देता है."</string>
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"पृष्ठभूमि डेटा उपयोग सेटिंग बदलें"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"एप्लिकेशन को पृष्ठभूमि डेटा उपयोग सेटिंग बदलने देता है."</string>
+ <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"एप्स को पृष्ठभूमि डेटा उपयोग सेटिंग बदलने देता है."</string>
<string name="permlab_accessWifiState" msgid="5202012949247040011">"Wi-Fi कनेक्शन देखें"</string>
- <string name="permdesc_accessWifiState" msgid="5002798077387803726">"एप्लिकेशन को Wi-Fi नेटवर्क के बारे में जानकारी, जैसे WI-Fi सक्षम है या नहीं और कनेक्ट किए गए Wi-Fi उपकरणों के नाम, देखने देता है."</string>
+ <string name="permdesc_accessWifiState" msgid="5002798077387803726">"एप्स को Wi-Fi नेटवर्क के बारे में जानकारी, जैसे WI-Fi सक्षम है या नहीं और कनेक्ट किए गए Wi-Fi उपकरणों के नाम, देखने देता है."</string>
<string name="permlab_changeWifiState" msgid="6550641188749128035">"Wi-Fi से कनेक्ट और डिस्कनेक्ट करें"</string>
- <string name="permdesc_changeWifiState" msgid="7137950297386127533">"एप्लिकेशन को Wi-Fi पहुंच बिंदुओं से कनेक्ट और डिस्कनेक्ट करने और Wi-Fi नेटवर्क के लिए उपकरण कॉन्फ़िगरेशन में परिवर्तन करने देता है."</string>
+ <string name="permdesc_changeWifiState" msgid="7137950297386127533">"एप्स को Wi-Fi पहुंच बिंदुओं से कनेक्ट और डिस्कनेक्ट करने और Wi-Fi नेटवर्क के लिए उपकरण कॉन्फ़िगरेशन में परिवर्तन करने देता है."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Wi-Fi मल्टीकास्ट प्राप्ति को अनुमति दें"</string>
- <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"एप्लिकेशन को Wi-Fi नेटवर्क पर मल्टीकास्ट पते के उपयोग से केवल आपके टेबलेट पर ही नहीं, बल्कि सभी उपकरणों पर भेजे गए पैकेट प्राप्त करने देता है. यह गैर-मल्टीकास्ट मोड से अधिक पावर का उपयोग करता है."</string>
- <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"एप्लिकेशन को Wi-Fi नेटवर्क पर मल्टीकास्ट पते के उपयोग से केवल आपके फ़ोन पर ही नहीं, बल्कि सभी उपकरणों पर भेजे गए पैकेट प्राप्त करने देता है. यह गैर-मल्टीकास्ट मोड से अधिक पावर का उपयोग करता है."</string>
+ <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"एप्स को Wi-Fi नेटवर्क पर मल्टीकास्ट पते के उपयोग से केवल आपके टेबलेट पर ही नहीं, बल्कि सभी उपकरणों पर भेजे गए पैकेट प्राप्त करने देता है. यह गैर-मल्टीकास्ट मोड से अधिक पावर का उपयोग करता है."</string>
+ <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"एप्स को Wi-Fi नेटवर्क पर मल्टीकास्ट पते के उपयोग से केवल आपके फ़ोन पर ही नहीं, बल्कि सभी उपकरणों पर भेजे गए पैकेट प्राप्त करने देता है. यह गैर-मल्टीकास्ट मोड से अधिक पावर का उपयोग करता है."</string>
<string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"Bluetooth सेटिंग पर पहुंचें"</string>
- <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"किसी एप्लिकेशन को स्थानीय Bluetooth टेबलेट कॉन्फ़िगर करने की और रिमोट उपकरणों के साथ खोजने और युग्मित करने देता है."</string>
- <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"एप्लिकेशन को स्थानीय Bluetooth फ़ोन कॉन्फ़िगर करने देता है, और रिमोट उपकरणों के साथ खोजने और युग्मित करने देता है."</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"किसी एप्स को स्थानीय Bluetooth टेबलेट कॉन्फ़िगर करने की और रिमोट उपकरणों के साथ खोजने और युग्मित करने देता है."</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"एप्स को स्थानीय Bluetooth फ़ोन कॉन्फ़िगर करने देता है, और रिमोट उपकरणों के साथ खोजने और युग्मित करने देता है."</string>
<string name="permlab_accessWimaxState" msgid="4195907010610205703">"WiMAX से कनेक्ट और डिस्कनेक्ट करें"</string>
- <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"एप्लिकेशन को WiMAX सक्षम है या नहीं और कनेक्ट किए गए किसी WiMAX नेटवर्क के बारे में जानकारी निर्धारित करने देता है."</string>
+ <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"एप्स को WiMAX सक्षम है या नहीं और कनेक्ट किए गए किसी WiMAX नेटवर्क के बारे में जानकारी निर्धारित करने देता है."</string>
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX स्थिति बदलें"</string>
- <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"एप्लिकेशन को WiMAX नेटवर्क से टेबलेट को कनेक्ट और डिस्कनेक्ट करने देता है."</string>
- <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"एप्लिकेशन को WiMAX नेटवर्क से फ़ोन को कनेक्ट और डिस्कनेक्ट करने देता है."</string>
+ <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"एप्स को WiMAX नेटवर्क से टेबलेट को कनेक्ट और डिस्कनेक्ट करने देता है."</string>
+ <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"एप्स को WiMAX नेटवर्क से फ़ोन को कनेक्ट और डिस्कनेक्ट करने देता है."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetooth उपकरणों के साथ युग्मित करें"</string>
- <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"एप्लिकेशन को टेबलेट पर Bluetooth का कॉन्फ़िगरेशन देखने, और युग्मित उपकरणों के साथ कनेक्शन बनाने और स्वीकार करने देता है."</string>
- <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"एप्लिकेशन को फ़ोन पर Bluetooth का कॉन्फ़िगरेशन देखने, और युग्मित उपकरणों के साथ कनेक्शन बनाने और स्वीकार करने देता है."</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"एप्स को टेबलेट पर Bluetooth का कॉन्फ़िगरेशन देखने, और युग्मित उपकरणों के साथ कनेक्शन बनाने और स्वीकार करने देता है."</string>
+ <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"एप्स को फ़ोन पर Bluetooth का कॉन्फ़िगरेशन देखने, और युग्मित उपकरणों के साथ कनेक्शन बनाने और स्वीकार करने देता है."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"नियर फ़ील्ड कम्यूनिकेशन नियंत्रित करें"</string>
- <string name="permdesc_nfc" msgid="7120611819401789907">"एप्लिकेशन को नियर फ़ील्ड कम्यूनिकेशन (NFC) टैग, कार्ड, और रीडर के साथ संचार करने देता है."</string>
+ <string name="permdesc_nfc" msgid="7120611819401789907">"एप्स को नियर फ़ील्ड कम्यूनिकेशन (NFC) टैग, कार्ड, और रीडर के साथ संचार करने देता है."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"अपना स्क्रीन लॉक अक्षम करें"</string>
- <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"एप्लिकेशन को कीलॉक और कोई भी संबद्ध पासवर्ड सुरक्षा अक्षम करने देता है. उदाहरण के लिए, इनकमिंग फ़ोन कॉल प्राप्त करते समय फ़ोन, कीलॉक को अक्षम कर देता है, फिर कॉल समाप्त होने पर कीलॉक को पुन: सक्षम कर देता है."</string>
+ <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"एप्स को कीलॉक और कोई भी संबद्ध पासवर्ड सुरक्षा अक्षम करने देता है. उदाहरण के लिए, इनकमिंग फ़ोन कॉल प्राप्त करते समय फ़ोन, कीलॉक को अक्षम कर देता है, फिर कॉल समाप्त होने पर कीलॉक को पुन: सक्षम कर देता है."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"समन्वयन सेटिंग पढ़ें"</string>
- <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"एप्लिकेशन को किसी खाते की समन्वयन सेटिंग पढ़ने देता है. उदाहरण के लिए, इससे यह निर्धारित किया जा सकता है कि लोग एप्लिकेशन किसी खाते के साथ समन्वयित है या नहीं."</string>
+ <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"एप्स को किसी खाते की समन्वयन सेटिंग पढ़ने देता है. उदाहरण के लिए, इससे यह निर्धारित किया जा सकता है कि लोग एप्स किसी खाते के साथ समन्वयित है या नहीं."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"समन्वयन बंद या चालू टॉगल करें"</string>
- <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"एप्लिकेशन को किसी खाते की समन्वयन सेटिंग संशोधित करने देता है. उदाहरण के लिए, इसका उपयोग लोग एप्लिकेशन का समन्वयन किसी खाते से सक्षम करने में हो सकता है."</string>
+ <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"एप्स को किसी खाते की समन्वयन सेटिंग संशोधित करने देता है. उदाहरण के लिए, इसका उपयोग लोग एप्स का समन्वयन किसी खाते से सक्षम करने में हो सकता है."</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"समन्वयन आंकड़े पढ़ें"</string>
- <string name="permdesc_readSyncStats" msgid="1510143761757606156">"एप्लिकेशन को किसी खाते के समन्वयन आंकड़े, साथ ही समन्वयित ईवेंट का इतिहास और समन्वयित डेटा की मात्रा पढ़ने देता है."</string>
+ <string name="permdesc_readSyncStats" msgid="1510143761757606156">"एप्स को किसी खाते के समन्वयन आंकड़े, साथ ही समन्वयित ईवेंट का इतिहास और समन्वयित डेटा की मात्रा पढ़ने देता है."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ग्राहकी-प्राप्त फ़ीड पढ़ें"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"एप्लिकेशन को वर्तमान में समन्वयित फ़ीड के बारे में विवरण प्राप्त करने देता है."</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"एप्स को वर्तमान में समन्वयित फ़ीड के बारे में विवरण प्राप्त करने देता है."</string>
<string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"ग्राहकी-प्राप्त फ़ीड लिखें"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"एप्लिकेशन को आपके वर्तमान समन्वयित फ़ीड को संशोधित करने देता है. दुर्भावनापूर्ण एप्लिकेशन आपके समन्वयित फ़ीड को बदल सकते है."</string>
- <string name="permlab_readDictionary" msgid="4107101525746035718">"डिक्शनरी में आपके द्वारा जोड़े गए शब्दों को पढ़ें"</string>
- <string name="permdesc_readDictionary" msgid="659614600338904243">"एप्लिकेशन को ऐसे सभी शब्दों, नामों और वाक्यांशों को पढ़ने देता है जो संभवत: उपयोगकर्ता द्वारा उपयोगकर्ता डिक्शनरी में संग्रहीत किए गए हों."</string>
- <string name="permlab_writeDictionary" msgid="2183110402314441106">"उपयोगकर्ता द्वारा परिभाषित डिक्शनरी में शब्द जोड़ें"</string>
- <string name="permdesc_writeDictionary" msgid="8185385716255065291">"एप्लिकेशन को उपयोगकर्ता डिक्शनरी में नए शब्द लिखने देता है."</string>
+ <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"एप्स को आपके वर्तमान समन्वयित फ़ीड को संशोधित करने देता है. दुर्भावनापूर्ण एप्स आपके समन्वयित फ़ीड को बदल सकते है."</string>
+ <string name="permlab_readDictionary" msgid="4107101525746035718">"शब्दकोश में आपके द्वारा जोड़े गए शब्दों को पढ़ें"</string>
+ <string name="permdesc_readDictionary" msgid="659614600338904243">"एप्स को ऐसे सभी शब्दों, नामों और वाक्यांशों को पढ़ने देता है जो संभवत: उपयोगकर्ता द्वारा उपयोगकर्ता शब्दकोश में संग्रहीत किए गए हों."</string>
+ <string name="permlab_writeDictionary" msgid="2183110402314441106">"उपयोगकर्ता द्वारा परिभाषित शब्दकोश में शब्द जोड़ें"</string>
+ <string name="permdesc_writeDictionary" msgid="8185385716255065291">"एप्स को उपयोगकर्ता शब्दकोश में नए शब्द लिखने देता है."</string>
<string name="permlab_sdcardRead" product="nosdcard" msgid="8235341515605559677">"संरक्षित संग्रहण पर पहुंच का परीक्षण करें"</string>
<string name="permlab_sdcardRead" product="default" msgid="8235341515605559677">"संरक्षित संग्रहण पर पहुंच का परीक्षण करें"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3642473292348132072">"एप्लि. को USB संग्रहण अनुमति का परीक्षण करने देता है जो भविष्य के उपकरणों में उपलब्ध होगा."</string>
- <string name="permdesc_sdcardRead" product="default" msgid="5914402684685848828">"एप्लिकेशन को SD कार्ड के लिए किसी अनुमति का परीक्षण करने देता है जो भविष्य के उपकरणों में उपलब्ध होगा."</string>
+ <string name="permdesc_sdcardRead" product="default" msgid="5914402684685848828">"एप्स को SD कार्ड के लिए किसी अनुमति का परीक्षण करने देता है जो भविष्य के उपकरणों में उपलब्ध होगा."</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"अपने USB संग्रहण की सामग्री बदलें या हटाएं"</string>
<string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"अपने SD कार्ड की सामग्री बदलें या हटाएं"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"एप्लि. को USB संग्रहण में लिखने देता है."</string>
- <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"एप्लिकेशन को SD कार्ड पर लिखने देता है."</string>
+ <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"एप्स को SD कार्ड पर लिखने देता है."</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"आंतरिक मीडिया संग्रहण सामग्रियों को बदलें/हटाएं"</string>
- <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"एप्लिकेशन को आंतरिक मीडिया संग्रहण की सामग्री को संशोधित करने देता है."</string>
+ <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"एप्स को आंतरिक मीडिया संग्रहण की सामग्री को संशोधित करने देता है."</string>
<string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"दस्तावेज़ संग्रहण प्रबंधित करें"</string>
- <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"एप्लिकेशन को दस्तावेज़ संग्रहण प्रबंधित करने की अनुमति दें."</string>
+ <string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"एप्स को दस्तावेज़ संग्रहण प्रबंधित करने की अनुमति दें."</string>
<string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"सभी उपयोगकर्ताओं के बाहरी संग्रहण तक पहुंचें"</string>
- <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"एप्लिकेशन को सभी उपयोगकर्ताओं के बाहरी संग्रहण तक पहुंचने दें."</string>
+ <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"एप्स को सभी उपयोगकर्ताओं के बाहरी संग्रहण तक पहुंचने दें."</string>
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"कैश फ़ाइल सिस्टम में पहंचे"</string>
- <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"एप्लिकेशन को संचय फ़ाइल सिस्टम पढ़ने और लिखने देता है."</string>
+ <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"एप्स को संचय फ़ाइल सिस्टम पढ़ने और लिखने देता है."</string>
<string name="permlab_use_sip" msgid="5986952362795870502">"इंटरनेट कॉल करें/प्राप्त करें"</string>
- <string name="permdesc_use_sip" msgid="4717632000062674294">"एप्लिकेशन को इंटरनेट कॉल करने/प्राप्त करने के लिए SIP सेवा का उपयोग करने देता है."</string>
+ <string name="permdesc_use_sip" msgid="4717632000062674294">"एप्स को इंटरनेट कॉल करने/प्राप्त करने के लिए SIP सेवा का उपयोग करने देता है."</string>
<string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"ऐतिहासिक नेटवर्क उपयोग पढें"</string>
- <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"किसी एप्लिकेशन को विशिष्ट नेटवर्क और एप्लिकेशन के लिए ऐतिहासिक नेटवर्क उपयोग को पढ़ने देता है."</string>
+ <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"किसी एप्स को विशिष्ट नेटवर्क और एप्स के लिए ऐतिहासिक नेटवर्क उपयोग को पढ़ने देता है."</string>
<string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"नेटवर्क नीति प्रबंधित करें"</string>
- <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"एप्लिकेशन को नेटवर्क नीतियां प्रबंधित करने और एप्लिकेशन-विशिष्ट नियमों को परिभाषित करने देता है."</string>
+ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"एप्स को नेटवर्क नीतियां प्रबंधित करने और एप्स-विशिष्ट नियमों को परिभाषित करने देता है."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"नेटवर्क उपयोग हिसाब बदलें"</string>
- <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"एप्लिकेशन को यह संशोधित करने देता है कि एप्लिकेशन की तुलना में नेटवर्क उपयोग का मूल्यांकन कैसे किया जाता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"एप्स को यह संशोधित करने देता है कि एप्स की तुलना में नेटवर्क उपयोग का मूल्यांकन कैसे किया जाता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_markNetworkSocket" msgid="3658527214914959749">"सॉकेट मार्क बदलें"</string>
- <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"एप्लिकेशन को रूटिंग के लिए सॉकेट मार्क बदलने देता है"</string>
+ <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"एप्स को रूटिंग के लिए सॉकेट मार्क बदलने देता है"</string>
<string name="permlab_accessNotifications" msgid="7673416487873432268">"सूचनाओं तक पहुंचें"</string>
- <string name="permdesc_accessNotifications" msgid="458457742683431387">"एप्लिकेशन को सूचनाओं को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य एप्लिकेशन के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"एप्स को सूचनाओं को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य एप्स के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना श्रवणकर्ता सेवा से जुड़ें"</string>
- <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को सूचना श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string>
- <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन एप्लिकेशन प्रारंभ करें"</string>
- <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"धारक को वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन एप्लिकेशन प्रारंभ करने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को सूचना श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string>
+ <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन एप्स प्रारंभ करें"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"धारक को वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन एप्स प्रारंभ करने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"नेटवर्क स्थितियों के अवलोकनों को सुनें"</string>
- <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"एप्लिकेशन को नेटवर्क स्थितियों के अवलोकनों को सुनने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"एप्स को नेटवर्क स्थितियों के अवलोकनों को सुनने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"स्क्रीन-अनलॉक पासवर्ड में अनुमति प्राप्त लंबाई और वर्णों को नियंत्रित करें."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"स्क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string>
@@ -672,7 +680,7 @@
<string name="policylab_expirePassword" msgid="885279151847254056">"स्क्रीन लॉक करें पासवर्ड समाप्ति सेट करें"</string>
<string name="policydesc_expirePassword" msgid="1729725226314691591">"नियंत्रित करें कि कितने समय में लॉक-स्क्रीन पासवर्ड बदला जाना चाहिए."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"संग्रहण एन्क्रिप्शन सेट करें"</string>
- <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"संग्रहीत एप्लिकेशन डेटा को एन्क्रिप्ट किया जाना आवश्यक है."</string>
+ <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"संग्रहीत एप्स डेटा को एन्क्रिप्ट किया जाना आवश्यक है."</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"कैमरों को अक्षम करें"</string>
<string name="policydesc_disableCamera" msgid="2306349042834754597">"सभी उपकरण कैमरों का उपयोग रोकें."</string>
<string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"कीगार्ड में सुविधाएं अक्षम करें"</string>
@@ -804,7 +812,7 @@
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"स्क्रीन लॉक की गई है."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"अनलॉक करने के लिए मेनू दबाएं या आपातलकालीन कॉल करें."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"अनलॉक करने के लिए मेनू दबाएं."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"अनलॉक करने के लिए प्रतिमान आरेखित करें"</string>
+ <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"अनलॉक करने के लिए आकार आरेखित करें"</string>
<string name="lockscreen_emergency_call" msgid="5347633784401285225">"आपातकालीन कॉल"</string>
<string name="lockscreen_return_to_call" msgid="5244259785500040021">"कॉल पर वापस लौटें"</string>
<string name="lockscreen_pattern_correct" msgid="9039008650362261237">"सही!"</string>
@@ -833,19 +841,19 @@
<string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"कृपया उपयोगकर्ता मार्गदर्शिका देखें या ग्राहक सहायता से संपर्क करें."</string>
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"सिम कार्ड लॉक किया गया है."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"सिम कार्ड अनलॉक कर रहा है…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"आपने अपना अनलॉक प्रतिमान <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत बनाया है. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत बनाया है. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"आपने अपना पासवर्ड <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिखा है. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"आपने अपना पिन <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिखा है. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुनः प्रयास करें."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"आपने अपना अनलॉक प्रतिमान <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत बनाया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने Google साइन-इन का उपयोग करके आपके टेबलेट को अनलॉक करने को कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"आपने अपना अनलॉक प्रतिमान <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत बनाया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने Google साइन-इन का उपयोग करके आपके फ़ोन को अनलॉक करने को कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत बनाया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने Google साइन-इन का उपयोग करके आपके टेबलेट को अनलॉक करने को कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत बनाया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने Google साइन-इन का उपयोग करके आपके फ़ोन को अनलॉक करने को कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"आप गलत तरीके से टेबलेट को अनलॉक करने का प्रयास <xliff:g id="NUMBER_0">%d</xliff:g> बार कर चुके हैं. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयास के बाद, टेबलेट फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"आप गलत तरीके से फ़ोन को अनलॉक करने का प्रयास <xliff:g id="NUMBER_0">%d</xliff:g> बार कर चुके हैं. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयास के बाद, फ़ोन फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"आप टेबलेट को गलत तरीके से <xliff:g id="NUMBER">%d</xliff:g> बार अनलॉक करने का प्रयास कर चुके हैं. टेबलेट अब फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"आप फ़ोन को गलत तरीके से <xliff:g id="NUMBER">%d</xliff:g> बार अनलॉक करने का प्रयास कर चुके हैं. फ़ोन अब फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"प्रतिमान भूल गए?"</string>
+ <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"आकार भूल गए?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"खाता अनलॉक"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"बहुत अधिक प्रतिमान प्रयास"</string>
+ <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"बहुत अधिक आकार प्रयास"</string>
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"अनलॉक करने के लिए, अपने Google खाते से प्रवेश करें."</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"उपयोगकर्ता नाम (ईमेल)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"पासवर्ड"</string>
@@ -856,10 +864,10 @@
<string name="lockscreen_unlock_label" msgid="737440483220667054">"अनलॉक करें"</string>
<string name="lockscreen_sound_on_label" msgid="9068877576513425970">"ध्वनि चालू करें"</string>
<string name="lockscreen_sound_off_label" msgid="996822825154319026">"ध्वनि बंद"</string>
- <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"प्रतिमान प्रारंभ किया गया"</string>
- <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"प्रतिमान साफ़ किया गया"</string>
+ <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"आकार प्रारंभ किया गया"</string>
+ <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"आकार साफ़ किया गया"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"कक्ष जोड़ा गया"</string>
- <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"प्रतिमान पूरा किया गया"</string>
+ <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"आकार पूरा किया गया"</string>
<string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d विजेट में से %2$d."</string>
<string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"विजेट जोड़ें"</string>
<string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"रिक्त"</string>
@@ -875,11 +883,11 @@
<string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"विजेट <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> को हटा दिया गया."</string>
<string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"अनलॉक क्षेत्र विस्तृत करें."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"स्लाइड अनलॉक."</string>
- <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"प्रतिमान अनलॉक."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"आकार अनलॉक."</string>
<string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"फेस अनलॉक."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"पिन अनलॉक."</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"पासवर्ड अनलॉक."</string>
- <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"प्रतिमान क्षेत्र."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"आकार क्षेत्र."</string>
<string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"स्लाइड क्षेत्र."</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
@@ -896,7 +904,7 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"रीबूट करें"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"\'<xliff:g id="TITLE">%s</xliff:g>\' पर यह पृष्ठ दर्शाता है:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"नेविगेशन की पुष्टि करें"</string>
+ <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"मार्गदर्शक की पुष्टि करें"</string>
<string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"इस पृष्ठ को छोड़ें"</string>
<string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"इस पृष्ठ पर बने रहें"</string>
<string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nक्या आप वाकई इस पृष्ठ से दूर नेविगेट करना चाहते हैं?"</string>
@@ -921,25 +929,25 @@
<string name="autofill_area" msgid="3547409050889952423">"क्षेत्र"</string>
<string name="autofill_emirate" msgid="2893880978835698818">"अमीरात"</string>
<string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"अपने वेब बुकमार्क और इतिहास पढ़ें"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"एप्लिकेशन को ब्राउज़र द्वारा विज़िट किए गए सभी URL के इतिहास, और सभी ब्राउज़र बुकमार्क पढ़ने देता है. ध्यान दें: यह अनुमति तृतीय-पक्ष ब्राउज़र या वेब ब्राउज़िंग क्षमताओं वाले अन्य एप्लिकेशन द्वारा लागू नहीं की जा सकती."</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"एप्स को ब्राउज़र द्वारा विज़िट किए गए सभी URL के इतिहास, और सभी ब्राउज़र बुकमार्क पढ़ने देता है. ध्यान दें: यह अनुमति तृतीय-पक्ष ब्राउज़र या वेब ब्राउज़िंग क्षमताओं वाले अन्य एप्स द्वारा लागू नहीं की जा सकती."</string>
<string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"वेब बुकमार्क और इतिहास लिखें"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"एप्लिकेशन को आपके टेबलेट में संग्रहीत ब्राउज़र के इतिहास या बुकमार्क को संशोधित करने देता है. इससे एप्लिकेशन ब्राउज़र डेटा को मिटा सकता है या संशोधित कर सकता है. ध्यान दें: यह अनुमति तृतीय-पक्ष ब्राउज़र या वेब ब्राउज़िंग क्षमताओं वाले अन्य एप्लिकेशन द्वारा लागू नहीं की जा सकती."</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"एप्लिकेशन को आपके फ़ोन में संग्रहीत ब्राउज़र के इतिहास या बुकमार्क को संशोधित करने देता है. इससे एप्लिकेशन ब्राउज़र डेटा को मिटा सकता है या संशोधित कर सकता है. ध्यान दें: यह अनुमति तृतीय-पक्ष ब्राउज़र या वेब ब्राउज़िंग क्षमताओं वाले अन्य एप्लिकेशन द्वारा लागू नहीं की जा सकती."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"एप्स को आपके टेबलेट में संग्रहीत ब्राउज़र के इतिहास या बुकमार्क को संशोधित करने देता है. इससे एप्स ब्राउज़र डेटा को मिटा सकता है या संशोधित कर सकता है. ध्यान दें: यह अनुमति तृतीय-पक्ष ब्राउज़र या वेब ब्राउज़िंग क्षमताओं वाले अन्य एप्स द्वारा लागू नहीं की जा सकती."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"एप्स को आपके फ़ोन में संग्रहीत ब्राउज़र के इतिहास या बुकमार्क को संशोधित करने देता है. इससे एप्स ब्राउज़र डेटा को मिटा सकता है या संशोधित कर सकता है. ध्यान दें: यह अनुमति तृतीय-पक्ष ब्राउज़र या वेब ब्राउज़िंग क्षमताओं वाले अन्य एप्स द्वारा लागू नहीं की जा सकती."</string>
<string name="permlab_setAlarm" msgid="1379294556362091814">"अलार्म सेट करें"</string>
- <string name="permdesc_setAlarm" msgid="316392039157473848">"एप्लिकेशन को इंस्टॉल किए गए अलार्म घड़ी एप्लिकेशन में अलार्म सेट करने देता है. हो सकता है कुछ अलार्म घड़ी एप्लिकेशन में यह सुविधा न हो."</string>
+ <string name="permdesc_setAlarm" msgid="316392039157473848">"एप्स को इंस्टॉल किए गए अलार्म घड़ी एप्स में अलार्म सेट करने देता है. हो सकता है कुछ अलार्म घड़ी एप्स में यह सुविधा न हो."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"ध्वनिमेल जोड़ें"</string>
- <string name="permdesc_addVoicemail" msgid="6604508651428252437">"एप्लिकेशन को आपके ध्वनिमेल इनबॉक्स में संदेश जोड़ने देता है."</string>
+ <string name="permdesc_addVoicemail" msgid="6604508651428252437">"एप्स को आपके ध्वनिमेल इनबॉक्स में संदेश जोड़ने देता है."</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"ब्राउज़र भौगोलिक-स्थान अनुमतियों को बदलें"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"एप्लिकेशन को ब्राउज़र के भौगोलिक-स्थान की अनुमतियां संशोधित करने देता है. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग एकपक्षीय वेबसाइट को स्थान जानकारी भेजने में कर सकते हैं."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"एप्स को ब्राउज़र के भौगोलिक-स्थान की अनुमतियां संशोधित करने देता है. दुर्भावनापूर्ण एप्स इसका उपयोग एकपक्षीय वेबसाइट को स्थान जानकारी भेजने में कर सकते हैं."</string>
<string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"पैकेज सत्यापित करें"</string>
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"एप्लिकेशन को इंस्टॉल करने योग्य पैकेज सत्यापित करने देता है."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"पैकेज प्रमाणक से आबद्ध करें"</string>
- <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"धारक को पैकेज प्रमाणक के अनुरोध की अनुमति देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"धारक को पैकेज प्रमाणक के अनुरोध की अनुमति देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"सीरियल पोर्ट पर पहुंचें"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API का उपयोग करके धारक को सीरियल पोर्ट पर पहुंच प्रदान करता है."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"बाह्य रूप से सामग्री प्रदाताओं पर पहुंच"</string>
- <string name="permdesc_accessContentProvidersExternally" msgid="4544346486697853685">"धारक को शेल से सामग्री प्रदाताओं तक पहुंचने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यकता नहीं होनी चाहिए."</string>
- <string name="permlab_updateLock" msgid="3527558366616680889">"स्वचालित उपकरण अपडेट का समर्थन न करें"</string>
+ <string name="permdesc_accessContentProvidersExternally" msgid="4544346486697853685">"धारक को शेल से सामग्री प्रदाताओं तक पहुंचने देता है. सामान्य एप्स के लिए कभी भी आवश्यकता नहीं होनी चाहिए."</string>
+ <string name="permlab_updateLock" msgid="3527558366616680889">"अपनेआप उपकरण की नई जानकारी न लें"</string>
<string name="permdesc_updateLock" msgid="1655625832166778492">"धारक को उपकरण अपग्रेड करने के लिए, गैर-सहभागी रीबूट के ठीक समय के बारे में सिस्टम पर जानकारी प्रस्तुत करने देता है."</string>
<string name="save_password_message" msgid="767344687139195790">"क्या आप चाहते हैं कि ब्राउज़र पासवर्ड को याद रखे?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"अभी नहीं"</string>
@@ -957,7 +965,7 @@
<string name="searchview_description_query" msgid="5911778593125355124">"खोज क्वेरी"</string>
<string name="searchview_description_clear" msgid="1330281990951833033">"क्वेरी साफ़ करें"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"क्वेरी सबमिट करें"</string>
- <string name="searchview_description_voice" msgid="2453203695674994440">"ध्वनि खोज"</string>
+ <string name="searchview_description_voice" msgid="2453203695674994440">"बोलकर खोजें"</string>
<string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"स्पर्श के द्वारा अन्वेषण करें सक्षम करें?"</string>
<string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> स्पर्श के द्वारा अन्वेषण करें सक्षम करना चाहती है. स्पर्श के द्वारा अन्वेष करें चालू होने पर, आप अपनी अंगुली के नीचे क्या है उसका विवरण सुन सकते हैं या देख सकते हैं या टेबलेट से संवाद करने के लिए जेस्चर निष्पादित कर सकते हैं."</string>
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> स्पर्श के द्वारा अन्वेषण करें सक्षम करना चाहती है. स्पर्श के द्वारा अन्वेष करें चालू होने पर, आप अपनी अंगुली के नीचे क्या है उसका विवरण सुन सकते हैं या देख सकते हैं या फ़ोन से संवाद करने के लिए जेस्चर निष्पादित कर सकते हैं."</string>
@@ -1086,7 +1094,7 @@
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"संग्रहण स्थान समाप्त हो रहा है"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"हो सकता है कुछ सिस्टम फ़ंक्शन कार्य न करें"</string>
<string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> चल रहा है"</string>
- <string name="app_running_notification_text" msgid="4653586947747330058">"अधिक जानकारी के लिए या एप्लिकेशन रोकने के लिए स्पर्श करें."</string>
+ <string name="app_running_notification_text" msgid="4653586947747330058">"अधिक जानकारी के लिए या एप्स रोकने के लिए स्पर्श करें."</string>
<string name="ok" msgid="5970060430562524910">"ठीक है"</string>
<string name="cancel" msgid="6442560571259935130">"रद्द करें"</string>
<string name="yes" msgid="5362982303337969312">"ठीक है"</string>
@@ -1099,8 +1107,8 @@
<string name="alwaysUse" msgid="4583018368000610438">"इस क्रिया के लिए डिफ़ॉल्ट रूप से उपयोग करें."</string>
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"सिस्टम सेटिंग > Apps > डाउनलोड किए गए में डिफ़ॉल्ट साफ करें."</string>
<string name="chooseActivity" msgid="7486876147751803333">"कोई क्रिया चुनें"</string>
- <string name="chooseUsbActivity" msgid="6894748416073583509">"USB उपकरण के लिए कोई एप्लिकेशन चुनें"</string>
- <string name="noApplications" msgid="2991814273936504689">"कोई भी एप्लिकेशन यह कार्यवाही नहीं कर सकता."</string>
+ <string name="chooseUsbActivity" msgid="6894748416073583509">"USB उपकरण के लिए कोई एप्स चुनें"</string>
+ <string name="noApplications" msgid="2991814273936504689">"कोई भी एप्स यह कार्यवाही नहीं कर सकता."</string>
<string name="aerr_title" msgid="1905800560317137752"></string>
<string name="aerr_application" msgid="932628488013092776">"दुर्भाग्यवश, <xliff:g id="APPLICATION">%1$s</xliff:g> रुक गया है."</string>
<string name="aerr_process" msgid="4507058997035697579">"दुर्भाग्यवश, <xliff:g id="PROCESS">%1$s</xliff:g> प्रक्रिया रुक गई है."</string>
@@ -1119,20 +1127,20 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"स्केल"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"हमेशा दिखाएं"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"इसे सिस्टम सेटिंग > Apps > डाउनलोड किए गए में पुन: सक्षम करें."</string>
- <string name="smv_application" msgid="3307209192155442829">"एप्लिकेशन <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने उसकी स्वयं लागू होने वाली StrictMode नीति का उल्लंघन किया है."</string>
+ <string name="smv_application" msgid="3307209192155442829">"एप्स <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने उसकी स्वयं लागू होने वाली StrictMode नीति का उल्लंघन किया है."</string>
<string name="smv_process" msgid="5120397012047462446">"प्रक्रिया <xliff:g id="PROCESS">%1$s</xliff:g> ने उसकी स्व-प्रवर्तित StrictMode नीति का उल्लंघन किया है."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android अपग्रेड हो रहा है..."</string>
- <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> में से <xliff:g id="NUMBER_0">%1$d</xliff:g> एप्लिकेशन अनुकूलित हो रहा है."</string>
- <string name="android_upgrading_starting_apps" msgid="451464516346926713">"एप्लिकेशन प्रारंभ होने वाले हैं"</string>
+ <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> में से <xliff:g id="NUMBER_0">%1$d</xliff:g> एप्स अनुकूलित हो रहा है."</string>
+ <string name="android_upgrading_starting_apps" msgid="451464516346926713">"एप्स प्रारंभ होने वाले हैं"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"बूट समाप्त हो रहा है."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> चल रही है"</string>
- <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"एप्लिकेशन पर स्विच करने के लिए स्पर्श करें"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"एप्लिकेशन स्विच करें?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"दूसरा एप्लिकेशन पहले से चल रहा है जिसे किसी नए एप्लिकेशन को प्रारंभ करने के पहले बंद किया जाना आवश्यक है."</string>
+ <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"एप्स पर स्विच करने के लिए स्पर्श करें"</string>
+ <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"एप्स स्विच करें?"</string>
+ <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"दूसरा एप्स पहले से चल रहा है जिसे किसी नए एप्स को प्रारंभ करने के पहले बंद किया जाना आवश्यक है."</string>
<string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> पर वापस लौटें"</string>
- <string name="old_app_description" msgid="2082094275580358049">"नया एप्लिकेशन प्रारंभ न करें."</string>
+ <string name="old_app_description" msgid="2082094275580358049">"नया एप्स प्रारंभ न करें."</string>
<string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> प्रारंभ करें"</string>
- <string name="new_app_description" msgid="1932143598371537340">"पुराने एप्लिकेशन को बिना सहेजे बंद करें."</string>
+ <string name="new_app_description" msgid="1932143598371537340">"पुराने एप्स को बिना सहेजे बंद करें."</string>
<string name="sendText" msgid="5209874571959469142">"पाठ के लिए किसी क्रिया को चुनें"</string>
<string name="volume_ringtone" msgid="6885421406845734650">"रिंगर वॉल्यूम"</string>
<string name="volume_music" msgid="5421651157138628171">"मीडिया वॉल्यूम"</string>
@@ -1140,9 +1148,9 @@
<string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"मौन रिंगटोन सेट है"</string>
<string name="volume_call" msgid="3941680041282788711">"कॉल के दौरान वॉल्यूम"</string>
<string name="volume_bluetooth_call" msgid="2002891926351151534">"Bluetooth कॉल के दौरान वॉल्यूम"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"अलार्म वॉल्यूम"</string>
+ <string name="volume_alarm" msgid="1985191616042689100">"अलार्म आवाज़"</string>
<string name="volume_notification" msgid="2422265656744276715">"सूचना वॉल्यूम"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"वॉल्यूम"</string>
+ <string name="volume_unknown" msgid="1400219669770445902">"आवाज़"</string>
<string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"Bluetooth वॉल्यूम"</string>
<string name="volume_icon_description_ringer" msgid="3326003847006162496">"रिंगटोन वॉल्यूम"</string>
<string name="volume_icon_description_incall" msgid="8890073218154543397">"कॉल वॉल्यूम"</string>
@@ -1184,7 +1192,7 @@
<string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"फ़ोन <xliff:g id="DEVICE_NAME">%1$s</xliff:g> से कनेक्ट रहते समय Wi-Fi से अस्थायी रूप से डिस्कनेक्ट हो जाएगा"</string>
<string name="select_character" msgid="3365550120617701745">"वर्ण सम्मिलित करें"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS संदेश भेज रहा है"</string>
- <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> बड़ी संख्या में SMS संदेश भेज रहा है. क्या आप इस एप्लिकेशन को संदेश भेजना जारी रखने देना चाहते हैं?"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> बड़ी संख्या में SMS संदेश भेज रहा है. क्या आप इस एप्स को संदेश भेजना जारी रखने देना चाहते हैं?"</string>
<string name="sms_control_yes" msgid="3663725993855816807">"अनुमति दें"</string>
<string name="sms_control_no" msgid="625438561395534982">"अस्वीकार करें"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>, <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> पर संदेश भेजना चाहता है."</string>
@@ -1193,7 +1201,7 @@
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"भेजें"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"रद्द करें"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"मेरी पसंद को याद रखें"</string>
- <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"आप इसे बाद में सेटिंग > एप्लिकेशन में बदल सकते हैं"</string>
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"आप इसे बाद में सेटिंग > एप्स में बदल सकते हैं"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"हमेशा अनुमति दें"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"कभी भी अनुमति न दें"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"सिमकार्ड निकाला गया"</string>
@@ -1227,7 +1235,7 @@
<string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"USB संग्रहण बंद करें"</string>
<string name="usb_storage_stop_error_message" msgid="1970374898263063836">"USB संग्रहण बंद करने में कोई समस्या हुई थी. जांचें कि आपने USB होस्ट अनमाउंट किया है या नहीं, तब पुन: प्रयास करें."</string>
<string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"USB संग्रहण चालू करें"</string>
- <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"यदि आप USB संग्रहण चालू करते हैं, तो आपके द्वारा उपयोग किए जा रहे कुछ एप्लिकेशन रुक जाएंगे और हो सकता है कि वे तब तक अनुपलब्ध रहें जब तक कि आप USB संग्रहण बंद नहीं कर देते."</string>
+ <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"यदि आप USB संग्रहण चालू करते हैं, तो आपके द्वारा उपयोग किए जा रहे कुछ एप्स रुक जाएंगे और हो सकता है कि वे तब तक अनुपलब्ध रहें जब तक कि आप USB संग्रहण बंद नहीं कर देते."</string>
<string name="dlg_error_title" msgid="7323658469626514207">"USB कार्यवाही विफल"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ठीक है"</string>
<string name="usb_mtp_notification_title" msgid="3699913097391550394">"किसी मीडिया उपकरण के रूप में कनेक्ट किया गया"</string>
@@ -1275,16 +1283,16 @@
<string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"USB संग्रहण निकाला गया. नया मीडिया सम्मिलित करें."</string>
<string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"SD कार्ड निकाला गया. एक नया सम्मिलित करें."</string>
<string name="activity_list_empty" msgid="1675388330786841066">"कोई मिलती-जुलती गतिविधि नहीं मिली."</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"घटक उपयोग आंकड़े अपडेट करें"</string>
- <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"एप्लिकेशन को घटक उपयोग के संकलित आंकड़े संशोधित करने देता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"घटक उपयोग आंकड़ों की नई जानकारी पाएं"</string>
+ <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"एप्स को घटक उपयोग के संकलित आंकड़े संशोधित करने देता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_copyProtectedData" msgid="4341036311211406692">"सामग्री की प्रतिलिपि बनाएं"</string>
- <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"एप्लिकेशन को सामग्री की प्रतिलिपि बनाने के लिए डिफ़ॉल्ट कंटेनर सेवा शुरू करने देता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"एप्स को सामग्री की प्रतिलिपि बनाने के लिए डिफ़ॉल्ट कंटेनर सेवा शुरू करने देता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_route_media_output" msgid="1642024455750414694">"मीडिया आउटपुट को रूट करें"</string>
- <string name="permdesc_route_media_output" msgid="4932818749547244346">"एप्लिकेशन को मीडिया आउटपुट को अन्य बाहरी उपकरणों पर रूट करने देता है."</string>
+ <string name="permdesc_route_media_output" msgid="4932818749547244346">"एप्स को मीडिया आउटपुट को अन्य बाहरी उपकरणों पर रूट करने देता है."</string>
<string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"कीगार्ड सुरक्षित संग्रहण एक्सेस करें"</string>
- <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"एप्लिकेशन को कीगार्ड सुरक्षित संग्रहण एक्सेस करने देती है."</string>
+ <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"एप्स को कीगार्ड सुरक्षित संग्रहण एक्सेस करने देती है."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"कीगार्ड दिखाना और छिपाना नियंत्रित करें"</string>
- <string name="permdesc_control_keyguard" msgid="3043732290518629061">"एप्लिकेशन को कीगार्ड नियंत्रित करने देती है."</string>
+ <string name="permdesc_control_keyguard" msgid="3043732290518629061">"एप्स को कीगार्ड नियंत्रित करने देती है."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"ज़ूम नियंत्रण के लिए दो बार स्पर्श करें"</string>
<string name="gadget_host_error_inflating" msgid="4882004314906466162">"विजेट नहीं जोड़ा जा सका."</string>
<string name="ime_action_go" msgid="8320845651737369027">"जाएं"</string>
@@ -1296,7 +1304,7 @@
<string name="ime_action_default" msgid="2840921885558045721">"निष्पादित करें"</string>
<string name="dial_number_using" msgid="5789176425167573586">"<xliff:g id="NUMBER">%s</xliff:g> के उपयोग द्वारा \n नंबर डायल करें"</string>
<string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g> का उपयोग करके\n संपर्क बनाएं"</string>
- <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"निम्न एक या अधिक एप्लिकेशन अभी और भविष्य में आपके खाते में पहुंच की अनुमति का अनुरोध करते हैं."</string>
+ <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"निम्न एक या अधिक एप्स अभी और भविष्य में आपके खाते में पहुंच की अनुमति का अनुरोध करते हैं."</string>
<string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"क्या आप इस अनुरोध को अनुमति देना चाहते हैं?"</string>
<string name="grant_permissions_header_text" msgid="6874497408201826708">"पहुंच अनुरोध"</string>
<string name="allow" msgid="7225948811296386551">"अनुमति दें"</string>
@@ -1393,7 +1401,7 @@
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mode change"</string>
<string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
- <string name="activitychooserview_choose_application" msgid="2125168057199941199">"कोई एप्लिकेशन चुनें"</string>
+ <string name="activitychooserview_choose_application" msgid="2125168057199941199">"कोई एप्स चुनें"</string>
<string name="shareactionprovider_share_with" msgid="806688056141131819">"इसके साथ साझा करें:"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> के साथ साझा करें"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"स्लाइडिंग हैंडल. स्पर्श करके रखें."</string>
@@ -1479,12 +1487,12 @@
<string name="wifi_display_notification_message" msgid="4498802012464170685">"यह स्क्रीन अन्य उपकरण पर दिखाई दे रही है"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"डिस्कनेक्ट करें"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"आपातकालीन कॉल"</string>
- <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"प्रतिमान भूल गए"</string>
- <string name="kg_wrong_pattern" msgid="1850806070801358830">"गलत प्रतिमान"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"आकार भूल गए"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"गलत आकार"</string>
<string name="kg_wrong_password" msgid="2333281762128113157">"गलत पासवर्ड"</string>
<string name="kg_wrong_pin" msgid="1131306510833563801">"गलत PIN"</string>
<string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%1$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="kg_pattern_instructions" msgid="398978611683075868">"अपना प्रतिमान आरेखित करें"</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"अपना आकार आरेखित करें"</string>
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"सिम PIN डालें"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"PIN डालें"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"पासवर्ड डालें"</string>
@@ -1497,7 +1505,7 @@
<string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK कोड 8 या अधिक संख्या वाला होना चाहिए."</string>
<string name="kg_invalid_puk" msgid="3638289409676051243">"सही PUK कोड पुन: डालें. बार-बार प्रयास करने से सिम स्थायी रूप से अक्षम हो जाएगी."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"पिन कोड का मिलान नहीं होता"</string>
- <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बहुत अधिक प्रतिमान प्रयास"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बहुत अधिक आकार प्रयास"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"अनलॉक करने के लिए, अपने Google खाते से प्रवेश करें."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"उपयोगकर्ता नाम (ईमेल)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"पासवर्ड"</string>
@@ -1507,24 +1515,24 @@
<string name="kg_login_checking_password" msgid="1052685197710252395">"खाते की जांच की जा रही है…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आप अपना PIN <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आप अपना पासवर्ड <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपने अपना अनलॉक प्रतिमान <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"आप टेबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, टेबलेट फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"आप फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, फ़ोन फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"आप टेबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. टेबलेट अब फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"आप फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. फ़ोन अब फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक प्रतिमान को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टेबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक प्रतिमान को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टेबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"निकालें"</string>
- <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"वॉल्यूम को उपरोक्त अनुशंसित स्तर तक बढ़ाएं?\nलंबे समय तक अधिक वॉल्यूम पर सुनने से आपकी सुनने की क्षमता को क्षति पहुंच सकती है."</string>
+ <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"आवाज़ को उपरोक्त सुझाव दिया गया स्तर तक बढ़ाएं?\nलंबे समय तक अधिक आवाज़ पर सुनने से आपकी सुनने की क्षमता को क्षति पहुंच सकती है."</string>
<string name="continue_to_enable_accessibility" msgid="1626427372316070258">"पहुंच-योग्यता को सक्षम करने के लिए दो अंगुलियों से नीचे दबाए रखें."</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"पहुंच-योग्यता सक्षम कर दी है."</string>
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"पहुंच-योग्यता रद्द की गई."</string>
<string name="user_switched" msgid="3768006783166984410">"वर्तमान उपयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="owner_name" msgid="2716755460376028154">"स्वामी"</string>
<string name="error_message_title" msgid="4510373083082500195">"त्रुटि"</string>
- <string name="app_no_restricted_accounts" msgid="5739463249673727736">"यह एप्लिकेशन प्रतिबंधित प्रोफ़ाइल के खातों का समर्थन नहीं करता है"</string>
- <string name="app_not_found" msgid="3429141853498927379">"इस कार्यवाही को प्रबंधित करने के लिए कोई एप्लिकेशन नहीं मिला"</string>
+ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"यह एप्स प्रतिबंधित प्रोफ़ाइल के खातों का समर्थन नहीं करता है"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"इस कार्यवाही को प्रबंधित करने के लिए कोई एप्स नहीं मिला"</string>
<string name="revoke" msgid="5404479185228271586">"निरस्त करें"</string>
<string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
<string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index cd43b8d..e9f5ed1 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Previše brisanja stavki <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Prostor za pohranu tabletnog računala pun je. Izbrišite nekoliko datoteka kako biste oslobodili prostor."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Prostor za pohranu na telefonu je pun. Izbrišite nekoliko datoteka kako biste oslobodili prostor."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mreža se možda nadzire"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Od strane nepoznate treće strane"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Od strane domene <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opcije tabletnog uređaja"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opcije telefona"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"sprečavanje promjene aplikacije"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Sprječava korisnika u prebacivanju na drugu aplikaciju."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"dohvaćanje informacija o trenutačnoj aplikaciji"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Omogućuje vlasniku dohvaćanje privatnih informacija o trenutačnoj aplikaciji i uslugama u prednjem planu na zaslonu."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Omogućuje nositelju dohvaćanje privatnih informacija o trenutačnoj aplikaciji u prednjem planu na zaslonu."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"praćenje i nadzor svih pokretanja aplikacija"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Omogućuje aplikaciji nadzor i upravljanje načinom na koji sustav pokreće aktivnosti. Zlonamjerne aplikacije mogu posve ugroziti sustav. Ta je dozvola potrebna samo za razvoj, nikada za uobičajenu upotrebu."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"slanje paketno uklonjenog prijenosa"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Omogućuje aplikaciji upravljanje značajkama Wi-Fi zaslona niske razine."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"primanje audioizlaza"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Omogućuje aplikaciji primanje i preusmjeravanje audioizlaza."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Otkrivanje pokretača značajke"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Aplikaciji omogućuje snimanje zvuka radi otkrivanja pokretača značajke. Snimanje se može odvijati u pozadini, ali ne sprječava drugo snimanje zvuka (npr. kameru)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"primanje videoizlaza"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Omogućuje aplikaciji primanje i preusmjeravanje videoizlaza."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"primanje sigurnog videoizlaza"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"sprečava telefon da prijeđe u stanje mirovanja"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Aplikaciji omogućuje sprječavanje prelaska tabletnog računala u mirovanje."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Aplikaciji omogućuje da spriječi prelazak telefona u mirovanje."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infracrveni prijenos"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Aplikaciji omogućuje upotrebu infracrvenog odašiljača tableta."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Aplikaciji omogućuje upotrebu infracrvenog odašiljača telefona."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"uključivanje ili isključivanje tabletnog uređaja"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"uključivanje ili isključivanje telefona"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Aplikaciji omogućuje uključivanje i isključivanje tabletnog računala."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 437367f..8343bb3 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Túl sok <xliff:g id="CONTENT_TYPE">%s</xliff:g> törlés."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"A táblagép tárhelye tele van. Szabadítson fel helyet néhány fájl törlésével."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"A telefon tárhelye megtelt. Hely felszabadításához töröljön néhány fájlt."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Lehet, hogy a hálózat felügyelt"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ismeretlen harmadik fél által"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Megfigyelő: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Saját"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Táblagép beállításai"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefonbeállítások"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"alkalmazásváltás megakadályozása"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Megakadályozza, hogy a felhasználó átváltson egy másik alkalmazásra."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"az alkalmazás aktuális információinak lekérése"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Lehetővé teszi, hogy a felhasználó privát adatokat kérjen le az aktuális alkalmazásról és szolgáltatásról a képernyő előterében."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Lehetővé teszi, hogy a felhasználó privát adatokat kérjen le az aktuális alkalmazásról a képernyő előterében."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"alkalmazásindítások nyomon követése és vezérlése"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Lehetővé teszi az alkalmazás számára, hogy figyelje és vezérelje, hogy a rendszer hogyan indít el tevékenységeket. A rosszindulatú alkalmazások teljesen tönkretehetik a rendszert. Ez az engedély csak fejlesztéshez szükséges, normál használathoz sosem."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"eltávolított csomagú üzenetek küldése"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Lehetővé teszi, hogy az alkalmazás irányítsa a Wi-Fi kijelzők alacsonyabb szintű funkcióit."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"audiokimenet rögzítése"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Engedélyezi az alkalmazásnak a hangkimenet rögzítését és átirányítását."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotwordérzékelés"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Lehetővé teszi, hogy alkalmazás rögzítse a befelé jövő hangokat hotwordérzékelés céljából. A rögzítés végbemehet a háttérben, és nem zavarja a más jellegű hangrögzítést, például a kamera esetében."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"videokimenet rögzítése"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Engedélyezi az alkalmazásnak a videokimenet rögzítését és átirányítását."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"biztonságos videokimenet rögzítése"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"telefon alvó üzemmódjának megakadályozása"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Lehetővé teszi az alkalmazás számára, hogy megakadályozza, hogy a táblagép alvó üzemmódra váltson."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Lehetővé teszi az alkalmazás számára, hogy megakadályozza, hogy a telefon alvó üzemmódra váltson."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infravörös érzékelő"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Engedélyezi, hogy az alkalmazás használhassa a táblagép infravörös érzékelőjét."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Engedélyezi, hogy az alkalmazás használhassa a telefon infravörös érzékelőjét."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"a táblagép be- és kikapcsolása"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"a telefon be- és kikapcsolása"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Lehetővé teszi az alkalmazás számára a táblagép be- és kikapcsolását."</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index b15ea4f..97643c9 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Չափից շատ <xliff:g id="CONTENT_TYPE">%s</xliff:g> հեռացումներ:"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Գրասալիկի պահոցը լիքն է: Ջնջեք մի քանի ֆայլ` տարածք ազատելու համար:"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Հեռախոսի պահոցը լիքն է: Ջնջեք մի քանի ֆայլեր` տարածություն ազատելու համար:"</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Ցանցը կարող է վերահսկվել"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Անհայտ երրորդ կողմի կողմից"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>-ի կողմից"</string>
<string name="me" msgid="6545696007631404292">"Իմ"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Գրասալիկի ընտրանքները"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Հեռախոսի ընտրանքներ"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"կանխել ծրագրի փոխարկումները"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Կանխում է օգտվողի անցումը այլ հավելվածի:"</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"ստանալ ընթացիկ հավելվածի մասին տեղեկություններ"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Թույլ է տալիս սեփականատիրոջը առբերել գաղտնի տեղեկություններ ընթացիկ հավելվածի և ծառայությունների մասին էկրանի առաջին պլանում:"</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Թույլ է տալիս սեփականատիրոջը առբերել գաղտնի տեղեկություններ ընթացիկ հավելվածի մասին էկրանի առաջին պլանում:"</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"վերահսկել և կառավարել բոլոր հավելվածների թողարկումը"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Թույլ է տալիս հավելվածին հետևել և վերահսկել, թե ինչպես է համակարգը գործարկում գործողությունները: Վնասարար հավելվածները կարող են ամբողջությամբ վնասել համակարգը: Այս թույլտվությունը անհրաժեշտ է միայն ծրագրավորման համար և ոչ երբեք սովորական օգտագործման համար:"</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"ուղարկել հեռացված փաթեթի մասին հաղորդում"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Թույլ է տալիս հավելվածին կառավարել WiFi ցուցադրիչների ցածր մակարդակի գործառույթները:"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"պահել աուդիո արտածումը"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Թույլ է տալիս ծրագրին պահել և վերահղել աուդիո արտածումը:"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Թեժ բառի հայտնաբերում"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Հավելվածին թույլ է տալիս որսալ ձայնանյութը՝ թեժ բառի հայտնաբերման համար: Դա կարող է տեղի ունենալ հետնաշերտում, սակայն չի խանգարի այլ աուդիո ձայնագրություններին (օր.՝ Տեսախցիկից):"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"պահել վիդեո արտածումը"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Թույլ է տալիս ծրագրին պահել և վերահղել վիդեո արտածումը:"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"պահել անվտանգ վիդեո արտածումը"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"կանխել հեռախոսի քնի ռեժիմին անցնելը"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Թույլ է տալիս հավելվածին կանխել գրասալիկի` քնի ռեժիմին անցնելը:"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Թույլ է տալիս հավելվածին կանխել հեռախոսի` քնի ռեժիմին անցնելը:"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"փոխանցել ինֆրակարմիր հաղորդիչով"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Հավելվածին թույլ է տալիս օգտագործել գրասալիկի ինֆրակարմիր հաղորդիչը:"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Հավելվածին թույլ է տալիս օգտագործել հեռախոսի ինֆրակարմիր հաղորդիչը:"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"գրասալիկը միացնել կամ անջատել"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"հեռախոսը միացնել կամ անջատել"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Թույլ է տալիս հավելվածին միացնել կամ անջատել գրասալիկը:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 04110af..6de81ac 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Terlalu banyak <xliff:g id="CONTENT_TYPE">%s</xliff:g> penghapusan."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Penyimpanan tablet penuh. Hapus beberapa file untuk mengosongkan ruang."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Penyimpanan di ponsel penuh. Hapus sebagian file untuk mengosongkan ruang."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Jaringan mungkin dipantau"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Saya"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opsi tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opsi telepon"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"cegah pergantian aplikasi"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Mencegah pengguna beralih ke apl lain."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"dapatkan info tentang aplikasi yang aktif"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Mengizinkan pemegang mengambil informasi pribadi tentang aplikasi dan layanan saat ini di latar depan layar."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Memungkinkan pemegang mengambil informasi pribadi tentang aplikasi yang aktif di latar depan layar."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"memantau dan mengontrol semua peluncuran apl"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Mengizinkan apl memantau dan mengontrol cara sistem meluncurkan kegiatan. Apl berbahaya dapat meretas sistem sepenuhnya. Izin ini hanya diperlukan untuk pengembangan, tidak pernah diperlukan untuk penggunaan normal."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"kirim siaran paket dihapus"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Izinkan aplikasi mengontrol fitur tingkat rendah dari tampilan Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"tangkap keluaran audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Memungkinkan aplikasi menangkap dan mengalihkan keluaran audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Deteksi kata cepat"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Memungkinkan aplikasi menangkap audio untuk deteksi Kata Cepat. Penangkapan dapat berlangsung di latar belakang namun tidak akan mencegah penangkapan audio yang lain (misalnya Perekam video)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"tangkap keluaran video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Memungkinkan aplikasi menangkap dan mengalihkan keluaran video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"tangkap keluaran video aman"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"mencegah ponsel menjadi tidak aktif"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Mengizinkan apl mencegah tablet tidur."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Mengizinkan apl mencegah ponsel tidur."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"pancarkan inframerah"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Memungkinkan aplikasi menggunakan pemancar inframerah tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Memungkinkan aplikasi menggunakan pemancar inframerah ponsel."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"hidupkan atau matikan tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"daya ponsel hidup atau mati"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Mengizinkan apl menyalakan atau mematikan tablet."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index fd864da..5ae7c5f 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Troppe eliminazioni di <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Spazio di archiviazione del tablet esaurito. Elimina alcuni file per liberare spazio."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Spazio di archiviazione del telefono esaurito. Elimina alcuni file per liberare spazio."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"La rete potrebbe essere monitorata"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Da una terza parte sconosciuta"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Da <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Io"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opzioni tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opzioni telefono"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedire commutazione applicazione"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Impedisce all\'utente di passare a un\'altra applicazione."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"recupero di informazioni sull\'app corrente"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Consente al titolare di recuperare le informazioni private sull\'applicazione e sui servizi attualmente in primo piano sullo schermo."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Consente al titolare di recuperare le informazioni private sull\'app correntemente in primo piano sullo schermo."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitoraggio e controllo avvio di tutte le applicazioni"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Consente all\'applicazione di monitorare e controllare l\'avvio delle attività da parte del sistema. Le applicazioni dannose potrebbero compromettere completamente il sistema. Questa autorizzazione è necessaria solo per lo sviluppo, mai per l\'utilizzo normale."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"invio broadcast rimossi dal pacchetto"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Consente all\'applicazione di controllare le funzioni di basso livello di schermi Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"acquisizione dell\'uscita audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Consente all\'app di acquisire e reindirizzare l\'uscita audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Rilevamento hotword"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Consente all\'app di acquisire l\'audio per il rilevamento Hotword. L\'acquisizione può avvenire in background ma non impedisce l\'acquisizione di altro audio (ad esempio con la videocamera)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"acquisizione dell\'uscita video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Consente all\'app di acquisire e reindirizzare l\'uscita video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"acquisizione dell\'uscita video sicura"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"disattivazione stand-by del telefono"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Consente all\'applicazione di impedire lo stand-by del tablet."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Consente all\'applicazione di impedire lo stand-by del telefono."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"trasmissione a infrarossi"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Consente all\'app di utilizzare il trasmettitore a infrarossi del tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Consente all\'app di utilizzare il trasmettitore a infrarossi del telefono."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"accensione o spegnimento del tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"accensione o spegnimento del telefono"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Consente all\'applicazione di accendere o spegnere il tablet."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 1875122..b9eecd0 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"יש מחיקות רבות מדי של <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"שטח האחסון של הטבלט מלא. מחק קבצים כדי לפנות מקום."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"שטח האחסון של הטלפון מלא. מחק חלק מהקבצים כדי לפנות שטח."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ייתכן שהרשת מנוטרת"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"על ידי צד שלישי לא מוכר"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"על ידי <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"אני"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"אפשרויות טאבלט"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"אפשרויות טלפון"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"מנע החלפת יישומים"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"מניעת מעבר ליישום אחר על ידי המשתמש."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"קבל פרטים על היישום הנוכחי"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"מאפשר לבעלים לאחזר מידע פרטי לגבי האפליקציה והשירותים הנוכחיים שבקדמת המסך."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"מאפשר לבעלים לאחזר מידע פרטי לגבי היישום הנוכחי שבקדמת המסך."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"ניהול מעקב ושליטה על כל הפעלות היישומים"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"מאפשר ליישום לנהל מעקב אחר האופן שבו המערכת מפעילה פעילויות, ולשלוט בו. יישומים זדוניים עלולים לסכן את המערכת כולה. הרשאה זו אינה נחוצה לשימוש רגיל, אלא לפיתוח בלבד."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"שלח שידור שהוסר מחבילה"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"מאפשר לאפליקציה לשלוט בתכונות ברמה נמוכה של תצוגות Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"קליטת פלט אודיו"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"מאפשרת לאפליקציה לקלוט ולהפנות מחדש פלט אודיו."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"זיהוי של מילת הפעלה"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"מאפשרת לאפליקציה לקלוט אודיו עבור זיהוי של מילת הפעלה. פעולת הקליטה יכולה להתבצע ברקע, אבל לא מונעת קליטת אודיו אחרת (למשל, במצלמת הווידאו)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"קליטת פלט וידאו"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"מאפשרת לאפליקציה לקלוט ולהפנות מחדש פלט וידאו."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"קליטת פלט וידאו מאובטח"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"מניעת מעבר הטלפון למצב שינה"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"מאפשר ליישום למנוע מהטבלט לעבור למצב שינה."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"מאפשר ליישום למנוע מהטלפון לעבור למצב שינה."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"שידור באינפרא-אדום"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"מאפשרת לאפליקציה להשתמש במשדר האינפרא-אדום של הטאבלט."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"מאפשרת לאפליקציה להשתמש במשדר האינפרא-אדום של הטלפון."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"הפעלה או כיבוי של טאבלט"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"הפעל או כבה את הטלפון"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"מאפשר ליישום להפעיל או לכבות את הטבלט."</string>
@@ -644,7 +652,7 @@
<string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"נהל מדיניות רשת"</string>
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"מאפשר ליישום לנהל מדיניות הרשת להגדיר כללים ספציפיים-ליישום."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"שנה ניהול חשבונות של שימוש ברשת"</string>
- <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"הרשאה זו מאפשרת ליישום לשנות את אופן החישוב של נתוני שימוש ברשת מול כל יישום. לא מיועד לשימוש ביישומים רגילים."</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"הרשאה זו מאפשרת לאפליקציה לשנות את אופן החישוב של נתוני שימוש ברשת מול כל אפליקציה. לא מיועד לשימוש באפליקציות רגילות."</string>
<string name="permlab_markNetworkSocket" msgid="3658527214914959749">"שינוי של סימני Socket"</string>
<string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"ההרשאה הזו מאפשרת לאפליקציה לשנות סימני Socket עבור ניתוב"</string>
<string name="permlab_accessNotifications" msgid="7673416487873432268">"גישה להתראות"</string>
@@ -810,7 +818,7 @@
<string name="lockscreen_pattern_correct" msgid="9039008650362261237">"נכון!"</string>
<string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"נסה שוב"</string>
<string name="lockscreen_password_wrong" msgid="5737815393253165301">"נסה שוב"</string>
- <string name="faceunlock_multiple_failures" msgid="754137583022792429">"חרגת ממספר הניסיונות המרבי של זיהוי פרצוף"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"חרגת ממספר הניסיונות המרבי של זיהוי פנים"</string>
<string name="lockscreen_plugged_in" msgid="8057762828355572315">"טוען (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<string name="lockscreen_charged" msgid="321635745684060624">"טעון"</string>
<string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
@@ -876,7 +884,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"הרחב את אזור ביטול הנעילה."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"ביטול נעילה באמצעות הסטה."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"ביטול נעילה באמצעות ציור קו."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ביטול נעילה באמצעות זיהוי פרצוף."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ביטול נעילה באמצעות זיהוי פנים."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"ביטול נעילה באמצעות מספר PIN."</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"ביטול נעילה באמצעות סיסמה."</string>
<string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"אזור ציור קו."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index bf2dcac..c2401bc 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>での削除が多すぎます。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"タブレットのストレージに空き領域がありません。ファイルを削除して空き領域を確保してください。"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"端末のストレージに空き領域がありません。ファイルを削除して空き領域を確保してください。"</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ネットワークが監視される場合があります"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"自分"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"タブレットオプション"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"携帯電話オプション"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"アプリケーションの切り替えを禁止する"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"ユーザーが別のアプリに切り替えられないようにします。"</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"現在のアプリ情報の取得"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"画面のフォアグラウンドで実行されるアプリとサービスに関する非公開情報を取得することを所有者に許可します。"</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"画面のフォアグラウンドで現在のアプリに関する非公開情報を取得することを所有者に許可します。"</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"すべてのアプリ起動の監視と制御"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"システムによるアクティビティ起動方法を監視し制御することをアプリに許可します。この許可を悪意のあるアプリに利用されると、システム全体のセキュリティが侵害される恐れがあります。この許可は開発時にのみ必要で、通常の使用では不要です。"</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"パッケージ削除ブロードキャストの送信"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Wi-Fiディスプレイの低レベル機能を制御することをアプリに許可します。"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"音声出力のキャプチャ"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"音声出力のキャプチャとリダイレクトをアプリに許可します。"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"注目ワード検出"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"注目ワード検出での音声キャプチャをアプリに許可します。キャプチャはバックグラウンドで発生しますが、その他の音声キャプチャ(例: ビデオ録画)を妨げることはありません。"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"動画出力のキャプチャ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"動画出力のキャプチャとリダイレクトをアプリに許可します。"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"セキュリティ保護された動画出力のキャプチャ"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"端末のスリープを無効にする"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"タブレットのスリープを無効にすることをアプリに許可します。"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"携帯端末のスリープを無効にすることをアプリに許可します。"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"赤外線の送信"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"タブレットの赤外線送信機能の使用をアプリに許可します。"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"携帯電話の赤外線送信機能の使用をアプリに許可します。"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"タブレットの電源ON/OFF"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"電源のON/OFF"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"タブレットの電源のON/OFFをアプリに許可します。"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 745b4c7..e4e5f92 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
+ <string name="byteShort" msgid="8340973892742019101">"ბაიტი"</string>
<string name="kilobyteShort" msgid="5973789783504771878">"კბაიტი"</string>
<string name="megabyteShort" msgid="6355851576770428922">"მბაიტი"</string>
<string name="gigabyteShort" msgid="3259882455212193214">"გბაიტი"</string>
@@ -31,7 +31,7 @@
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
<string name="emptyPhoneNumber" msgid="7694063042079676517">"(ტელეფონის ნომრის გარეშე)"</string>
- <string name="unknownName" msgid="2277556546742746522">"უცნობი"</string>
+ <string name="unknownName" msgid="2277556546742746522">"(უცნობი)"</string>
<string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ხმოვანი ფოსტა"</string>
<string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
<string name="mmiError" msgid="5154499457739052907">"კავშირის პრობლემა ან არასწორი MMI კოდი."</string>
@@ -65,10 +65,10 @@
<string name="RuacMmi" msgid="7827887459138308886">"არასასურველი მომაბეზრებელი ზარების უარყოფა"</string>
<string name="CndMmi" msgid="3116446237081575808">"დამრეკავი ნომრის მოწოდება"</string>
<string name="DndMmi" msgid="1265478932418334331">"არ შემაწუხოთ"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"მრეკავის ID ნაგულისხმევად შეზღუდულია. შემდეგი ზარი: შეზღუდულია."</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"აბონენტის ID ნაგულისხმევად შეზღუდულია. შემდეგი ზარი: შეუზღუდავი."</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"აბონენტის ID უპირობოდ შეზღუდული არ არის. შემდეგი ზარი: შეზღუდულია."</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"აბონენტის ID ნაგულისხმევად შეზღუდული არ არის. შემდეგი ზარი: შეუზღუდავი."</string>
+ <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"ნაგულისხმებად დაყენებულია ნომრის დაფარვა. შემდეგი ზარი: დაფარულია."</string>
+ <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"ნაგულისხმებად დაყენებულია ნომრის დაფარვა. შემდეგი ზარი: არ არის დაფარული."</string>
+ <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"ნაგულისხმებად დაყენებულია ნომრის დაფარვის გამორთვა. შემდეგი ზარი: დაფარულია."</string>
+ <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ნაგულისხმებად დაყენებულია ნომრის დაფარვის გამორთვა. შემდეგი ზარი: არ არის დაფარული."</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"სერვისი არ არის მიწოდებული."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"არ შეგიძლიათ აბონენტის ID პარამეტრების შეცვლა."</string>
<string name="RestrictedChangedTitle" msgid="5592189398956187498">"წვდომის შეზღუდვები შეცვლილია"</string>
@@ -131,11 +131,16 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>-ის ძალიან ბევრი წაშლილები."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"ტაბლეტის მეხსიერება გავსებულია. ადგილის გასათავისუფლებლად წაშალეთ ფაილების ნაწილი."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"ტელეფონის მეხსიერება გავსებულია. ადგილის გასათავისუფლებლად წაშალეთ ფაილების ნაწილი."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"შესაძლოა ქსელი მონიტორინგის ქვეშ იმყოფება"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"მე"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"ტაბლეტის პარამეტრები"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"ტელეფონის პარამეტრები"</string>
<string name="silent_mode" msgid="7167703389802618663">"ჩუმი რეჟიმი"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"უსადენოს ჩართვა"</string>
+ <string name="turn_on_radio" msgid="3912793092339962371">"უსადენო კავშირის ჩართვა"</string>
<string name="turn_off_radio" msgid="8198784949987062346">"უსადენო ინტერნეტის გამორთვა"</string>
<string name="screen_lock" msgid="799094655496098153">"ეკრანის დაბლოკვა"</string>
<string name="power_off" msgid="4266614107412865048">"გამორთვა"</string>
@@ -153,7 +158,7 @@
<string name="global_actions" product="tablet" msgid="408477140088053665">"ტაბლეტის პარამეტრები"</string>
<string name="global_actions" product="default" msgid="2406416831541615258">"ტელეფონის პარამეტრები"</string>
<string name="global_action_lock" msgid="2844945191792119712">"ეკრანის დაბლოკვა"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"გამორთულია"</string>
+ <string name="global_action_power_off" msgid="4471879440839879722">"კვების გამორთვა"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"ხარვეზის შესახებ ანგარიში"</string>
<string name="bugreport_title" msgid="2667494803742548533">"შექმენით შეცდომის ანგარიში"</string>
<string name="bugreport_message" msgid="398447048750350456">"იგი შეაგროვებს ინფორმაციას თქვენი მოწყობილობის ამჟამინდელი მდგომარეობის შესახებ, რათა ის ელფოსტის შეტყობინების სახით გააგზავნოს. ხარვეზის ანგარიშის მომზადებასა და შეტყობინების გაგზავნას გარკვეული დრო სჭირდება. გთხოვთ, მოითმინოთ."</string>
@@ -182,7 +187,7 @@
<string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"მოწყობილობებთან და ქსელებთან წვდომა Bluetooth მეშვეობით."</string>
<string name="permgrouplab_audioSettings" msgid="8329261670151871235">"აუდიო პარამეტრები"</string>
<string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"აუდიო პარამეტრების შეცვლა."</string>
- <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"აზიანებს ელემენტს"</string>
+ <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"ხარჯავს ბატარეას"</string>
<string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"იმ ფუნქციების გამოყენება, რომელიც ელემენტს სწრაფად დახლის."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"კალენდარი"</string>
<string name="permgroupdesc_calendar" msgid="5777534316982184416">"კალენდარსა და ღონისძიებებზე პირდაპირი წვდომა."</string>
@@ -218,7 +223,7 @@
<string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"ყურსაცვამის აპარატურულ მოწყობილობაზე პირდაპირი წვდომა."</string>
<string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"სატელეფონო ზარები"</string>
<string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"სატელეფონო ზარების მონიტორინგი, ჩაწერა და განხორციელება."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"სისტემის ხელსაწყოები"</string>
+ <string name="permgrouplab_systemTools" msgid="4652191644082714048">"სისტემური ინსტრუმენტები"</string>
<string name="permgroupdesc_systemTools" msgid="8162102602190734305">"დაბალი წვდომა და სისტემის კონტროლი"</string>
<string name="permgrouplab_developmentTools" msgid="3446164584710596513">"დეველოპმენტის ინსტრუმენტები"</string>
<string name="permgroupdesc_developmentTools" msgid="7058828032358142018">"ელემენტები, რომლებიც მხოლოდ აპების დეველოპერებს სჭირდებათ."</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"აპის გადართვებისგან დაცვა"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"ხელს უშლის მომხმარებლის სხვა აპზე გადართვას."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"ამჟამინდელი აპის ინფორმაციის მიღება"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"ნებას რთავს მფლობელს, მოიპოვოს მიმდინარე აპლიკაციის და სერვისების შესახებ პირადი ინფორმაცია ეკრანის წინა პლანზე."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"ნებას რთავს მფლობელს, მოიპოვოს მიმდინარე აპლიკაციის შესახებ პირადი ინფორმაცია ეკრანის წინა პლანზე."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"ყველა აპის გაშვების მონიტორინგი დ კონტროლი"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"აპს შეეძლება სისტემის მიერ გამოძახებული აქტივობების მონიტორინგი და მართვა. მავნე აპლიკაციებს შეეძლებათ სისტემის სრული კონტროლი. ეს ნებართვა საჭროა მხოლოდ დეველოპმენტისთვის და ჩვეულებრივი მოხმარებისთის არ გამოიყენება."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"პაკეტების წაშლის შესახებ შეტყობინებების გაგზავნა"</string>
@@ -349,10 +354,10 @@
<string name="permdesc_manageAppTokens" msgid="8043431713014395671">"აპს შეეძლება, შექმნას და მართოს საკუთარი იდენტიფიკაციის ნიშნები, ჩვეულებრივი Z-წყობის უგულვებელყოფით. ჩვეულებრივი აპებისთვის მისი გამოყენება არასდროს არის საჭირო."</string>
<string name="permlab_freezeScreen" msgid="4708181184441880175">"ეკრანის გაყინვა"</string>
<string name="permdesc_freezeScreen" msgid="8558923789222670064">"აპლიკაციას შეეძლება ეკრანის დროებით გაშეშება სრულ ეკრანზე გადასასვლელად."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"გასაღებზე დაჭერა და ღილაკების მართვა"</string>
+ <string name="permlab_injectEvents" msgid="1378746584023586600">"ღილაკების და სამართავი ელემენტების დაჭერა"</string>
<string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"აპს შეეძლება შეყვანის საკუთარი მოვლენების (გასაღები და ა.შ.) სხვა აპებისთვის გადაცემა. მავნე აპებმა შესაძლოა ეს გამოიყენონ ტაბლეტის საკონტროლოდ."</string>
<string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"აპს შეეძლება შეყვანის საკუთარი მოვლენების (გასაღები და ა.შ.) სხვა აპებისთვის გადაცემა. მავნე აპებმა შესაძლოა ეს გამოიყენონ ტელეფონის საკონტროლოდ."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"ჩაწერეთ რასაც ბეჭდავთ და რა ქმედებებსაც მიმართავთ."</string>
+ <string name="permlab_readInputState" msgid="469428900041249234">"მომხმარებლის ქმედებების და მის მიერ შეყვანილი ტექსტის ჩაწერა"</string>
<string name="permdesc_readInputState" msgid="8387754901688728043">"აპს შეეძლება დაინახოს გასაღები, როდესაც მას ბეჭდავთ თუნდაც სხვა აპში მუშაობის დროს (მაგალითად, პაროლის აკრეფა). ჩვეულებრივ აპებს მსგავსი რამ არასოდეს სჭირდება."</string>
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"შეტანის მეთოდთან დაკავშირება"</string>
<string name="permdesc_bindInputMethod" msgid="3250440322807286331">"აპს შეეძლება ზედა დონის ინტერფეისის წვდომის სისტემასთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
@@ -468,7 +473,7 @@
<string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"აპს შეეძლება გაიგოს თქვენი სავარაუდო მდებარეობა. ის გამოითვლება მდებარეობის სერვისის მიერ ქსელის მონაცემების - მობილური კავშირგაბმულობის ანძებისა და Wi-Fi-ის მიხედვით. ეს სერვისები ჩართული უნდა იყოს თქვენს მოწყობილობაზე, ხოლო აპებს უნდა ჰქონდეთ მათი გამოყენების უფლება. აპები მათი მონაცემების მიხედვით სავარაუდო მდებარეობის გამოთვლას შეძლებენ."</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"SurfaceFlinger-ზე წვდომა"</string>
<string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"აპს შეეძლება, გამოიყენოს SurfaceFlinger-ის დაბალი დონის ელემენტები."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ჩარჩოს ბუფერის წაკითხვა"</string>
+ <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"კადრის ბუფერის (ეკრანის შიგთავსის) წაკითხვა"</string>
<string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"აპს შეეძლება წაიკითხოს ბუფერული ჩარჩოს კონტენტი."</string>
<string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Wifi ეკრანის კონფიგურაცია"</string>
<string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"აპს შეეძლება Wifi ეკრანებთან დაკავშირება და დაკონფიგურირება."</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"აპს შეეძლება აკონტროლოს Wifi ეკრანების დაბალი დონის ფუნქციები."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"გამომავალი აუდიოს დაჭერა"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"საშუალებას აძლევს აპს დაიჭიროს და გადაამისამართოს გამომავალი აუდიო."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ჯადოსნური სიტყვის პოვნა"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"საშუალებას აძლევს აპს ჩაიწეროს აუდიო ჯადოსნნური სიტყვების ამოცნობისათვის. ჩაწერა შესაძლოა განხორციელდეს ფონურად, თუმცა ხელს არ უშლის სხვა სახის აუდიოს ჩაწერას (მაგ. ვიდეოჩამწერიდან)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"გამომავალი ვიდეოს დაჭერა"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"საშუალებას აძლევს აპს დაიჭიროს და გადაამისამართოს გამომავალი ვიდეო."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"გამომავალი დაცული ვიდეოს დაჭერა"</string>
@@ -514,7 +521,7 @@
<string name="permdesc_asec_rename" msgid="1794757588472127675">"აპს შეეძლება შიდა მეხსიერებისთვის სახელის გადარქმევა."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ვიბრაციის კონტროლი"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"აპს შეეძლება, მართოს ვიბრირება."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"სასიგნალო შუქის მართვა"</string>
+ <string name="permlab_flashlight" msgid="2155920810121984215">"ფანრის მართვა"</string>
<string name="permdesc_flashlight" msgid="6522284794568368310">"აპს შეეძლება, მართოს განათება."</string>
<string name="permlab_manageUsb" msgid="1113453430645402723">"USB მოწყობილობების უფლებებისა და სასურველი პარამეტრების მართვა"</string>
<string name="permdesc_manageUsb" msgid="7776155430218239833">"აპს შეეძლება USB მოწყობილობების პარამეტრებისა და ნებართვების მართვა."</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ტელეფონის ძილის რეჟიმში გადასვლის აღკვეთა"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"აპს შეეძლება ხელი შეუშალოს ტაბლეტის დაძინებას."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"აპს შეეძლება ხელი შეუშალოს ტელეფონის დაძინებას."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"ინფრაწითელით გადაცემა"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"რთავს ნებას აპს გამოიყენოს ტაბლეტის ინფრაწითელი გადამცემი."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"რთავს ნებას აპს გამოიყენოს ტელეფონის ინფრაწითელი გადამცემი."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"ტაბლეტის ჩართვა ან გამორთვა"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"ტელეფონის ჩართვა ან გამორთვა"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"აპს შეეძლება, ჩართოს ან გამორთოს ტაბლეტი."</string>
@@ -579,7 +589,7 @@
<string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"აპს შეეძლება შექმნას ქსელური ბუდეები და გამოიყენოს მორგებული ქსელის პროტოკოლები. ბრაუზერი და სხვა აპლიკაციები უზრუნველყოფს ინტერნეტში მონაცემების გაგზავნის საშუალებას, ამგვარად ეს უფლება ინფორმაციის გასაგზავნად საჭირო არაა."</string>
<string name="permlab_writeApnSettings" msgid="505660159675751896">"ქსელის პარამეტრებისა და ტრაფიკის შეცვლა / შეწყვეტა"</string>
<string name="permdesc_writeApnSettings" msgid="5333798886412714193">"აპს შეეძლება ქსელის პარამეტრების შეცვლა, მთელი ქსელის ტრაფიკის შეწყვეტა და ინსპექტირება, მაგალითად, ნებისმიერი APN-ის პორტისა და პროქსის შეცვლა. მავნე აპებს შეეძლებათ ქსელის პაკეტების მონიტორინგი, გადამისამართება ან შეცვლა თქვენთვის შეტყობინების გარეშე."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"ქსელის დაკავშირებულობის შეცვლა"</string>
+ <string name="permlab_changeNetworkState" msgid="958884291454327309">"კავშირის მდგომარეობის/პარამეტრების შეცვლა"</string>
<string name="permdesc_changeNetworkState" msgid="6789123912476416214">"აპს შეეძლება, შეცვალოს ქსელის კავშირის მდგომარეობა."</string>
<string name="permlab_changeTetherState" msgid="5952584964373017960">"მიერთებული კავშირის შეცვლა"</string>
<string name="permdesc_changeTetherState" msgid="1524441344412319780">"აპს შეეძლება, შეცვალოს მობილური ქსელის კავშირის მდგომარეობა."</string>
@@ -843,14 +853,14 @@
<string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"თქვენ <xliff:g id="NUMBER">%d</xliff:g>-ჯერ არასწორად სცადეთ ტაბლეტის განბლოკვა. ამიტომ ტაბლეტზე დადგება საწყისი, ქარხნული პარამეტრები."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g> ჯერ. ახლა ტელეფონზე დაყენდება საწყისი, ქარხნული პარამეტრები."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"კიდევ სცადეთ <xliff:g id="NUMBER">%d</xliff:g> წამში."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"დაგავიწყდათ ნიმუში?"</string>
+ <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"დაგავიწყდათ გრაფიკული გასაღები?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"ანგარიშით განბლოკვა"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"ნახატი ნიმუშის ძალიან ბევრი მცდელობა"</string>
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"განბლოკვისთვის გაიარეთ ავტორიზაცია თქვენი Google ანგარიშით."</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"მომხმარებლის სახელი (ელფოსტა)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"პაროლი"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"შესვლა"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"მომხმარებლის არასწორი სახელი ან პაროლი"</string>
+ <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"არასწორი მომხმარებლის სახელი ან პაროლი."</string>
<string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"დაგავიწყდათ მომხმარებლის სახელი და პაროლი?\nეწვიეთ ბმულს "<b>"google.com/accounts/recovery"</b>"."</string>
<string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"შემოწმება..."</string>
<string name="lockscreen_unlock_label" msgid="737440483220667054">"განბლოკვა"</string>
@@ -947,7 +957,7 @@
<string name="save_password_never" msgid="8274330296785855105">"არასოდეს"</string>
<string name="open_permission_deny" msgid="7374036708316629800">"ამ გვერდის გახსნის უფლება არ გაქვთ."</string>
<string name="text_copied" msgid="4985729524670131385">"ტექსტი დაკოპირებულია გაცვლის ბუფერში."</string>
- <string name="more_item_label" msgid="4650918923083320495">"მეტი"</string>
+ <string name="more_item_label" msgid="4650918923083320495">"დამატებით"</string>
<string name="prepend_shortcut_label" msgid="2572214461676015642">"მენიუ+"</string>
<string name="menu_space_shortcut_label" msgid="2410328639272162537">"[ინტერვალი]"</string>
<string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
@@ -1036,15 +1046,15 @@
<string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>-ზე"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> წელს"</string>
<string name="day" msgid="8144195776058119424">"დღე"</string>
- <string name="days" msgid="4774547661021344602">"დღეები"</string>
+ <string name="days" msgid="4774547661021344602">"დღე"</string>
<string name="hour" msgid="2126771916426189481">"საათი"</string>
<string name="hours" msgid="894424005266852993">"საათი"</string>
<string name="minute" msgid="9148878657703769868">"წთ"</string>
<string name="minutes" msgid="5646001005827034509">"წუთი"</string>
<string name="second" msgid="3184235808021478">"წმ."</string>
- <string name="seconds" msgid="3161515347216589235">"წამები"</string>
+ <string name="seconds" msgid="3161515347216589235">"წამი"</string>
<string name="week" msgid="5617961537173061583">"კვირა"</string>
- <string name="weeks" msgid="6509623834583944518">"კვირები"</string>
+ <string name="weeks" msgid="6509623834583944518">"კვირა"</string>
<string name="year" msgid="4001118221013892076">"წელი"</string>
<string name="years" msgid="6881577717993213522">"წელი"</string>
<plurals name="duration_seconds">
@@ -1094,8 +1104,8 @@
<string name="dialog_alert_title" msgid="2049658708609043103">"ყურადღება"</string>
<string name="loading" msgid="7933681260296021180">"ჩატვირთვა…"</string>
<string name="capital_on" msgid="1544682755514494298">"ჩართ."</string>
- <string name="capital_off" msgid="6815870386972805832">"გამორთულია"</string>
- <string name="whichApplication" msgid="4533185947064773386">"მოქმედების დასრულება შემდეგი საშუალებით:"</string>
+ <string name="capital_off" msgid="6815870386972805832">"გამორთ."</string>
+ <string name="whichApplication" msgid="4533185947064773386">"რა გამოვიყენოთ?"</string>
<string name="alwaysUse" msgid="4583018368000610438">"ამ ქმედებისთვის ნაგულისხმევად გამოყენება."</string>
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"ნაგულისხმევი პარამეტრების წაშლა სისტემის პარამეტრებში > აპებში > ჩამოტვირთულებში."</string>
<string name="chooseActivity" msgid="7486876147751803333">"აირჩიეთ მოქმედება"</string>
@@ -1122,7 +1132,7 @@
<string name="smv_application" msgid="3307209192155442829">"აპმა <xliff:g id="APPLICATION">%1$s</xliff:g> (პროცესი <xliff:g id="PROCESS">%2$s</xliff:g>) დაარღვია საკუთარი StrictMode დებულება."</string>
<string name="smv_process" msgid="5120397012047462446">"ამ პროცესმა <xliff:g id="PROCESS">%1$s</xliff:g> დააზიანა საკუთარი StrictMode დებულება."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android ახალ ვერსიაზე გადადის…"</string>
- <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g> აპლიკაციის (სულ <xliff:g id="NUMBER_1">%2$d</xliff:g>-დან) ოპტიმიზაცია."</string>
+ <string name="android_upgrading_apk" msgid="7904042682111526169">"მიმდინარეობს აპლიკაციების ოპტიმიზაცია. დასრულებულია <xliff:g id="NUMBER_0">%1$d</xliff:g>, სულ <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"აპების ჩართვა"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"ჩატვირთვის დასასრული."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> გაშვებულია"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index a75c6a9..f56d261 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"មានការលុប <xliff:g id="CONTENT_TYPE">%s</xliff:g> ច្រើនពេក។"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"ឧបករណ៍ផ្ទុកនៃកុំព្យូទ័របន្ទះពេញ។ លុបឯកសារមួយចំនួន។"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"ឧបករណ៍ផ្ទុកទូរស័ព្ទពេញ! លុបឯកសារមួយចំនួនដើម្បីបង្កើនទំហំ។"</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"បណ្ដាញអាចត្រូវបានតាមដាន"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ដោយភាគីទីបីដែលមិនស្គាល់"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"ដោយ <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"ខ្ញុំ"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"ជម្រើសកុំព្យូទ័របន្ទះ"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"ជម្រើសទូរស័ព្ទ"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ការពារការប្ដូរកម្មវិធី"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"ការពារអ្នកប្រើមិនឲ្យប្ដូរទៅកម្មវិធីផ្សេង។"</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"យកព័ត៌មានកម្មវិធីបច្ចុប្បន្ន"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"អនុញ្ញាតឱ្យម្ចាស់ទៅយកព័ត៌មានឯកជនអំពីកម្មវិធីបច្ចុប្បន្ន និងសេវាកម្មនៅក្នុងផ្ទៃខាងមុខរបស់អេក្រង់។"</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"ឲ្យម្ចាស់ទៅយកព័ត៌មានផ្ទាល់ខ្លួនអំពីកម្មវិធីបច្ចុប្បន្នក្នុងផ្ទៃខាងមុខនៃអេក្រង់។"</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"តាមដាន និងពិនិត្យការចាប់ផ្ដើមកម្មវិធី"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"ឲ្យកម្មវិធីតាមដាន និងពិនិត្យវិធីដែលប្រព័ន្ធចាប់ផ្ដើមសកម្មភាព។ កម្មវិធីព្យាបាទអាចសម្របសម្រួលប្រព័ន្ធទាំងស្រុង។ សិទ្ធិនេះចាំបាច់សម្រាប់តែការអភិវឌ្ឍ មិនសម្រាប់ប្រើធម្មតាទេ។"</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"ផ្ញើកញ្ចប់ការប្រកាសបានយកចេញ"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"ឲ្យកម្មវិធីពិនិត្យលក្ខណៈកម្រិតទាបនៃការបង្ហាញវ៉ាយហ្វាយ។"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ចាប់យកលទ្ធផលអូឌីយ៉ូ"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ឱ្យកម្មវិធីដើម្បីចាប់យក និងប្ដូរទិសលទ្ធផលអូឌីយ៉ូ។"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ការរកឃើញពាក្យ"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"ឲ្យកម្មវិធីថតអូឌីយ៉ូសម្រាប់ការរកឃើញពាក្យ។ ការថតអាចកើតឡើងក្នុងផ្ទៃខាងក្រោយ ប៉ុន្តែមិនរារាំងការថតអូឌីយ៉ូផ្សេងទេ (ឧ. ម៉ាស៊ីនថតវីដេអូ)។"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"ចាប់យកលទ្ធផលវីដេអូ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"ឲ្យកម្មវិធីចាប់យក និងប្ដូរទិសលទ្ធផលវីដេអូ។"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ចាប់យកលទ្ធផលវីដេអូសុវត្ថិភាព"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ការពារទូរស័ព្ទមិនឲ្យដេក"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ឲ្យកម្មវិធីការពារកុំព្យូទ័របន្ទះមិនឲ្យដេក។"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"ឲ្យកម្មវិធីការពារទូរស័ព្ទមិនឲ្យដេក។"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"បញ្ជូនអ៊ីនហ្វ្រារ៉េដ"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"ឲ្យកម្មវិធីប្រើកម្មវិធីបញ្ជូនអ៊ីនហ្វ្រារ៉េដរបស់កុំព្យូទ័របន្ទះ។"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"ឲ្យកម្មវិធីប្រើកម្មវិធីបញ្ជូនតាមអ៊ីនហ្វ្រារ៉េដរបស់ទូរស័ព្ទ។"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"បិទ/បើកកុំព្យូទ័របន្ទះ"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"បិទ/បើកទូរស័ព្ទ"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"ឲ្យកម្មវិធីបិទ/បើកកុំព្យូទ័របន្ទះ។"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 9f6c84b..41e66ce 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g> 삭제가 너무 많습니다."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"태블릿 저장공간이 꽉 찼습니다. 일부 파일을 삭제하여 저장 여유 공간을 늘리세요."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"휴대전화 저장공간이 꽉 찼습니다. 일부 파일을 삭제하여 저장공간을 늘리세요."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"네트워크가 모니터링될 수 있음"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"나"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"태블릿 옵션"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"휴대전화 옵션"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"애플리케이션 전환 방지"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"사용자가 다른 앱으로 전환하지 못하게 합니다."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"현재 앱 정보 얻기"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"권한을 가진 프로그램이 화면의 포그라운드에서 현재 애플리케이션 및 서비스에 대한 비공개 정보를 검색하도록 허용합니다."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"권한을 가진 프로그램이 화면의 포그라운드에서 현재 애플리케이션에 대한 비공개 정보를 검색하도록 허용합니다."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"실행 중인 모든 앱 모니터링 및 제어"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"앱이 시스템에서 활동이 시작되는 방식을 모니터링하고 관리할 수 있도록 허용합니다. 이 경우 악성 앱이 이 기능을 이용하여 시스템을 완전히 손상시킬 수 있습니다. 이 권한은 개발 과정에만 필요하며 일반 사용 시에는 필요하지 않습니다."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"패키지 제거 브로드캐스트 보내기"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"앱이 Wi-Fi 디스플레이의 하위 수준 기능을 제어하도록 허용합니다."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"오디오 출력 캡처"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"앱이 오디오 출력을 캡처하고 리디렉션하도록 허용합니다."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"핫워드 감지"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"앱에서 핫워드 감지를 위해 오디오를 캡처하도록 허용합니다. 캡처는 백그라운드에서 수행될 수 있지만 다른 오디오 캡처를 차단하지 않습니다(예: 캠코더)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"동영상 출력 캡처"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"앱이 동영상 출력을 캡처하고 리디렉션하도록 허용합니다."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"안전한 동영상 출력 캡처"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"휴대전화가 절전 모드로 전환되지 않도록 설정"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"앱이 태블릿의 절전 모드 전환을 막도록 허용합니다."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"앱이 휴대전화의 절전 모드 전환을 막도록 허용합니다."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"적외선 전송"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"앱에서 태블릿의 적외선 송신기를 사용하도록 허용합니다."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"앱에서 휴대전화의 적외선 송신기를 사용하도록 허용합니다."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"태블릿 전원 켜고 끄기"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"휴대전화 전원 켜고 끄기"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"앱이 태블릿을 켜거나 끌 수 있도록 허용합니다."</string>
@@ -670,7 +680,7 @@
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"기기 전체 프록시 설정"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"정책이 사용 설정되어 있는 동안 사용될 기기 전체 프록시를 설정합니다. 첫 번째 기기 관리자가 설정한 전체 프록시만 유효합니다."</string>
<string name="policylab_expirePassword" msgid="885279151847254056">"화면 잠금 비밀번호 만료 설정"</string>
- <string name="policydesc_expirePassword" msgid="1729725226314691591">"화면 잠금 비밀번호 변경 빈도 설정"</string>
+ <string name="policydesc_expirePassword" msgid="1729725226314691591">"화면 잠금 비밀번호 변경 빈도를 설정합니다."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"저장소 암호화 설정"</string>
<string name="policydesc_encryptedStorage" msgid="2637732115325316992">"저장한 애플리케이션 데이터를 암호화해야 합니다."</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"카메라 사용 안함"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 0dddde7..9d088f6 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"ມີການລຶບ <xliff:g id="CONTENT_TYPE">%s</xliff:g> ຫຼາຍເກີນໄປ."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"ພື້ນທີ່ຈັດເກັບຂໍ້ມູນໃນແທັບເລັດເຕັມ. ລຶບບາງໄຟລ໌ອອກເພື່ອເພີ່ມພື້ນທີ່ຫວ່າງ."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"ພື້ນທີ່ໃນໂທລະສັບເຕັມແລ້ວ. ກະລຸນາລຶບບາງໄຟລ໌ອອກເພື່ອເພີ່ມພື້ນທີ່ຫວ່າງ."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ການນຳໃຊ້ເຄືອຂ່າຍອາດມີການກວດສອບຕິດຕາມ"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ໂດຍບຸກຄົນທີສາມທີ່ບໍ່ຮູ້ຈັກ"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"ໂດຍ <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"ຂ້າພະເຈົ້າ"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"ໂຕເລືອກແທັບເລັດ"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"ໂຕເລືອກໂທລະສັບ"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ຂັດຂວາງການສະລັບແອັບຯ"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"ປ້ອງກັນບໍ່ໃຫ້ຜູ່ໃຊ້ສະຫຼັບໄປຫາແອັບຯອື່ນ."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"ດຶງຂໍ້ມູນແອັບຯໃນປັດຈຸບັນ"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງດຶງຂໍ້ມູນສ່ວນໂຕ ກ່ຽວກັບແອັບພລິເຄຊັນ ແລະ ການບໍລິການປັດຈຸບັນໃນໜ້າຈໍໄດ້."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງດຶງຂໍ້ມູນສ່ວນໂຕ ກ່ຽວກັບແອັບພລິເຄຊັນປັດຈຸບັນໃນສ່ວນຂອງໜ້າຈໍໄດ້."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"ຕິດຕາມ ແລະຄວບຄຸມການເປີດໂຕຂອງແອັບຯທັງໝົດ"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"ອະນຸຍາດໃຫ້ແອັບຯ ຕິດຕາມ ແລະຄວບຄຸມວິທີທີ່ລະບົບເລີ່ມການເຮັດວຽກຕ່າງໆ. ແອັບຯທີ່ເປັນອັນຕະລາຍ ອາດເຮັດໃຫ້ລະບົບທັງໝົດເກີດອັນຕະລາຍໄດ້. ການກຳນົດສິດນີ້ຈຳເປັນສຳລັບການພັດທະນາເທົ່ານັ້ນ, ບໍ່ແມ່ນສຳລັບການນຳໃຊ້ທົ່ວໄປ."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"ສົ່ງການກະຈ່າຍຂໍ້ມູນທີ່ເອົາແພັກເກດອອກແລ້ວ"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"ອະນຸຍາດໃຫ້ແອັບຯ ຄວບຄຸມຄວາມສາມາດລະດັບຕໍ່າຂອງການສະແດງຜົນ Wifi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ບັນທຶກສຽງອອກ"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ອະນຸຍາດໃຫ້ແອັບຯບັນທຶກ ແລະປ່ຽນເສັ້ນທາງການປ້ອນຂໍ້ມູນອອກຂອງສຽງ."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ການກວດຫາ Hotword"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"ອະນຸຍາດໃຫ້ແອັບຯຈັບຂໍ້ມູນສຽງສຳລັບການກວດຈັບ Hotword. ການຈັບຂໍ້ມູນສາມາດເກີດຂຶ້ນໃນພື້ນຫຼັງໄດ້ ແຕ່ຈະບໍ່ໄປຂັດຂວາງການຈັບຂໍ້ມູນສຽງອື່ນໆ (ເຊັ່ນ: ກ້ອງວິດີໂອ)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"ບັນທຶກວິດີໂອອອກ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"ອະນຸຍາດໃຫ້ແອັບຯບັນທຶກ ແລະປ່ຽນເສັ້ນທາງການປ້ອນຂໍ້ມູນອອກຂອງວິດີໂອ."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ບັນທຶກວິດີໂອອອກຢ່າງປອດໄພ"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ຂັດຂວາງບໍ່ໃຫ້ໂທລະສັບປິດໜ້າຈໍ"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ອະນຸຍາດໃຫ້ແອັບຯ ປ້ອງກັນບໍ່ໃຫ້ປິດໜ້າຈໍແທັບເລັດ."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"ອະນຸຍາດໃຫ້ແອັບຯປ້ອງກັນບໍ່ໃຫ້ປິດໜ້າຈໍໂທລະສັບ."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"ສົ່ງອິນຟຣາເຣດ"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"ອະນຸຍາດໃຫ້ແອັບຯໃຊ້ການສົ່ງອິນຟຣາເຣດຂອງແທັບເລັດໄດ້."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"ອະນຸຍາດໃຫ້ແອັບຯໃຊ້ການສົ່ງອິນຟຣາເຣດຂອງໂທລະສັບໄດ້."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"ເປີດ ຫຼືປິດແທັບເລັດ"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"ເປີດ ຫຼືປິດໂທລະສັບ"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"ອະນຸຍາດໃຫ້ແອັບຯເປີດ ຫຼືປິດແທັບເລັດ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 9fa2070..c575a21 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Per daug <xliff:g id="CONTENT_TYPE">%s</xliff:g> trynimo."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Planšetinio kompiuterio atmintis pilna. Kad atlaisvintumėte vietos, ištrinkite kelis failus."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefono atmintis pilna. Ištrinkite kai kuriuos failus, kad atlaisvintumėte vietos."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Tinklas gali būti stebimas"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Nežinoma trečioji šalis"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Aš"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Planšetinio kompiuterio parinktys"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefono parinktys"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"neleisti perjungti programų"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Neleidžiama naudotojui perjungti į kitą programą."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"gauti esamos programos informaciją"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Savininkui leidžiama gauti privačios informacijos apie dabartinę programą ir paslaugas, naudojamas ekrano priekiniame plane."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Savininkui leidžiama gauti privačią esamos pirmaeilės ekrano programos informaciją."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"stebėti ir valdyti visų programų paleidimą"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Leidžiama programai stebėti ir valdyti, kaip sistema paleidžia veiklą. Kenkėjiškos programos gali visiškai pažeisti sistemą. Šis leidimas reikalingas tik kuriant ir jo niekada nereikia naudojant įprastai."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"siųsti pašalinto paketo perdavimą"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Leidžiama programai valdyti „Wi-Fi“ pateikčių žemo lygio funkcijas."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"fiksuoti garso išvestį"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Programai leidžiama fiksuoti ir peradresuoti garso išvestį."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Aktyvinamųjų žodžių aptikimas"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Programai leidžiama įrašyti garsą, kad būtų galima aptikti aktyvinamuosius žodžius. Įrašymas gali būti vykdomas fone, bet tai netrikdo kitų garso įrašymo veiksmų (pvz., įrašymo vaizdo kamera)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"fiksuoti vaizdo išvestį"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Programai leidžiama fiksuoti ir peradresuoti vaizdo išvestį."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"fiksuoti saugią vaizdo išvestį"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"neleisti telefonui snausti"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Leidžiama programai neleisti planšetiniam kompiuteriui užmigti."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Leidžiama programai neleisti telefonui užmigti."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"perduoti duomenis infraraudonaisiais spinduliais"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Programai leidžiama naudoti planšetinio kompiuterio infraraudonųjų spindulių perdavimo įrenginį."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Programai leidžiama naudoti telefono infraraudonųjų spindulių perdavimo įrenginį."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"įjungti arba išjungti planšetinį kompiuterį"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"telefono įjungimas ir išjungimas"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Leidžiama programai įjungti ar išjungti planšetinį kompiuterį."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5d81fc7..0dda696 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Pārāk daudz <xliff:g id="CONTENT_TYPE">%s</xliff:g> dzēsto vienumu."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Planšetdatora atmiņa ir pilna. Dzēsiet dažus failus, lai atbrīvotu vietu."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Tālruņa atmiņa ir pilna! Dzēsiet dažus failus, lai atbrīvotu vietu."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Iespējams, tīklā veiktās darbības tiek pārraudzītas."</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Nezināma trešā puse"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Domēns <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Man"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Planšetdatora opcijas"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Tālruņa opcijas"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"novērst lietojumprogrammu pārslēgšanu"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Novērš lietotāja pārslēgšanos uz citu lietotni."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"pašreizējās lietotnes informācijas iegūšana"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Ļauj īpašniekam izgūt privātu informāciju par pašreizējo lietojumprogrammu un pakalpojumiem ekrāna priekšplānā."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Ļauj īpašniekam izgūt privātu informāciju par pašreizējo lietojumprogrammu ekrāna priekšplānā."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"pārraudzīt un kontrolēt visu lietotņu atvēršanu"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Ļauj lietotnei pārraudzīt un kontrolēt, kā sistēmā tiek palaistas darbības. Ļaunprātīgas lietotnes var pilnībā uzlauzt sistēmu. Šī atļauja ir nepieciešama tikai izstrādei, taču ne parastai lietošanai."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"sūtīt apraidi par pakotnes noņemšanu"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Ļauj lietotnei kontrolēt zema līmeņa funkcijas Wi-Fi displejos."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"tvert audio izvadi"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Ļauj lietotnei tvert un novirzīt audio izvadi."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Īsinājumvārda noteikšana"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Ļauj lietotnei tvert audio īsinājumvārda noteikšanai. Tveršana var notikt fonā, taču tā neaizkavē citu audio (piemēram, videokameras audio) tveršanu."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"tvert video izvadi"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Ļauj lietotnei tvert un novirzīt video izvadi."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"tvert drošu video izvadi"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"novērst tālruņa pāriešanu miega režīmā"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ļauj lietotnei novērst planšetdatora pāriešanu miega režīmā."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Ļauj lietotnei novērst tālruņa pāriešanu miega režīmā."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"pārraidīt infrasarkano staru signālu"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Ļauj lietotnei izmantot planšetdatora infrasarkano staru signāla raidītāju."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Ļauj lietotnei izmantot tālruņa infrasarkano staru signāla raidītāju."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"ieslēgt vai izslēgt planšetdatoru"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"ieslēgt vai izslēgt tālruni"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Ļauj lietotnei ieslēgt vai izslēgt planšetdatoru."</string>
diff --git a/core/res/res/values-mcc510-mnc21/config.xml b/core/res/res/values-mcc510-mnc21/config.xml
new file mode 100644
index 0000000..1fd9dfa
--- /dev/null
+++ b/core/res/res/values-mcc510-mnc21/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Don't use roaming icon for considered operators -->
+ <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+ <item>51001</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 3fe7899..b456d3e 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Хэт олон <xliff:g id="CONTENT_TYPE">%s</xliff:g> устгах."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Таблетийн сан дүүрсэн. Зай чөлөөлөх бол зарим файлыг устгана уу."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Утасны сан дүүрсэн. Зай чөлөөлөх бол зарим файлыг устгана уу."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Сүлжээ хянагдаж байж болзошгүй"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Тодорхойгүй гуравдагч талаас"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>-с"</string>
<string name="me" msgid="6545696007631404292">"Би"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Таблетын сонголтууд"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Утасны сонголт"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"апп шилжүүлэхийг хориглох"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Хэрэглэгч бусад апп-руу сэлгэхийг хориглох."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"одоогийн апп-н мэдээллийг авах"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Эзэмшигч нь дэлгэцний нүүрэнд байгаа одоогийн аппликешн болон үйлчилгээний талаарх хувийн мэдээллийг унших боломжтой."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Эзэмшигч нь дэлгэцний нүүрэнд байгаа одоогийн аппликешны талаарх хувийн мэдээллийг унших боломжтой."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"бүх апп-ын эхлэлийг хянах болон удирдах"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Апп нь систем активитиг яаж эхлүүлж байгааг хянах болон удирдан боломжтой. Хортой апп нь системд бүрэн нөлөөлж болзошгүй. Энэ эрх нь зөвхөн хөгжүүлэлтийн үед л хэрэгтэй ба энгийн хэрэглээнд огт хэрэггүй."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"багц хасагдсан өргөн дамжууллыг илгээх"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Апп нь Wifi дэлгэцний доод-төвшиний функцийг удирдах боломжтой."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"аудио гаралтыг барих"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Апп-т аудио гаралтыг барих, дахин чиглүүлэхийг зөвшөөрнө."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Хотворд таних"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Апп-д Хотворд илрүүлэхийн тулд аудиог бичихийг зөвшөөрнө. Бичилт далд хийгдэх бөгөөд бусад аудио бичилтэд (жнь. видео бичлэг) саад болохгүй."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"видео гаралтыг барих"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Апп-т видео гаралтыг барих, дахин чиглүүлэхийг зөвшөөрнө."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"найдвартай видео гаралтыг барих"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"утсыг унтуулахгүй байлгах"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Апп нь таблетыг унтахаас сэргийлэх боломжтой"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Апп нь утсыг унтахаас сэргийлэх боломжтой"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"хэт улаанаар дамжуулах"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Апп-д таблетын хэт улаан дамжуулагчийг ашиглахыг зөвшөөрнө."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Апп-д утасны хэт улаан дамжуулагчийг ашиглахыг зөвшөөрнө."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"таблетыг унтраах эсвэл асаах"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"утсыг унтраах эсвэл асаах"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Апп нь таблетыг асаах, унтраах боломжтой."</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 748fc5a..b266591 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Terlalu banyak pemadaman <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Storan tablet penuh. Padamkan beberapa fail untuk mengosongkan ruang."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Storan telefon penuh. Padamkan beberapa fail untuk mengosongkan ruang."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rangkaian mungkin dipantau"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Saya"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Pilihan tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Pilihan telefon"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"halang pertukaran apl"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Menghalang pengguna daripada bertukar kepada apl lain."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"dapatkan maklumat apl semasa"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Membenarkan pemegang mendapatkan maklumat peribadi tentang aplikasi dan perkhidmatan semasa di latar hadapan skrin."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Membenarkan pemegang mendapatkan maklumat peribadi tentang permohonan semasa di latar hadapan skrin"</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"pantau dan kawal semua pelancaran apl"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Membenarkan apl untuk memantau dan mengawal cara sistem melancarkan aktiviti. Apl hasad boleh menjejaskan sistem sepenuhnya. Kebenaran ini hanya diperlukan untuk pembangunan, tidak sekali-kali untuk penggunaan biasa."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"hantar siaran bahawa pakej telah dialih keluar"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Membenarkan apl mengawal ciri tahap rendah paparan Wifi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"tangkap output audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Membenarkan apl menangkap dan mengubah hala output audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Pengesanan sebutan laluan"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Benarkan apl merakam audio untuk pengesahan Sebutan Laluan. Rakaman ini boleh berlaku di latar belakang tetapi tidak menghalang rakaman audio lain (cth. Kamkorder)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"tangkap output video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Membenarkan apl menangkap dan mengubah hala output video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"tangkap output video selamat"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"halang telefon daripada tidur"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Membenarkan apl menghalang tablet daripada tidur."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Membenarkan apl menghalang telefon daripada tidur."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"hantar inframerah"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Membenarkan apl menggunakan pemancar inframerah tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Membenarkan apl menggunakan pemancar inframerah telefon."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"menghidupkan atau mematikan kuasa tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"kuasakan telefon hidup atau mati"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Membenarkan apl menghidupkan atau mematikan tablet."</string>
@@ -1578,8 +1588,8 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN tidak sepadan. Cuba lagi."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN terlalu pendek. Mesti sekurang-kurangnya 4 angka."</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="311050995198548675">"Cuba lg dlm 1 st"</item>
- <item quantity="other" msgid="4730868920742952817">"Cuba lg dlm <xliff:g id="COUNT">%d</xliff:g> st"</item>
+ <item quantity="one" msgid="311050995198548675">"Cuba 1 saat lagi"</item>
+ <item quantity="other" msgid="4730868920742952817">"Cuba <xliff:g id="COUNT">%d</xliff:g> saat lagi"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Cuba sebentar lagi"</string>
<string name="transient_navigation_confirmation" msgid="4907844043611123426">"Leret bhg tepi skrin utk serlah bar"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index f53f817..c0d58aa 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"For mange slettinger av <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Nettbrettlageret er fullt. Slett noen filer for å frigjøre lagringsplass."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonlageret er fullt. Slett noen filer for å frigjøre lagringsplass."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Nettverket blir muligens overvåket"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Av en ukjent tredjepart"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Av <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Meg"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Innstillinger for nettbrettet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefoninnstillinger"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"forhindre bytte mellom apper"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Hindrer brukeren i å bytte til en annen app."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"få informasjon om appen"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Tillater innehaveren å hente privat informasjon om den gjeldende appen og tjenester i forgrunnen av skjermen."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Tillater brukeren å få tilgang til privat informasjon om den aktuelle appen i forgrunnen på skjermen."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"overvåke og kontrollere all oppstart av apper"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Lar appen overvåke og kontrollere hvordan systemet starter opp aktiviteter. Ondsinnede apper kan utsette hele systemet for sikkerhetsbrudd. Denne tillatelsen er bare nødvendig for utviklere, aldri for vanlig bruk."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"kringkaste melding om fjernet pakke"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Tillater appen å kontrollere lavnivåfunksjoner i Wi-Fi-skjermer."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ta opp fra lydutdata"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Lar appen ta opp og omdirigere lydutdata."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Gjenkjennelse av kommandoord"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Gir appen tillatelse til å ta opp lyd for å gjenkjenne kommandoord. Opptaket kan skje i bakgrunnen, men forhindrer ikke lydopptak i andre funksjoner (f.eks. i videoopptak)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"ta opp fra videoutdata"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Lar appen ta opp og omdirigere videoutdata."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ta opp fra sikre videoutdata"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"forhindre telefonen fra å sove"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Lar appen hindre nettbrettet fra å gå over i sovemodus."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Lar appen hindre telefonen fra å gå over i sovemodus."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infrarød overføring"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Gir appen tillatelse til å bruke nettbrettets infrarøde sender."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Gir appen tillatelse til å bruke telefonens infrarøde sender."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"slå på eller av nettbrettet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"slå telefonen av eller på"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Lar appen slå på eller av nettbrettet."</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 67775da..20ab30e 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -314,7 +314,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"अनुप्रयोग स्विचहरू जोगाउनुहोस्"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"अन्य अनुप्रयोगमा स्विच गर्नबाट प्रयोगकर्ताहरूलाई रोक्छ।"</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"वर्तमान अनुप्रयोगको जानकारी प्राप्त गर्नुहोस्"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"स्क्रिनको अग्र भागमा हालको अनुप्रयोग र सेवाहरूका बारे निजी जानकारी निकाल्न बाहकलाई अनुमति दिन्छ।"</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"होल्डरलाई स्क्रिनको पृष्ठभूमिमा वर्तमान अनुप्रयोगको बारेमा व्यक्तिगत जानकारी पुनःप्राप्त गर्न अनुमति दिन्छ।"</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"सबै अनुप्रयोग सुरुवात गर्ने निरीक्षण र नियन्त्रण गर्नुहोस्"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"अनुप्रयोगलाई कसरी प्रणाली सुरुवात गतिहरू मोनिटर गर्न र नियन्त्रण गर्न अनुमति दिन्छ। खराब अनुप्रयोगहरूले प्रणालीमा पूर्ण सहमत गर्न सक्दछ। यो अनुमति केवल विकासको लागि आवश्यक छ, साधारण प्रयोगको लागि कहिले होइन।"</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"प्याकेज हटाइएको प्रसारणलाई पठाउनुहोस्"</string>
@@ -655,6 +655,8 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"प्रयोगकर्तालाई वाहक-प्रदान विन्यास अनुप्रयोग सुरु गर्न अनुमति दिन्छ। साधारण अनुप्रयोगहरूलाई कहिल्यै आवश्यक पर्ने छैन।"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"सञ्जाल अवस्थाका पर्यवेक्षणका लागि सुन्नुहोस्"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"सञ्जाल अवस्थाका पर्यवेक्षण सुन्नका लागि अनुप्रयोगलाई अनुमति दिन्छ।सामान्य अनुप्रयोगलाई चाँहिदै नचाँहिन सक्छ।"</string>
+ <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"जल्दोबल्दो शब्द पहिचानका लागि अनुरोध गर्नुहोस्"</string>
+ <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"जल्दाबल्दा शब्द पहिचानका लागि अनुरोध पठाउन अनुप्रयोगलाई अनुमति दिन्छ।सामान्य अनुप्रयोगका लागि यो कहिल्यै नचाहिन सक्छ।"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियमहरू मिलाउनुहोस्"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"स्क्रिन-अनलक पासवर्डहरूमा अनुमति दिइएको लम्बाइ र अक्षरहरू नियन्त्रण गर्नुहोस्।"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"मोनिटर स्क्रिन-अनलक प्रयत्नहरू"</string>
@@ -1568,7 +1570,7 @@
<string name="write_fail_reason_cancelled" msgid="7091258378121627624">"रद्द गरियो"</string>
<string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"सामाग्री लेखनमा त्रुटि"</string>
<string name="reason_unknown" msgid="6048913880184628119">"अज्ञात"</string>
- <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"प्रशासक PIN प्रविष्ट गर्नुहोस्"</string>
+ <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"प्रशासक PIN प्रविष्टि गर्नुहोस्"</string>
<string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN प्रविष्टि गर्नुहोस्"</string>
<string name="restr_pin_incorrect" msgid="8571512003955077924">"गलत"</string>
<string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"वर्तमान PIN"</string>
@@ -1578,10 +1580,10 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN हरू मेल खाएनन्। पुनः प्रयास गर्नुहोस्।"</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN अति छोटो भयो। कम्तीमा ४ अङ्क हुन आवश्यक छ।"</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="311050995198548675">"१ सेकेन्ड पछि पुन: प्रयास गर्नुहोला।"</item>
- <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्डमा पुन: प्रयास गर्नुहोस्"</item>
+ <item quantity="one" msgid="311050995198548675">"१ सेकेन्ड पछि पुनः प्रयास गर्नुहोस्।"</item>
+ <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्डमा पुनः प्रयास गर्नुहोस्"</item>
</plurals>
- <string name="restr_pin_try_later" msgid="973144472490532377">"पछि पुन: प्रयास गर्नुहोस्"</string>
+ <string name="restr_pin_try_later" msgid="973144472490532377">"पछि पुनः प्रयास गर्नुहोस्"</string>
<string name="transient_navigation_confirmation" msgid="4907844043611123426">"पट्टि देखिने बनाउन स्क्रिनको छेउमा स्वाइप गर्नुहोस्"</string>
<string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"प्रणाली पट्टि देखिने बनाउन स्क्रिनको छेउबाट स्वाइप गर्नुहोस्"</string>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index db0c218..3a97f95 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Te veel verwijderen voor <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tabletgeheugen is vol. Verwijder enkele bestanden om ruimte vrij te maken."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefoongeheugen is vol. Verwijder enkele bestanden om ruimte vrij te maken."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netwerk kan worden gecontroleerd"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Door een onbekende derde partij"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Door <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Ik"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tabletopties"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefoonopties"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"schakelen tussen apps voorkomen"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Hiermee wordt voorkomen dat de gebruiker overschakelt naar een andere app."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"huidige appgegevens ophalen"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Hiermee kan de houder persoonlijke gegevens ophalen over de app en services die momenteel op de voorgrond worden weergegeven."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"De houder kan hiermee persoonlijke gegevens ophalen over de applicatie die momenteel op de voorgrond wordt weergegeven."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"alle startende apps bijhouden en beheren"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Hiermee kan de app de manier bijhouden en beheren waarop het systeem activiteiten start. Schadelijke apps kunnen het systeem volledig in gevaar brengen. Deze machtiging is alleen voor ontwikkeling vereist, nooit voor normaal gebruik."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"melding verzenden dat pakket is verwijderd"</string>
@@ -436,12 +439,12 @@
<string name="permlab_writeContacts" msgid="5107492086416793544">"uw contacten aanpassen"</string>
<string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Hiermee kan de app gegevens wijzigen over de contacten die zijn opgeslagen op uw tablet, inclusief de frequentie waarmee u heeft gebeld, gemaild of op andere manieren heeft gecommuniceerd met specifieke contacten. Met deze toestemming kunnen apps contactgegevens verwijderen."</string>
<string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Hiermee kan de app gegevens wijzigen over de contacten die zijn opgeslagen op uw telefoon, inclusief de frequentie waarmee u heeft gebeld, gemaild of op andere manieren heeft gecommuniceerd met specifieke contacten. Met deze toestemming kunnen apps contactgegevens verwijderen."</string>
- <string name="permlab_readCallLog" msgid="3478133184624102739">"oproeplogboek lezen"</string>
- <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Hiermee kan de app het oproeplogboek van uw tablet lezen, inclusief gegevens over inkomende en uitgaande oproepen. Met deze toestemming kunnen apps uw oproeploggegevens opslaan, en schadelijke apps kunnen logoproepgegevens zonder uw medeweten delen."</string>
- <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Hiermee kan de app het oproeplogboek van uw telefoon lezen, inclusief gegevens over inkomende en uitgaande oproepen. Met deze toestemming kunnen apps uw oproeploggegevens opslaan, en schadelijke apps kunnen logoproepgegevens zonder uw medeweten delen."</string>
- <string name="permlab_writeCallLog" msgid="8552045664743499354">"oproeplogboek schrijven"</string>
- <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Toestaan dat de app het oproeplogboek van uw tablet aanpast, waaronder gegevens over inkomende en uitgaande oproepen. Schadelijke apps kunnen hiermee uw oproeplogboek wissen of aanpassen."</string>
- <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Toestaan dat de app het oproeplogboek van uw telefoon aanpast, waaronder gegevens over inkomende en uitgaande oproepen. Schadelijke apps kunnen hiermee uw oproeplogboek wissen of aanpassen."</string>
+ <string name="permlab_readCallLog" msgid="3478133184624102739">"gesprekkenlijst lezen"</string>
+ <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Hiermee kan de app het gesprekkenlijst van uw tablet lezen, inclusief gegevens over inkomende en uitgaande oproepen. Met deze toestemming kunnen apps uw oproeploggegevens opslaan, en schadelijke apps kunnen logoproepgegevens zonder uw medeweten delen."</string>
+ <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Hiermee kan de app het gesprekkenlijst van uw telefoon lezen, inclusief gegevens over inkomende en uitgaande oproepen. Met deze toestemming kunnen apps uw oproeploggegevens opslaan, en schadelijke apps kunnen logoproepgegevens zonder uw medeweten delen."</string>
+ <string name="permlab_writeCallLog" msgid="8552045664743499354">"gesprekkenlijst schrijven"</string>
+ <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Toestaan dat de app het gesprekkenlijst van uw tablet aanpast, waaronder gegevens over inkomende en uitgaande oproepen. Schadelijke apps kunnen hiermee uw gesprekkenlijst wissen of aanpassen."</string>
+ <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Toestaan dat de app het gesprekkenlijst van uw telefoon aanpast, waaronder gegevens over inkomende en uitgaande oproepen. Schadelijke apps kunnen hiermee uw gesprekkenlijst wissen of aanpassen."</string>
<string name="permlab_readProfile" msgid="4701889852612716678">"uw eigen contactkaart lezen"</string>
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Hiermee kan de app persoonlijke profielgegevens lezen die op uw apparaat zijn opgeslagen, zoals uw naam en contactgegevens. Dit betekent dat de app u kan identificeren en uw profielgegevens naar anderen kan verzenden."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"uw eigen contactkaart aanpassen"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"De app toestaan minder belangrijke functies van wifi-displays te beheren."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"audio-uitvoer vastleggen"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Hiermee kan de app audio-uitvoer vastleggen en verwerken."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detectie van hotwords"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Hiermee kan de app audio opnemen voor het detecteren van hotwords. Het opnemen kan op de achtergrond plaatsvinden, maar voorkomt niet dat andere audio wordt opgenomen (bijvoorbeeld in Camcorder)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"video-uitvoer vastleggen"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Hiermee kan de app video-uitvoer vastleggen en verwerken."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"beveiligde video-uitvoer vastleggen"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"voorkomen dat telefoon overschakelt naar slaapmodus"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Hiermee kan de app voorkomen dat de tablet overschakelt naar de slaapmodus."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Hiermee kan de app voorkomen dat de telefoon overschakelt naar de slaapmodus."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infrarood verzenden"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Hiermee kan de app de infraroodzender van de tablet gebruiken."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Hiermee kan de app de infraroodzender van de telefoon gebruiken."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"tablet in- of uitschakelen"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"telefoon in- of uitschakelen"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Hiermee kan de app de tablet in- of uitschakelen."</string>
@@ -846,7 +854,7 @@
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Patroon vergeten?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Account ontgrendelen"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Te veel patroonpogingen"</string>
- <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Als u wilt ontgrendelen, moet u zich aanmelden bij uw Google-account."</string>
+ <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Log in op uw Google-account om te ontgrendelen."</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Gebruikersnaam (e-mail)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Wachtwoord"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Inloggen"</string>
@@ -1161,7 +1169,7 @@
<item quantity="one" msgid="1634101450343277345">"Open wifi-netwerk beschikbaar"</item>
<item quantity="other" msgid="7915895323644292768">"Open wifi-netwerken beschikbaar"</item>
</plurals>
- <string name="wifi_available_sign_in" msgid="4029489716605255386">"Aanmelden bij wifi-netwerk"</string>
+ <string name="wifi_available_sign_in" msgid="4029489716605255386">"Inloggen op wifi-netwerk"</string>
<string name="network_available_sign_in" msgid="8495155593358054676">"Inloggen bij netwerk"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index d2cf5b8..3196373 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zbyt wiele usuwanych <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Pamięć tabletu jest pełna. Usuń niektóre pliki, aby zwolnić miejsce."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Pamięć telefonu jest pełna. Usuń niektóre pliki, aby zwolnić miejsce."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Sieć może być monitorowana"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Przez nieznaną firmę zewnętrzną"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Przez <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opcje tabletu"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opcje telefonu"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zapobieganie przełączaniu aplikacji"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Uniemożliwia użytkownikowi przełączenie na inną aplikację."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"pobierz informacje o bieżącej aplikacji"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Pozwala właścicielowi na pobieranie prywatnych informacji o bieżącej aplikacji i usługach widocznych na ekranie."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Zezwala posiadaczowi na pobieranie prywatnych informacji o bieżącej aplikacji i wyświetlanie ich na pierwszym planie ekranu."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitorowanie i kontrolowanie wszystkich uruchamianych aplikacji"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Pozwala aplikacji na monitorowanie i kontrolowanie sposobu uruchamiania działań przez system. Złośliwe aplikacje mogą całkowicie naruszyć zabezpieczenia systemu. To uprawnienie nigdy nie jest potrzebne podczas normalnego użytkowania, a jedynie podczas programowania."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"wysyłanie transmisji informującej o usuniętym pakiecie"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Zezwala aplikacji na zarządzanie niskopoziomowymi funkcjami wyświetlaczy Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"przechwyć wyjście audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Zezwala aplikacji na przechwytywanie i przekierowywanie wyjścia audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Wykrywanie słów-kluczy"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Umożliwia aplikacji przechwytywanie dźwięku w celu wykrywania słów-kluczy. Może się to odbywać w tle i nie uniemożliwia innego przechwytywania dźwięku (np. z kamery)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"przechwyć wyjście wideo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Zezwala aplikacji na przechwytywanie i przekierowywanie wyjścia wideo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"przechwyć bezpieczne wyjście wideo"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zapobieganie przejściu telefonu w stan uśpienia"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Pozwala aplikacji na zapobieganie przechodzeniu tabletu do trybu uśpienia."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Pozwala aplikacji na zapobieganie przechodzeniu telefonu w tryb uśpienia."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"przesyłanie w podczerwieni"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Zezwala aplikacji na używanie nadajnika podczerwieni w tablecie."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Zezwala aplikacji na używanie nadajnika podczerwieni w telefonie."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"włączenie lub wyłączenie tabletu"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"włączanie lub wyłączanie telefonu"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Pozwala aplikacji na włączanie i wyłączanie tabletu."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index a21994b..69884ab 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -100,7 +100,7 @@
<string name="roamingText9" msgid="7969296811355152491">"Roaming - Funcionalidade de Serviço Total"</string>
<string name="roamingText10" msgid="3992906999815316417">"Roaming - Funcionalidade de Serviço Parcial"</string>
<string name="roamingText11" msgid="4154476854426920970">"Faixa de Roaming activada"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Faixa de Roaming desactivada"</string>
+ <string name="roamingText12" msgid="1189071119992726320">"Faixa de Roaming desativada"</string>
<string name="roamingTextSearching" msgid="8360141885972279963">"A procurar Serviço"</string>
<string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
<string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -131,12 +131,17 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminações de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"O armazenamento do tablet está cheio. Elimine alguns ficheiros para libertar espaço."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"O armazenamento do telemóvel está cheio. Elimine alguns ficheiros para libertar espaço."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"A rede pode ser monitorizada"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opções do tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opções do telefone"</string>
<string name="silent_mode" msgid="7167703389802618663">"Modo silencioso"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Activar sem fios"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Desactivar sem fios"</string>
+ <string name="turn_on_radio" msgid="3912793092339962371">"Ativar sem fios"</string>
+ <string name="turn_off_radio" msgid="8198784949987062346">"Desativar sem fios"</string>
<string name="screen_lock" msgid="799094655496098153">"Bloqueio de ecrã"</string>
<string name="power_off" msgid="4266614107412865048">"Desligar"</string>
<string name="silent_mode_silent" msgid="319298163018473078">"Campainha desativada"</string>
@@ -237,7 +242,7 @@
<string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Poderão ser instalados scripts para tornar o conteúdo da aplicação mais acessível."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Observar o texto que escreve"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclui dados pessoais, como números de cartões de crédito e palavras-passe."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"desactivar ou modificar barra de estado"</string>
+ <string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar barra de estado"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite à aplicação desativar a barra de estado ou adicionar e remover ícones do sistema."</string>
<string name="permlab_statusBarService" msgid="7247281911387931485">"barra de estado"</string>
<string name="permdesc_statusBarService" msgid="716113660795976060">"Permite que a aplicação seja apresentada na barra de estado."</string>
@@ -289,7 +294,7 @@
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que a aplicação ative a depuração para outra aplicação. As aplicações maliciosas podem utilizar isto para eliminar outras aplicações."</string>
<string name="permlab_changeConfiguration" msgid="4162092185124234480">"alterar as definições de visualização do sistema"</string>
<string name="permdesc_changeConfiguration" msgid="4372223873154296076">"Permite à aplicação alterar a configuração atual, como o local ou o tamanho global do tipo de letra."</string>
- <string name="permlab_enableCarMode" msgid="5684504058192921098">"activar modo de carro"</string>
+ <string name="permlab_enableCarMode" msgid="5684504058192921098">"ativar modo de carro"</string>
<string name="permdesc_enableCarMode" msgid="4853187425751419467">"Permite que a aplicação ative o modo automóvel."</string>
<string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"fechar outras aplicações"</string>
<string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Permite que a aplicação termine processos em segundo plano de outras aplicações. Isto pode fazer com que outras aplicações deixem de funcionar."</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedir trocas de aplicações"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Impede que o utilizador mude para outra aplicação."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"obter informações da aplicação atual"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Permite ao titular obter informações privadas acerca da aplicação e dos serviços atuais no primeiro plano do ecrã."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permite ao titular recuperar informações privadas acerca da aplicação atual no primeiro plano do ecrã."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitorizar e controlar a iniciação de todas as aplicações"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permite que uma aplicação monitorize e controle a forma como o sistema inicia atividades. As aplicações maliciosas podem comprometer totalmente o sistema. Esta autorização só é necessária para programação, nunca para utilização normal."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar difusão de pacote removido"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que a aplicação controle funcionalidades de baixo nível em visores Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capturar saída de áudio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite à aplicação capturar e redirecionar a saída de áudio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Deteção de Palavra de ativação"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permite à aplicação capturar áudio para deteção da Palavra de ativação. A captura pode acontecer em segundo plano, mas não impede outras capturas de áudio (por exemplo com câmara de vídeo)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capturar saída de vídeo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite à aplicação capturar e redirecionar a saída de vídeo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capturar saída de vídeo segura"</string>
@@ -488,8 +495,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que a aplicação tire fotografias e grave vídeos com a câmara. Esta autorização permite que a aplicação utilize a câmara sem a sua confirmação em qualquer altura."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"desativar LED indicador de transmissão com a câmara em utilização"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permite que uma aplicação de sistema pré-instalada desative o LED indicador de utilização da câmara."</string>
- <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desactivar tablet de forma permanente"</string>
- <string name="permlab_brick" product="default" msgid="8337817093326370537">"desactivar telefone de forma permanente"</string>
+ <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desativar tablet de forma permanente"</string>
+ <string name="permlab_brick" product="default" msgid="8337817093326370537">"desativar telefone de forma permanente"</string>
<string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"Permite que a aplicação desative definitivamente todo o tablet. Esta ação é muito perigosa."</string>
<string name="permdesc_brick" product="default" msgid="5788903297627283099">"Permite que a aplicação desative definitivamente todo o telemóvel. Esta ação é muito perigosa."</string>
<string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"forçar reinício do tablet"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir modo de inactividade do telefone"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que a aplicação impeça o tablet de entrar no modo de suspensão."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permite que a aplicação impeça o telemóvel de entrar em inatividade."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmitir infravermelhos"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permite que a aplicação utilize o transmissor de infravermelhos do tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permite que a aplicação utilize o transmissor de infravermelhos do telemóvel."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"ligar ou desligar o tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"ligar ou desligar o telefone"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permite que uma aplicação ligue ou desligue o tablet."</string>
@@ -1094,7 +1104,7 @@
<string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
<string name="loading" msgid="7933681260296021180">"A carregar…"</string>
<string name="capital_on" msgid="1544682755514494298">"Ativado"</string>
- <string name="capital_off" msgid="6815870386972805832">"Desactivar"</string>
+ <string name="capital_off" msgid="6815870386972805832">"Desativar"</string>
<string name="whichApplication" msgid="4533185947064773386">"Concluir ação utilizando"</string>
<string name="alwaysUse" msgid="4583018368000610438">"Utilizar por predefinição para esta acção."</string>
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"Limpar a predefinição nas Definições do Sistema > Aplicações > Transferidas."</string>
@@ -1214,19 +1224,19 @@
<string name="usb_storage_title" msgid="5901459041398751495">"Ligado através de USB"</string>
<string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"Ligou ao computador através de USB. Toque no botão abaixo se pretender copiar ficheiros entre o computador e a memória de armazenamento USB do Android."</string>
<string name="usb_storage_message" product="default" msgid="805351000446037811">"Ligou ao computador através de USB. Toque no botão abaixo se pretender copiar ficheiros entre o computador e o cartão SD do Android."</string>
- <string name="usb_storage_button_mount" msgid="1052259930369508235">"Activar armazenamento USB"</string>
+ <string name="usb_storage_button_mount" msgid="1052259930369508235">"Ativar armazenamento USB"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"Existe um problema ao utilizar a memória de armazenamento USB para o armazenamento em massa USB."</string>
<string name="usb_storage_error_message" product="default" msgid="2876018512716970313">"Existe um problema ao utilizar o cartão SD para armazenamento em massa USB."</string>
<string name="usb_storage_notification_title" msgid="8175892554757216525">"Ligado através de USB"</string>
<string name="usb_storage_notification_message" msgid="939822783828183763">"Toque para copiar ficheiros para/do computador."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Desactivar armazenamento USB"</string>
+ <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Desativar armazenamento USB"</string>
<string name="usb_storage_stop_notification_message" msgid="1656852098555623822">"Toque para desativar a memória de armazenamento USB."</string>
<string name="usb_storage_stop_title" msgid="660129851708775853">"O armazenamento USB está a ser utilizado"</string>
<string name="usb_storage_stop_message" product="nosdcard" msgid="4264025280777219521">"Antes de desativar a memória de armazenamento USB, desmonte (\"ejete\") a memória de armazenamento USB do Android do computador."</string>
<string name="usb_storage_stop_message" product="default" msgid="8043969782460613114">"Antes de desativar a memória de armazenamento USB, desmonte (\"ejete\") o cartão SD do Android do computador."</string>
- <string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"Desactivar armazenamento USB"</string>
+ <string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"Desativar armazenamento USB"</string>
<string name="usb_storage_stop_error_message" msgid="1970374898263063836">"Ocorreu um problema ao desativar a memória de armazenamento USB. Verifique se desinstalou o anfitrião USB e, em seguida, tente novamente."</string>
- <string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Activar armazenamento USB"</string>
+ <string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Ativar armazenamento USB"</string>
<string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Se ativar a memória de armazenamento USB, algumas aplicações que estiver a utilizar serão paradas e poderão ficar indisponíveis até desativar a memória de armazenamento USB."</string>
<string name="dlg_error_title" msgid="7323658469626514207">"Operação USB sem êxito"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 1189c2a..3a86f55 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Muitas exclusões de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"O armazenamento do tablet está cheio. Exclua alguns arquivos para liberar espaço."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"O armazenamento do telefone está cheio. Exclua alguns arquivos para liberar espaço."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"A rede pode ser monitorada"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por terceiros desconhecidos"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opções do tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opções do telefone"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"evitar trocas de aplicativo"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Impede que o usuário alterne para outro aplicativo."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"obter informações do aplicativo atual"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Permite que o proprietário armazene informações particulares sobre o aplicativo e os serviços em primeiro plano na tela."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permite ao titular recuperar informações particulares sobre o aplicativo atual em primeiro plano na tela."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitorar e controlar todos os aplicativos que estão sendo iniciados"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permite que o aplicativo monitore e controle a forma como o sistema inicia atividades. Aplicativos maliciosos podem comprometer completamente o sistema. Esta permissão só é necessária para o desenvolvimento, nunca para o uso normal."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar transmissão removida do pacote"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que o aplicativo controle recursos de baixo nível de monitores Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capturar saída de áudio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite que o aplicativo capture e redirecione a saída de áudio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detecção de hotwords"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permite que o dispositivo capture áudio para a detecção de hotwords. A captura pode acontecer em segundo plano, mas não impede outras capturas de áudio (como por uma câmera de vídeo)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capturar saída de vídeo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite que o aplicativo capture e redirecione a saída de vídeo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capturar saída de vídeo segura"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir modo de inatividade do telefone"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que o aplicativo impeça o tablet de entrar no modo de inatividade."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permite que o aplicativo impeça o telefone de entrar no modo de inatividade."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmitir infravermelhos"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permite que o aplicativo use o transmissor infravermelho do tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permite que o aplicativo use o transmissor infravermelho do telefone."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"ligar ou desligar o tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"ligar ou desligar o telefone"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permite que o aplicativo ative ou desative o tablet."</string>
@@ -656,7 +664,7 @@
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"detectar observações nas condições da rede"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que o aplicativo detecte observações nas condições da rede. Não deve ser necessário para aplicativos comuns."</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="policydesc_limitPassword" msgid="3252114203919510394">"Controlar 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>
<string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Monitorar quantas vezes a senha foi digitada incorretamente ao desbloquear a tela e bloquear o tablet ou apagar todos os dados do tablet se a senha for digitada incorretamente muitas vezes."</string>
<string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Monitorar quantas vezes a senha foi digitada incorretamente ao desbloquear a tela e bloquear o telefone ou apagar todos os dados do telefone se a senha for digitada incorretamente muitas vezes."</string>
@@ -666,7 +674,7 @@
<string name="policydesc_forceLock" msgid="1141797588403827138">"Controle como e quando a tela é bloqueada."</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Apagar todos os dados"</string>
<string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Apague os dados do tablet sem aviso redefinindo a configuração original."</string>
- <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Apague os dados do telefone sem aviso redefinindo a configuração original."</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Apagar os dados do telefone sem aviso redefinindo a configuração original."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir o proxy global do dispositivo"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configura o proxy global do dispositivo para ser usado enquanto a política estiver ativada. Somente o primeiro administrador do dispositivo pode configurar um verdadeiro proxy global."</string>
<string name="policylab_expirePassword" msgid="885279151847254056">"Definir val. da senha de bloqueio"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 68f0e06..c4b5e5b 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -158,6 +158,12 @@
<skip />
<!-- no translation found for low_memory (3475999286680000541) -->
<skip />
+ <!-- no translation found for ssl_ca_cert_warning (5848402127455021714) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Jau"</string>
<!-- no translation found for power_dialog (8545351420865202853) -->
<skip />
@@ -479,7 +485,7 @@
<skip />
<!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
<skip />
- <!-- no translation found for permdesc_getTopActivityInfo (8153651434145132505) -->
+ <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
<skip />
<!-- no translation found for permlab_runSetActivityWatcher (892239094867182656) -->
<skip />
@@ -781,6 +787,10 @@
<skip />
<!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
<skip />
+ <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
+ <skip />
+ <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
+ <skip />
<!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
<skip />
<!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
@@ -900,6 +910,12 @@
<skip />
<!-- no translation found for permdesc_wakeLock (8559100677372928754) -->
<skip />
+ <!-- no translation found for permlab_transmitIr (7545858504238530105) -->
+ <skip />
+ <!-- no translation found for permdesc_transmitIr (5358308854306529170) -->
+ <skip />
+ <!-- no translation found for permdesc_transmitIr (7957763745020300725) -->
+ <skip />
<!-- no translation found for permlab_devicePower (2787034722616350417) -->
<skip />
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"metter en/ord funcziun l\'apparat"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 0e7ba3a..9842414 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Prea multe ştergeri <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Stocarea pe tabletă este plină. Ștergeţi câteva fişiere pentru a elibera spaţiu."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Stocarea pe telefon este plină. Ștergeţi câteva fişiere pentru a elibera spaţiu."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rețeaua poate fi monitorizată"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opţiuni tablet PC"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opţiuni telefon"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"împiedicare comutare între aplicaţii"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Împiedică trecerea utilizatorului la o altă aplicaţie."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"obținere informații despre aplicația curentă"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Permite titularului să afișeze informații private despre aplicația și serviciile curente în prim-planul ecranului."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permite proprietarului să preia informațiile private despre aplicația curentă în prim-planul ecranului."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitorizare şi control asupra lansării tuturor aplicaţiilor"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permite aplicaţiei să monitorizeze şi să controleze modul în care sistemul lansează activităţi. Aplicaţiile rău intenţionate pot să compromită sistemul în întregime. Această permisiune este necesară doar pentru dezvoltare şi niciodată pentru utilizarea normală."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"trimitere mesaj difuzat privind extragerea din pachet"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite aplicaţiei să controleze funcţiile de nivel redus ale afişajelor Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"să intercepteze ieșirea audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite aplicației să intercepteze și să redirecționeze ieșirea audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"detectarea expresiei de activare"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Activează captarea semnalului audio de către aplicație pentru detectarea expresiei de activare. Captarea poate avea loc în fundal, dar nu împiedică altă captare audio (de ex., cameră video)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"să intercepteze ieșirea video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite aplicației să intercepteze și să redirecționeze ieșirea video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"să intercepteze ieșirea video securizată"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"împiedicare intrare telefon în repaus"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite aplicaţiei să împiedice intrarea tabletei în stare de repaus."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permite aplicaţiei să împiedice intrarea telefonului în stare de repaus."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmisie prin infraroșii"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permite aplicației să utilizeze transmițătorul prin infraroșii al tabletei."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permite aplicației să utilizeze transmițătorul prin infraroșii al telefonului."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"pornire sau oprire computer tablet PC"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"telefon pornit sau oprit"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permite aplicaţiei să pornească sau să oprească tableta."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 80e806f..e96a40d 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Слишком много удалений <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Память планшетного ПК заполнена. Удалите какие-нибудь файлы, чтобы освободить место."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Память телефона заполнена. Удалите какие-нибудь файлы, чтобы освободить место."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Действия в сети могут отслеживаться"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Я"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Настройки планшетного ПК"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Параметры телефона"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"Защита от переключения приложений"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Запрещает пользователям переключаться между приложениями."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"Показ информации о текущем приложении"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"На экране будут отображаться сведения о текущем приложении и запущенных сервисах."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"На экране будут отображаться сведения о текущем приложении."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"Отслеживание и управление запуском всех приложений"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Приложение сможет отслеживать запуск системных процессов и управлять им. Вредоносные программы смогут получить полный контроль над системой. Это разрешение необходимо только для разработки и не нужно в обычном режиме."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"Отправка оповещений об удалении пакетов"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Приложение сможет управлять низкоуровневыми функциями экранов, подключенных через Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"захват аудиосигнала"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Приложение сможет захватывать и перенаправлять аудиосигнал."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"распознавать голосовые команды"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Приложение сможет анализировать звук для распознавания голосовых команд. Этот процесс выполняется в фоновом режиме и не мешает другим операциям (например, записи видеоролика)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"захват видеосигнала"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Приложение сможет захватывать и перенаправлять видеосигнал."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"захват защищенного видеосигнала"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Отключение спящего режима"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Приложение сможет запрещать перевод планшетного ПК в спящий режим."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Приложение сможет запрещать перевод телефона в спящий режим."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"использовать инфракрасный передатчик"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Приложение сможет использовать инфракрасный передатчик планшетного ПК."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Приложение сможет использовать инфракрасный передатчик телефона."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Включение/выключение планшета"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"Включение/выключение телефона"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Приложение сможет включать и выключать планшетный ПК."</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 9b32bd9..9dc197f 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -314,7 +314,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"යෙදුම් මාරු වීම වැළක්වීම"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"වෙනත් යෙදුමක් වෙත පරිශීලකයාව මාරු වීම වළක්වයි."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"පවතින යෙදුමේ තොරතුරු ලබාගැනීම"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"තිරයේ පෙරබිම තුළ තිබෙන දැන් පවත්නා යෙදුමේ සහ සේවාවල පෞද්ගලික තොරතුරු ලබාගැනීමට දරන්නාට අවසර දෙන්න."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"තිරයේ පෙරබිම තුළ තිබෙන දැන් පවත්නා යෙදුමේ පෞද්ගලික තොරතුරු ලබාගැනීමට දරන්නාට අවසර දෙන්න."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"සියලු යෙදුම් දියත් කිරීම් නිරීක්ෂණය සහ පාලනය කිරීම"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"පද්ධතිය ක්රියාකාරකම් දියත් කරන්නේ කෙසේදැයි නිරීක්ෂණයට සහ පාලනයට යෙදුමට අවසර දෙන්න. අනිෂ්ට යෙදුම් මගින් පද්ධතිය සම්පූර්ණයෙන්ම සම්මුතියකට එළඹිය හැක. වර්ධනය සඳහා පමණක් මෙම අවසරය අවශ්ය වෙයි, සාමාන්ය භාවිතය සඳහා කිසි විටෙකත් අවශ්ය නොවෙයි."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"පැකේජ ඉවත් කිරීමේ ප්රචාරණයක් යවන්න"</string>
@@ -655,6 +655,8 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"වාහකයා ලබාදුන් සැකසුම් යෙදුම් උත්පාදනයට ධාරකයාට අවසර දෙන්න. සාමාන්ය යෙදුම් සඳහා කිසිදා අවශ්ය නොවෙයි."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ජාල තත්ව මත නිරීක්ෂණ වෙත ඇහුම්කන් දීම"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"යෙදුමකට ජාල තත්ව මත නිරීක්ෂණ වෙත ඇහුම්කන් දීමට අවසර දේ. සාමාන්ය යෙදුම් සඳහා කිසිදා අවශ්ය නොවේ."</string>
+ <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"අණවදන හඳුනාගැනීම ඉල්ලයි"</string>
+ <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"අණවදන හඳුනාගැනීම සඳහා ඉල්ලීමට යෙදුමට ඉඩ දෙන්න. සාමාන්ය යෙදුම් සඳහා කිසිදා අවශ්ය නොවෙයි."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"මුරපද නීති සකස් කිරීම"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"තිරය අගුළු ඇරීමේ මුරපදයට අනුමත අකුරු සහ දිග පාලනය කරන්න."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"තිරය අගුළු ඇරීමේ උත්සාහයන් නිරීක්ෂණය කරන්න"</string>
@@ -1581,7 +1583,7 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN නොගැළපෙයි. නැවත උත්සහ කරන්න."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN කුඩා වැඩිය. ඉලක්කම් 4 වත් විය යුතුය."</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="311050995198548675">"තවත් තත්පර ^1 කින් යළි උත්සාහ කරන්න"</item>
+ <item quantity="one" msgid="311050995198548675">"තවත් තත්පර 1 කින් යළි උත්සාහ කරන්න"</item>
<item quantity="other" msgid="4730868920742952817">"තත්පර <xliff:g id="COUNT">%d</xliff:g> කින් නැවත උත්සහ කරන්න"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"පසුව නැවත උත්සාහ කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index ea118ce..d944031 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Príliš veľa odstránených položiek služby <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Ukladací priestor tabletu je plný. Odstráňte niektoré súbory a uvoľnite miesto."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Pamäť telefónu je plná. Odstráňte niektoré súbory a uvoľnite miesto."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Sieť môže byť monitorovaná"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Možnosti tabletu"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Možnosti telefónu"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zabrániť prepínaniu aplikácií"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Zabráni používateľovi prepnúť na inú aplikáciu."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"získať informácie o aktuálnej aplikácii"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Umožňuje držiteľovi povolenia načítať súkromné informácie o aktuálnej aplikácii a službách v popredí obrazovky."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Umožňuje držiteľovi povolenia načítať súkromné informácie o aktuálnej aplikácii v popredí obrazovky."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"sledovať a ovládať všetky spustenia aplikácií"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Umožňuje aplikácii sledovať a ovládať spúšťanie aktivít systémom. Škodlivé aplikácie môžu systém úplne ovládnuť. Toto povolenie je potrebné len na účely vývoja, nikdy nie na bežné používanie."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"odoslanie vysielania o odstránení balíčka"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Umožňuje aplikácii ovládať základné funkcie displejov cez siete Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"zachytiť výstup zvuku"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Umožňuje aplikácii zachytiť a presmerovať výstup zvuku."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Rozpoznanie kľúčových slov"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Umožňuje aplikácii zaznamenať zvuk s cieľom rozpoznať kľúčové slová. Záznam sa môže uskutočniť na pozadí a nebráni inému zaznamenávaniu zvuku (napríklad videokamerou)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"zachytiť výstup videa"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Umožňuje aplikácii zachytiť a presmerovať výstup videa."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"zachytiť zabezpečený výstup videa"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zabránenie prechodu telefónu do režimu spánku"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Umožňuje aplikácii zabrániť prechodu tabletu do režimu spánku."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Umožňuje aplikácii zabrániť prechodu telefónu do režimu spánku."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infračervený prenos"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Umožňuje aplikácii používať infračervený vysielač tabletu."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Umožňuje aplikácii používať infračervený vysielač telefónu."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"zapnutie a vypnutie tabletu"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"zapnutie a vypnutie telefónu"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Umožňuje aplikácii zapnúť a vypnúť tablet."</string>
@@ -1578,8 +1588,8 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kódy PIN sa nezhodujú. Skúste to znova."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"Kód PIN je príliš krátky. Musí mať minimálne 4 číslice."</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="311050995198548675">"Skúste to znova o 1 s."</item>
- <item quantity="other" msgid="4730868920742952817">"Skúste to znova o <xliff:g id="COUNT">%d</xliff:g> s."</item>
+ <item quantity="one" msgid="311050995198548675">"Skúste to zas o 1 s"</item>
+ <item quantity="other" msgid="4730868920742952817">"Skúste to zas o <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Skúste to znova neskôr"</string>
<string name="transient_navigation_confirmation" msgid="4907844043611123426">"Panel zobraz. prejdením okraja obr."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index a58e474..b047c1a9 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Preveč izbrisov vsebine <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Pomnilnik tabličnega računalnika je poln. Izbrišite nekaj datotek, da sprostite prostor."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Pomnilnik telefona je poln. Izbrišite nekaj datotek, da sprostite prostor."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Omrežje je lahko nadzorovano"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Neznana tretja oseba"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Nadzira: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Jaz"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Možnosti tabličnega računalnika"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Možnosti telefona"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"preprečevanje preklopa programov"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Uporabniku preprečuje preklop v drug program."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"pridobivanje podatkov o trenutni aplikaciji"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Imetniku dovoli pridobivanje zasebnih podatkov o trenutni aplikaciji in storitvah v ospredju zaslona."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Omogoča imetniku pridobivanje zasebnih podatkov o trenutni aplikaciji v ospredju zaslona."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"spremljanje in nadzor vseh zagonov programov"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Programu omogoča spremljanje in nadziranje načina, kako sistem zažene dejavnosti. Zlonamerni programi lahko v celoti ogrozijo varnost sistema. To dovoljenje je potrebno samo za razvoj, vendar nikoli za običajno uporabo."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"pošiljanje oddaje brez paketa"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Omogoča aplikaciji nadzor osnovnih funkcij zaslonov Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"zajem avdioizhoda"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Omogoči aplikaciji, da zajame in preusmeri avdioizhod."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Zaznavanje sprožilnih besed"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Aplikaciji dovoljuje snemanje zvoka za zaznavanje sprožilnih besed. Snemanje je možno tudi v ozadju, ne preprečuje pa drugega snemanja zvoka (npr. z videokamero)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"zajem videoizhoda"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Omogoči aplikaciji, da zajame in preusmeri videoizhod."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"zajem varnega videoizhoda"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"preprečevanje prehoda v stanje pripravljenosti telefona"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Omogoča, da program prepreči prehod tabličnega računalnika v stanje pripravljenosti."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Programu omogoča, da v telefonu prepreči prehod v stanje pripravljenosti."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"prenašanje z infrardečim oddajnikom"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Aplikaciji dovoljuje uporabo infrardečega oddajnika tabličnega računalnika."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Aplikaciji dovoljuje uporabo infrardečega oddajnika telefona."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"vklop ali izklop tabličnega računalnika"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"vklop ali izklop telefona"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Programu omogoča vklop ali izklop tabličnega računalnika."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index ce4e284..7480afd 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Превише <xliff:g id="CONTENT_TYPE">%s</xliff:g> избрисаних ставки."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Меморија таблета је пуна! Избришите неке датотеке да бисте ослободили простор."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Складиште телефона је пуно! Избришите неке датотеке како бисте ослободили простор."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежа се можда надгледа"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Од стране непознате треће стране"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Од стране <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Ја"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Опције за таблет"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Опције телефона"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"спречавање пребацивања са једне апликације на другу"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Спречава да корисник пређе на другу апликацију."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"преузимање информација о актуелној апликацији"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Дозвољава власнику да преузима приватне информације о актуелној апликацији и услугама у првом плану екрана."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Дозвољава власнику да преузима приватне информације о актуелној апликацији у првом плану екрана."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"надгледање и контрола покретања свих апликација"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Дозвољава апликацији да прати начин на који систем покреће активности и да њиме управља. Злонамерне апликације могу у потпуности да угрозе систем. Ова дозвола је потребна само за програмирање, а никада за уобичајено коришћење."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"слање емитовања уклоњеног пакета"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Дозвољава апликацији да контролише функције Wi-Fi екрана ниског нивоа."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"снимање аудио садржаја"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Дозвољава апликацији да снима и преусмерава аудио садржај."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Откривање актуелних речи"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Дозвољава апликацији да снима звук за откривање актуелних речи. Снимање може да се дешава у позадини, али не спречава друга снимања звука (нпр. камкордер)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"снимање видео садржаја"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Дозвољава апликацији да снима и преусмерава видео садржај."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"снимање безбедног видео садржаја"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"спречавање преласка телефона у стање спавања"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дозвољава апликацији да спречи таблет да пређе у стање спавања."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Дозвољава апликацији да спречи телефон да пређе у стање спавања."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"пренос инфрацрвених зрака"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Дозвољава апликацији да користи одашиљач инфрацрвених зрака таблета."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Дозвољава апликацији да користи одашиљач инфрацрвених зрака телефона."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"укључивање или искључивање таблета"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"укључивање или искључивање телефона"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Дозвољава апликацији да укључује или искључује таблет."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 2ea2b0a..2c04831 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"För många <xliff:g id="CONTENT_TYPE">%s</xliff:g>-borttagningar."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Pekdatorns lagringsutrymme är fullt. Ta bort några filer för att frigöra utrymme."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Mobilens lagringsutrymme är fullt. Ta bort några filer för att frigöra utrymme."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Nätverket kan vara övervakat"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Av en okänd tredje part"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Av <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Jag"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Alternativ för surfplattan"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefonalternativ"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"förhindrar programbyten"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Hindrar användaren från att byta till en annan app."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"hämta information om aktuell app"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Innehavaren tillåts att hämta privat information om den app och de tjänster som för tillfället är i förgrunden på skärmen."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Innehavaren tillåts att hämta privat information om den app som för tillfället är i förgrunden på skärmen."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"övervaka och styra alla appar som öppnas"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Tillåter att appen övervakar och styr hur systemet startar aktiviteter. Skadliga appar kan kompromettera systemet helt. Den här behörigheten behövs bara för programmering, aldrig för vanlig användning."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"skicka meddelande om borttaget paket"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Tillåter att appen kontrollerar grundläggande funktioner för Wi-Fi-skärmar."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"fånga upp ljudutgång"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Tillåt att appen fångar upp och omdirigerar ljudutgången."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Kommandoordsidentifiering"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Tillåter att appen spelar in ljud för att upptäcka kommandoord. Inspelningen kan pågå i bakgrunden utan att hindra andra ljudinspelningar (t.ex. med videokamera)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"fånga upp videoutgång"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Tillåt att appen fångar upp och omdirigerar videoutgången."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"fånga upp säker videoutgång"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"förhindra att telefonen sätts i viloläge"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Tillåter att appen förhindrar att surfplattan går in i viloläge."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Tillåter att appen förhindrar att mobilen går in i viloläge."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"tillåt IR-sändning"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Tillåter att appen använder surfplattans IR-sändare."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Tillåter att appen använder mobilens IR-sändare."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"slå på eller stänga av surfplattan"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"sätta på eller stänga av telefonen"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Tillåter att appen slår på eller stänger av surfplattan."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 2d18ed7..2049364 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Ufutaji mwingi sana <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Hifadhi ya kompyuta kibao imejaa. Futa baadhi ya faili ili kupata nafasi."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Hifadhi ya simu imejaa. Futa baadhi ya faili ili uweze kupata nafasi."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mtandao unaweza kufuatiliwa"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Na mtu mwingine asiyejulikana"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Na <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Mimi"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Chaguo za kompyuta ndogo"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Machaguo ya simu"</string>
@@ -143,7 +146,7 @@
<string name="silent_mode_vibrate" msgid="7072043388581551395">"Mtetemo wa programu ya milio"</string>
<string name="silent_mode_ring" msgid="8592241816194074353">"Programu ya milio imewashwa"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Inafunga..."</string>
- <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Kompyuta yako ndogo itazima."</string>
+ <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Kompyuta kibao yako itazima."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Simu yako itazima."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Unataka kuzima?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Washa upya kwa hali salama"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zuia swichi za app"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Huzuia mtumiaji dhidi ya kubadilisha na kwenda kwa programu nyingine."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"pata maelezo ya sasa kuhusu programu"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Huruhusu mmiliki kurejesha maelezo binafsi kuhusu programu ya sasa na huduma katika mandharimbele ya skrini."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Huruhusu mmiliki kurejesha maelezo ya faragha kuhusu programu ya sasa katika mandharimbele ya skrini."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"Fuatilia na kudhibiti uzinduzi wote wa programu"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Inaruhusu programu kufuatilia na kudhibiti jinsi mfumo unazindua shughuli. Programu hasidi zinaweza kutia mfumo hatarini. Ruhusa inahitajika tu kwa usanidi, kamwe sio kwa matumizi ya kawaida."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"furushi lililotumwa limeondoa tangazo"</string>
@@ -447,7 +450,7 @@
<string name="permlab_writeProfile" msgid="907793628777397643">"rekebisha kadi yako mwenyewe ya mawasiliano"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Inaruhusu programu kubadilisha au kuongeza taarifa ya maelezo mafupi ya kibinafsi yaliyohifadhiwa kwenye kifaa chako, kama vile jina lako na taarifa ya anwani. Hii inamaanisha kuwa programu inaweza kukutambua na inaweza kutuma taarifa ya maelezo yako mafupi kwa wengine."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"soma mipasho yako wa kijamii"</string>
- <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Huruhusu programu kufikia na kupatanisha masasisho ya kijamii kutoka kwa marafiki zako. Kuwa makini wakati unashiriki taarifa -- hii huruhusu programu kusoma mawasiliano kati yako na marafiki zako kwenye mitandao ya jamii, bila kujali usiri. Kumbuka: idhini hii haiwezi kutekelezwa kwenye mitandao yote ya jamii."</string>
+ <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Huruhusu programu kufikia na kupatanisha masasisho ya kijamii kutoka kwa marafiki zako. Kuwa makini wakati unashiriki taarifa -- hii huruhusu programu kusoma mawasiliano kati yako na marafiki zako kwenye mitandao jamii, bila kujali usiri. Kumbuka: idhini hii haiwezi kutekelezwa kwenye mitandao yote ya jamii."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"andika kwa mipasho yako wa kijamii"</string>
<string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"Huruhusu programu kuonyesha masasisho ya kijamii kutoka kwa marafiki zako. Kuwa makini wakati unashiriki taarifa -- hii inaruhusu programu kutoa ujumbe unaoweza kuonekana kuwa unatoka kwa rafiki. Kumbuka: idhini hii huenda usitekelezwe kwenye mitandao yote ya jamii."</string>
<string name="permlab_readCalendar" msgid="5972727560257612398">"soma matukio ya kalenda pamoja na maelezo ya siri"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Inaruhusu programu kudhibiti vipengele vya kiwango cha chini vya maonyesho ya Wifi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"nasa sauti"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Inaruhusu programu kunasa na kuelekeza sauti kwingine."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Kutambua neno tekelezi"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Inaruhusu programu kunasa sauti kwa ajili ya utambuzi wa Neno tekelezi. Kunasa kunaweza kukafanyika chinichini lakini hakutazuia unasaji mwingine wa sauti (kwa mfano Kamkoda)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"nasa sauti ya video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Inaruhusu programu kunasa na kuelekeza video kwingine."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"nasa sauti ya video kwa usalama"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zuia simu dhidi ya kulala"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Inaruhusu programu kuzuia kompyuta kibao kwenda kulala."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Inaruhusu programu kuzuia simu isiende kulala."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"sambaza infrared"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Inaruhusu programu kutumia transmita ya infrared ya kompyuta kibao."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Inaruhusu programu kutumia transmita ya infrared ya simu."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Washa au zima kompyuta kibao"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"washa au zima simu"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Inaruhusu programu kuwasha au kuzima kompyuta kibao."</string>
@@ -665,8 +673,8 @@
<string name="policylab_forceLock" msgid="2274085384704248431">"Funga skrini"</string>
<string name="policydesc_forceLock" msgid="1141797588403827138">"Dhibiti jinsi na wakati skrini inapofunga."</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Futa data zote"</string>
- <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Futa data ya kompyuta kibao bila ilani kwa kutekeleza urejeshaji wa mipangilio ya kiwandani."</string>
- <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Futa data ya simu bila ya ilani kwa kutekeleza urejeshaji wa mipangilio ya kiwandani."</string>
+ <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Futa data ya kompyuta kibao bila ilani kwa kurejesha mipangilio ya mwanzo."</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Futa data ya simu bila ilani kwa kurejesha mipangilio ya mwanzo."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Weka mbadala wa kifaa cha ulimwengu"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Weka kifaa mbadala cha ulimwengu kitakachotumiwa wakati wa kuwezesha sera. Msimamizi wa kwanza wa kifaa pekee anaweka matekelezo mbadala ya ulimwengu."</string>
<string name="policylab_expirePassword" msgid="885279151847254056">"Weka muda wa kuisha wa nenosiri"</string>
@@ -1122,7 +1130,7 @@
<string name="smv_application" msgid="3307209192155442829">"Programu <xliff:g id="APPLICATION">%1$s</xliff:g> (utaratibu <xliff:g id="PROCESS">%2$s</xliff:g>) imeenda kinyume na sera yake ya StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Shughuli ya <xliff:g id="PROCESS">%1$s</xliff:g> imeenda kinyume na kulazimisha sera yake ya StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Toleo jipya la Android linawekwa..."</string>
- <string name="android_upgrading_apk" msgid="7904042682111526169">"Inasadifisha programu <xliff:g id="NUMBER_0">%1$d</xliff:g> ya <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+ <string name="android_upgrading_apk" msgid="7904042682111526169">"Inaboresha programu <xliff:g id="NUMBER_0">%1$d</xliff:g> ya <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Programu zinaanza"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Inamaliza kuwasha."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> inaendelea"</string>
diff --git a/core/res/res/values-sw600dp-port/refs.xml b/core/res/res/values-sw600dp-port/refs.xml
deleted file mode 100644
index cda38cf..0000000
--- a/core/res/res/values-sw600dp-port/refs.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * 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.
-*/
--->
-<resources>
- <item type="string" name="transient_navigation_confirmation">@string/transient_navigation_confirmation_long</item>
-</resources>
\ No newline at end of file
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 226b48d..a0b0255 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"มีการลบ <xliff:g id="CONTENT_TYPE">%s</xliff:g> มากเกินไป"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"ที่จัดเก็บข้อมูลของแท็บเล็ตเต็ม ลบไฟล์บางไฟล์เพื่อเพิ่มพื้นที่ว่าง"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"ที่เก็บข้อมูลโทรศัพท์เต็ม ลบบางไฟล์เพื่อเพิ่มที่ว่าง"</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"เครือข่ายอาจได้รับการตรวจสอบ"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"โดยบุคคลที่สามที่ไม่รู้จัก"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"โดย <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"ฉัน"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"ตัวเลือกของแท็บเล็ต"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"ตัวเลือกโทรศัพท์"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ป้องกันการเปลี่ยนแอปพลิเคชัน"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"ป้องกันไม่ให้ผู้ใช้สลับไปใช้แอปพลิเคชันอื่น"</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"รับข้อมูลแอปพลิเคชันปัจจุบัน"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"ช่วยให้เจ้าของสามารถดึงข้อมูลส่วนตัวเกี่ยวกับแอปพลิเคชันและบริการปัจจุบันในส่วนหน้าของหน้าจอ"</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"ช่วยให้เจ้าของสามารถดึงข้อมูลส่วนตัวเกี่ยวกับแอปพลิเคชันปัจจุบันในส่วนหน้าของหน้าจอ"</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"ตรวจสอบและควบคุมแอปพลิเคชันทั้งหมดที่เปิดใช้งาน"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"อนุญาตให้แอปพลิเคชันตรวจสอบและควบคุมวิธีการที่ระบบเปิดกิจกรรมต่างๆ แอปพลิเคชันที่เป็นอันตรายอาจทำอันตรายแก่ระบบได้อย่างสิ้นเชิง การอนุญาตนี้จำเป็นสำหรับการพัฒนาเท่านั้น ไม่ใช้สำหรับแอปพลิเคชันทั่วไปโดยเด็ดขาด"</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"ส่งการกระจายข้อมูลว่ามีการนำแพคเกจออก"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"อนุญาตให้แอปควบคุมคุณลักษณะต่างๆ ในระดับล่างของการแสดงผลด้วย WiFi"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"บันทึกเอาต์พุตเสียง"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"อนุญาตให้แอปบันทึกและเปลี่ยนเส้นทางเอาต์พุตเสียง"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"การตรวจหาคำที่นิยม"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"อนุญาตให้แอปเก็บเสียงสำหรับการตรวจหาคำที่นิยม การเก็บเสียงสามารถดำเนินการอยู่ในพื้นหลัง แต่ไม่เป็นการป้องกันการเก็บเสียงอื่นๆ (เช่น กล้องวิดีโอ)"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"บันทึกเอาต์พุตวิดีโอ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"อนุญาตให้แอปบันทึกและเปลี่ยนเส้นทางเอาต์พุตวิดีโอ"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"บันทึกเอาต์พุตเสียงที่ปลอดภัย"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ป้องกันไม่ให้โทรศัพท์เข้าโหมดสลีป"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"อนุญาตให้แอปพลิเคชันป้องกันไม่ให้แท็บเล็ตเข้าสู่โหมดสลีป"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"อนุญาตให้แอปพลิเคชันป้องกันไม่ให้โทรศัพท์เข้าสู่โหมดสลีป"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"ส่งสัญญาณอินฟราเรด"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"อนุญาตให้แอปใช้ตัวส่งสัญญาณอินฟราเรดของแท็บเล็ต"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"อนุญาตให้แอปใช้ตัวส่งสัญญาณอินฟราเรดของโทรศัพท์"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"เปิดหรือปิดเครื่องแท็บเล็ต"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"เปิดหรือปิดโทรศัพท์"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"อนุญาตให้แอปพลิเคชันเปิดหรือปิดแท็บเล็ต"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 36a3ffe..5b06737 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Masyadong maraming pagtanggal ng <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Puno na ang storage ng tablet. Magtanggal ng ilang file upang magbakante ng espasyo."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Puno na ang storage ng telepono. Magtanggal ng ilang file upang magbakante ng espasyo."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Maaaring sinusubaybayan ang network"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ng isang di-kilalang third party"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Ng <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Ako"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Mga pagpipilian sa tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Mga pagpipilian sa telepono"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"pigilan ang mga paglipat ng app"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Pinipigilan ang mga user sa paglipat sa isa pang app."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"kunin ang impormasyon ng kasalukuyang app"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Pinapayagan ang may-ari na kumuha ng pribadong impormasyon tungkol sa kasalukuyang application at mga serbisyo sa foreground ng screen."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Pinapayagan ang may-ari na bawiin ang pribadong impormasyon tungkol sa kasalukuyang application sa foreground ng screen."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"subaybayan at kontrolin ang lahat ng paglunsad ng app"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Pinapayagan ang app na subaybayan at kontrolin kung paano naglulunsad ng mga aktibidad ang system. Maaaring ganap na ikompromiso ng nakakahamak na apps ang system. Kinakailangan lamang ang pahintulot na ito para sa pagpapabuti, hindi kailanman para sa normal na paggamit."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"magpadala ng package inalis ang broadcast"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Pinapayagan ang app na magkontrol ng mga tampok sa mababang antas ng mga dispay ng Wifi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"kumuha ng audio output"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Pinapayagan ang app na kumuha at mag-redirect ng audio output."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Paghahanap ng hotword"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Nagbibigay-daan sa app na kumuha ng audio na paghahanapan ng Hotword. Maaaring maisagawa sa background ang pagkuha, ngunit hindi nito pipigilan ang iba pang pagkuha ng audio (hal. Camcorder)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"kumuha ng video output"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Pinapayagan ang app na kumuha at mag-redirect ng video output."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"kumuha ng secure na video output"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"pigilan ang telepono mula sa paghinto"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Pinapayagan ang app na pigilan ang tablet mula sa pag-sleep."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Pinapayagan ang app na pigilan ang telepono mula sa pag-sleep."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"magpadala gamit ang infrared"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Nagbibigay-daan sa app na gamitin ang infrared transmitter ng tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Nagbibigay-daan sa app na gamitin ang infrared transmitter ng telepono."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"i-on o i-off ang power tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"i-on o i-off ang telepono"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Pinapayagan ang app na i-on o i-off ang tablet."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 8fb697d..14f98d7 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Çok fazla <xliff:g id="CONTENT_TYPE">%s</xliff:g> silme var."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tabletin depolama alanı dolu! Yer açmak için bazı dosyaları silin."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonun depolama alanı dolu! Yer açmak için bazı dosyaları silin."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Ağ izlenebilir"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Ben"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tablet seçenekleri"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefon seçenekleri"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"uygulama değişimlerini engelle"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Kullanıcının başka bir uygulamaya geçiş yapmasını engeller."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"geçerli uygulama bilgilerini al"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"İzin sahibine, ekranın ön planındaki geçerli uygulama ve hizmetler hakkında gizli bilgileri alma olanağı verir."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"İzin sahibine, ekranın ön planındaki geçerli uygulama hakkında gizli bilgileri alma olanağı verir."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"tüm uygulama başlatma işlemlerini izle ve denetle"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Uygulamaya, sistemin etkinlikleri nasıl başlattığını izleme ve denetleme izni verir. Kötü amaçlı uygulamalar sistemi tamamen tehlikeye atabilir. Bu izin normal kullanım için değildir, sadece geliştirme süreçlerinde kullanılır."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"paket ile kaldırılan yayını gönder"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Uygulamaya kablosuz ekranların alt düzey özelliklerini kontrol etme izni verir."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ses çıkışını yakala"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Uygulamaya, ses çıkışını yakalayıp yönlendirme izni verir."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Önemli kelime algılama"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Uygulamaya, Özel kelime algılamak için ses yakalama izni verir. Ses yakalama işlemi arka planda yapılabilir, ancak diğer ses yakalama işlemlerini (ör. kameranın ses kaydını) engellemez."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"video çıkışını yakala"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Uygulamaya, video çıkışını yakalayıp yönlendirme izni verir."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"güvenli video çıkışını yakala"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"telefonun uykuya geçmesini önleme"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Uygulamaya, tabletin uykuya geçmesini önleme izni verir."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Uygulamaya, telefonun uykuya geçmesini önleme izni verir."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"kızı ötesi iletme"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Uygulamaya, tabletin kızıl ötesi vericisini kullanma izni verir."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Uygulamaya, telefonunun kızıl ötesi vericisini kullanma izni verir."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"tableti aç veya kapat"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"telefonu aç veya kapat"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Uygulamaya, tabletinizi açma veya kapatma izni verir."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 9412629..3ff9fd9 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Забагато видалень <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Пам’ять планшетного ПК заповнено. Видаліть якісь файли, щоб звільнити місце."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Пам’ять телефону заповнено. Видаліть якісь файли, щоб звільнити місце."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мережу можуть відстежувати"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Невідомою третьою стороною"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Доменом <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Я"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Парам. пристрою"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Параметри тел."</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"запобіг. зміні програм"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Запобігати переходу користувача до іншої програми."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"отримати інформацію про поточну програму"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Дозволяє власникові отримувати приватну інформацію про поточну програму та служби на передньому плані екрана."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Дозволяє власникові отримувати приватну інформацію про поточну програму на передньому плані екрана."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"відстежувати та контролювати запуски всіх програм"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Дозволяє програмі відстежувати та контролювати, як саме система запускає дії. Шкідливі програми можуть отримати повний контроль над системою. Цей дозвіл потрібний лише для розробки, а не для звичайного користування."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"надсил. запис про видал. пакета"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Дозволяє програмі керувати низькорівневими функціями екранів Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"отримувати доступ до аудіовиходу"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Дозволяє програмі отримувати доступ до аудіовиходу й переспрямовувати його."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"виявляти команди швидкого запуску"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Дозволяє програмі записувати аудіо для виявлення команд швидкого запуску. Запис відбуватиметься у фоновому режимі й не перешкоджатиме запису іншого аудіо (напр., з відеокамери)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"отримувати доступ до відеовиходу"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Дозволяє програмі отримувати доступ до відеовиходу й переспрямовувати його."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"отримувати доступ до захищеного відеовиходу"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"недоп. перехід тел. в реж. сну"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дозволяє програмі не допускати перехід планшетного ПК у режим сну."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Дозволяє програмі не допускати перехід телефону в режим сну."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"передавати в інфрачервоному діапазоні"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Дозволяє програмі використовувати інфрачервоний передавач планшета."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Дозволяє програмі використовувати інфрачервоний передавач телефону."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"увімк. чи вимк. пристрій"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"вмик. чи вимик. телефон"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Дозволяє програмі вимикати чи вимикати планшетний ПК."</string>
@@ -1578,8 +1586,8 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-коди не збігаються. Повторіть спробу."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-код закороткий. Має бути принаймні 4 цифри."</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="311050995198548675">"Спробуйте за 1 с"</item>
- <item quantity="other" msgid="4730868920742952817">"Спробуйте за <xliff:g id="COUNT">%d</xliff:g> с"</item>
+ <item quantity="one" msgid="311050995198548675">"Повтор за 1 с"</item>
+ <item quantity="other" msgid="4730868920742952817">"Повтор за <xliff:g id="COUNT">%d</xliff:g> с"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Спробуйте пізніше"</string>
<string name="transient_navigation_confirmation" msgid="4907844043611123426">"Гортайте від краю, щоб відкрити панель"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 4e44cc4a..26e3f6e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Quá nhiều lần xóa <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Bộ nhớ máy tính bảng đã đầy. Hãy xóa một số tệp để tạo thêm dung lượng."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Bộ nhớ điện thoại đã đầy. Hãy xóa một số tệp để tạo thêm dung lượng."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mạng có thể được giám sát"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Bởi một bên thứ ba không xác định"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Bởi <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Tôi"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tùy chọn máy tính bảng"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Tùy chọn điện thoại"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ngăn chuyển đổi ứng dụng"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Ngăn người dùng chuyển sang ứng dụng khác."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"truy cập thông tin ứng dụng hiện tại"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Cho phép chủ sở hữu truy xuất thông tin cá nhân về ứng dụng và dịch vụ hiện tại ở nền trước của màn hình."</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Cho phép chủ sở hữu truy xuất thông tin cá nhân về ứng dụng hiện tại ở nền trước của màn hình."</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"giám sát và kiểm soát tất cả hoạt động khởi chạy ứng dụng"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Cho phép ứng dụng giám sát và kiểm soát cách hệ thống khởi chạy các hoạt động. Ứng dụng độc hại hoàn toàn có thể làm tổn hại hệ thống. Quyền này chỉ cần cho mục đích phát triển, không dành cho mục đích sử dụng thông thường."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"gửi truyền phát đã xóa của gói"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Cho phép ứng dụng kiểm soát các tính năng cấp thấp của màn hình Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"thu thập dữ liệu đầu ra âm thanh"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Cho phép ứng dụng thu thập và chuyển hướng dữ liệu đầu ra âm thanh."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Phát hiện từ nóng"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Cho phép ứng dụng thu thập dữ liệu âm thanh để phát hiện từ nóng. Quá trình thu thập này có thể diễn ra trong nền nhưng không ngăn các hoạt động thu thập dữ liệu âm thanh khác (ví dụ: máy quay video)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"thu thập dữ liệu đầu ra video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Cho phép ứng dụng thu thập và chuyển hướng dữ liệu đầu ra video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"thu thập dữ liệu đầu ra video an toàn"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ngăn điện thoại chuyển sang chế độ ngủ"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Cho phép ứng dụng ngăn máy tính bảng chuyển sang chế độ ngủ."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Cho phép ứng dụng ngăn điện thoại chuyển sang chế độ ngủ."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"phát hồng ngoại"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Cho phép ứng dụng sử dụng bộ phát hồng ngoại của máy tính bảng."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Cho phép ứng dụng sử dụng bộ phát hồng ngoại của điện thoại."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"bật hoặc tắt máy tính bảng"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"bật hoặc tắt điện thoại"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Cho phép ứng dụng bật hoặc tắt máy tính bảng."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 895952a..b250f14 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"太多<xliff:g id="CONTENT_TYPE">%s</xliff:g>删除项。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"平板电脑存储空间已满。请删除一些文件以腾出空间。"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"手机存储空间已满。请删除一些文件以腾出空间。"</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"网络可能会受到监控"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"我"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"平板电脑选项"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"手机选项"</string>
@@ -314,7 +319,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"禁止切换应用"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"阻止用户切换到其他应用。"</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"获取当前应用的信息"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"允许应用检索目前在屏幕前台运行的应用和服务专有的信息。"</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"允许应用检索目前在屏幕前台运行的应用专有的信息。"</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"监控所有应用的启动"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"允许应用监视和控制系统是如何启动活动的。恶意应用可能会完全破坏系统。此权限只有在进行开发时才需要,正常使用情况下绝不需要。"</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"发送包删除的广播"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"允许应用控制 WLAN 显示设备的基础功能。"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"捕获音频输出"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"允许该应用捕获和重定向音频输出。"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"关键词检测"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"允许应用针对关键词检测捕获音频。捕获操作会在后台进行,但不会禁止使用其他音频捕获工具(例如摄像机)。"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"捕获视频输出"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"允许该应用捕获和重定向视频输出。"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"捕获安全视频输出"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手机休眠"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允许应用阻止平板电脑进入休眠状态。"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"允许应用阻止手机进入休眠状态。"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"发射红外线"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"允许应用使用平板电脑的红外线发射器。"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"允许应用使用手机的红外线发射器。"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"打开或关闭平板电脑"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"开机或关机"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"允许应用打开或关闭平板电脑。"</string>
@@ -637,7 +647,7 @@
<string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"允许应用访问所有用户的外部存储设备。"</string>
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"访问缓存文件系统"</string>
<string name="permdesc_cache_filesystem" msgid="5578967642265550955">"允许应用读取和写入缓存文件系统。"</string>
- <string name="permlab_use_sip" msgid="5986952362795870502">"拨打/接听互联网通话"</string>
+ <string name="permlab_use_sip" msgid="5986952362795870502">"拨打/接听互联网电话"</string>
<string name="permdesc_use_sip" msgid="4717632000062674294">"允许应用使用 SIP 服务拨打/接听互联网电话。"</string>
<string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"读取网络使用情况历史记录"</string>
<string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"允许应用读取特定网络和应用的网络使用情况历史记录。"</string>
@@ -680,7 +690,7 @@
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"住宅"</item>
<item msgid="869923650527136615">"手机"</item>
- <item msgid="7897544654242874543">"单位电话"</item>
+ <item msgid="7897544654242874543">"单位"</item>
<item msgid="1103601433382158155">"单位传真"</item>
<item msgid="1735177144948329370">"住宅传真"</item>
<item msgid="603878674477207394">"寻呼机"</item>
@@ -688,8 +698,8 @@
<item msgid="9192514806975898961">"自定义"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"家庭"</item>
- <item msgid="7084237356602625604">"单位"</item>
+ <item msgid="8073994352956129127">"个人"</item>
+ <item msgid="7084237356602625604">"工作"</item>
<item msgid="1112044410659011023">"其他"</item>
<item msgid="2374913952870110618">"自定义"</item>
</string-array>
@@ -746,8 +756,8 @@
<string name="eventTypeAnniversary" msgid="3876779744518284000">"周年纪念日"</string>
<string name="eventTypeOther" msgid="7388178939010143077">"其他"</string>
<string name="emailTypeCustom" msgid="8525960257804213846">"自定义"</string>
- <string name="emailTypeHome" msgid="449227236140433919">"家用"</string>
- <string name="emailTypeWork" msgid="3548058059601149973">"单位"</string>
+ <string name="emailTypeHome" msgid="449227236140433919">"个人"</string>
+ <string name="emailTypeWork" msgid="3548058059601149973">"工作"</string>
<string name="emailTypeOther" msgid="2923008695272639549">"其他"</string>
<string name="emailTypeMobile" msgid="119919005321166205">"手机"</string>
<string name="postalTypeCustom" msgid="8903206903060479902">"自定义"</string>
@@ -1167,10 +1177,10 @@
<skip />
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"无法连接到 WLAN"</string>
<string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互联网连接状况不佳。"</string>
- <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WLAN Direct"</string>
- <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"启动 WLAN Direct。此操作将会关闭 WLAN 客户端/热点。"</string>
- <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"无法启动 WLAN Direct。"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"已启用 WLAN Direct"</string>
+ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WLAN 直连"</string>
+ <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"启动 WLAN 直连。此操作将会关闭 WLAN 客户端/热点。"</string>
+ <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"无法启动 WLAN 直连。"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"已启用 WLAN 直连"</string>
<string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"通过触摸进行设置"</string>
<string name="accept" msgid="1645267259272829559">"接受"</string>
<string name="decline" msgid="2112225451706137894">"拒绝"</string>
@@ -1420,9 +1430,9 @@
<string name="extract_edit_menu_button" msgid="8940478730496610137">"修改"</string>
<string name="data_usage_warning_title" msgid="1955638862122232342">"流量使用警告"</string>
<string name="data_usage_warning_body" msgid="2814673551471969954">"触摸可查看使用情况和设置。"</string>
- <string name="data_usage_3g_limit_title" msgid="7093334419518706686">"2G-3G 数据已停用"</string>
- <string name="data_usage_4g_limit_title" msgid="7636489436819470761">"4G 数据已停用"</string>
- <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"移动数据已停用"</string>
+ <string name="data_usage_3g_limit_title" msgid="7093334419518706686">"2G-3G 数据网络已停用"</string>
+ <string name="data_usage_4g_limit_title" msgid="7636489436819470761">"4G 数据网络已停用"</string>
+ <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"移动数据网络已停用"</string>
<string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"WLAN 数据网络已停用"</string>
<string name="data_usage_limit_body" msgid="3317964706973601386">"触摸可启用。"</string>
<string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"已超出 2G-3G 数据流量限制"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 7a2298f..e924d01 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"同時刪除太多 <xliff:g id="CONTENT_TYPE">%s</xliff:g>。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"平板電腦的儲存空間已滿。請刪除一些檔案,以騰出可用空間。"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"手機的儲存空間已滿。請刪除一些檔案,以騰出可用空間。"</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"網絡可能會受到監控"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"受到不明的第三方監控"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"受到 <xliff:g id="MANAGING_DOMAIN">%s</xliff:g> 監控"</string>
<string name="me" msgid="6545696007631404292">"我本人"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"平板電腦選項"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"手機選項"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"防止切換應用程式"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"防止用戶切換至其他應用程式。"</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"取得目前的應用程式資訊"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"允許應用程式針對目前在螢幕前景的應用程式和服務擷取私人資訊。"</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"允許應用程式從目前屏幕前景的應用程式擷取私人資訊。"</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"監視及控制所有應用程式的啟動程序"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"允許應用程式監視和控制系統啟動活動的方式。惡意應用程式可能會藉此破壞整個系統。這個權限只有開發人員才需要,一般使用上不需使用這個權限。"</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"傳送套件已移除廣播"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"允許應用程式控制 WiFi Display 的低階功能。"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"擷取音頻輸出"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"允許應用程式擷取及重新導向音頻輸出。"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"啟動字詞偵測"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"允許應用程式擷取啟動字詞偵測的音頻。擷取操作可以在背景執行,但並未阻止其他音頻擷取 (例如攝錄機)。"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"擷取視頻輸出"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"允許應用程式擷取及重新導向視頻輸出。"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"擷取安全視頻輸出"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手機進入休眠狀態"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允許應用程式防止平板電腦進入休眠狀態。"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"允許應用程式防止手機進入休眠狀態。"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"傳送紅外線"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"允許應用程式使用平板電腦的紅外線傳送器。"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"允許應用程式使用手機的紅外線傳送器。"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"開啟或關閉平板電腦"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"開啟或關閉手機"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"允許應用程式開啟或關閉平板電腦。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index df6da73..7be248f 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"同時刪除太多 <xliff:g id="CONTENT_TYPE">%s</xliff:g>。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"平板電腦的儲存空間已滿。請刪除一些檔案,以釋放出可用空間。"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"手機儲存空間已滿。請刪除一些檔案,以釋放可用空間。"</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"網路可能會受到監控"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"受到不明的第三方監控"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"受到 <xliff:g id="MANAGING_DOMAIN">%s</xliff:g> 監控"</string>
<string name="me" msgid="6545696007631404292">"我"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"平板電腦選項"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"電話選項"</string>
@@ -314,7 +317,7 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"防止切換應用程式"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"防止使用者切換到其他應用程式。"</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"取得目前的應用程式資訊"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"允許應用程式擷取目前在螢幕前景運作的應用程式和服務的不公開資訊。"</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"允許應用程式針對目前在螢幕前景運作的應用程式擷取私人資訊。"</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"監視及控制所有應用程式的啟動程序"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"允許應用程式監視和控制系統啟動活動的方式。請注意,惡意應用程式可能利用此功能破壞整個系統。這個權限只有開發人員才需要,一般使用者不需使用這個權限。"</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"傳送程式已移除廣播"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"允許應用程式控制 Wi-Fi 顯示裝置的低階功能。"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"擷取音訊輸出"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"允許應用程式擷取及重新導向音訊輸出。"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"熱門字詞偵測"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"允許應用程式針對熱門字詞偵測擷取音訊。擷取作業可在背景執行,但並未禁止使用其他音訊擷取工具 (例如攝錄影機)。"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"擷取視訊輸出"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"允許應用程式擷取及重新導向視訊輸出。"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"擷取安全視訊輸出"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手機進入待命狀態"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允許應用程式防止平板電腦進入休眠狀態。"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"允許應用程式防止手機進入休眠狀態。"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"傳送紅外線"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"允許應用程式使用平板電腦的紅外線傳送器。"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"允許應用程式使用手機的紅外線傳送器。"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"開啟或關閉平板電腦"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"開啟或關閉電源"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"允許應用程式開啟或關閉平板電腦。"</string>
@@ -672,7 +680,7 @@
<string name="policylab_expirePassword" msgid="885279151847254056">"設定螢幕上鎖密碼到期日"</string>
<string name="policydesc_expirePassword" msgid="1729725226314691591">"控制螢幕上鎖密碼的變更頻率。"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"設定儲存裝置加密"</string>
- <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"必須為儲存的應用程式資料加密。"</string>
+ <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"必須為儲存的應用程式資料進行加密。"</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"停用相機"</string>
<string name="policydesc_disableCamera" msgid="2306349042834754597">"禁止使用所有裝置相機。"</string>
<string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"停用鍵盤保護框上的功能"</string>
@@ -722,7 +730,7 @@
</string-array>
<string name="phoneTypeCustom" msgid="1644738059053355820">"自訂"</string>
<string name="phoneTypeHome" msgid="2570923463033985887">"住家"</string>
- <string name="phoneTypeMobile" msgid="6501463557754751037">"行動裝置"</string>
+ <string name="phoneTypeMobile" msgid="6501463557754751037">"手機"</string>
<string name="phoneTypeWork" msgid="8863939667059911633">"公司"</string>
<string name="phoneTypeFaxWork" msgid="3517792160008890912">"公司傳真"</string>
<string name="phoneTypeFaxHome" msgid="2067265972322971467">"住家傳真"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index dd8a7b9..f96b062 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Kunokususa <xliff:g id="CONTENT_TYPE">%s</xliff:g> okuningi kakhulu."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Isilondolozi sethebhulethi sigcwele! Susa amanye amafayela ukukhulula isikhala."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Isilondolozi sefoni sigcwele! Susa amanye amafayela ukukhulula isikhala."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Inethiwekhi ingase inganyelwe"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ngenkampani yangaphandle engaziwa"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Nge-<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Mina"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Okukhethwa kukho kwethebhulethi"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Okukhethwa kukho kwefoni"</string>
@@ -238,11 +241,11 @@
<string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Qapha umbhalo owuthayiphayo"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Kufaka phakathi idatha yomuntu siqu efana nezinombolo zekhadi lesikweletu namaphasiwedi."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"khubaza noma guqula ibha yomumo"</string>
- <string name="permdesc_statusBar" msgid="8434669549504290975">"Ivumela insiza ukuthi yenze umudwa ochaza ngesimo ukuthi ungasebenzi noma ukufaka noma ukukhipha izithonjana zohlelo."</string>
+ <string name="permdesc_statusBar" msgid="8434669549504290975">"Ivumela uhlelo lokusebenza ukuthi yenze umudwa ochaza ngesimo ukuthi ungasebenzi noma ukufaka noma ukukhipha izithonjana zohlelo."</string>
<string name="permlab_statusBarService" msgid="7247281911387931485">"umudwa ochaza ngesimo"</string>
<string name="permdesc_statusBarService" msgid="716113660795976060">"Ivumela uhlelo lokusebenza ukuthi lube umudwa ochaza ngesimo."</string>
<string name="permlab_expandStatusBar" msgid="1148198785937489264">"khulisa/nciphisa ibha yomumo"</string>
- <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Ivumela insiza ukuthi ikhulise noma inciphise umudwa ochza ngesimo."</string>
+ <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Ivumela uhlelo lokusebenza ukuthi ikhulise noma inciphise umudwa ochza ngesimo."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"thumela amakholi aphumayo kabusha"</string>
<string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Ivumela uhlelo lokusebenza ukucubungula amakholi aphumayo futhi ishintshe inombolo ezoshayelwa. Le mvume ivumela uhlelo lokusebenza ukwengamela, liqondise kabusha, noma livikele amakholi aphumayo."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"thola imiyalezo ebhaliwe (i-SMS)"</string>
@@ -250,7 +253,7 @@
<string name="permlab_receiveMms" msgid="1821317344668257098">"thola imiyalezo ebhaliwe (i-MMS)"</string>
<string name="permdesc_receiveMms" msgid="533019437263212260">"Ivumela uhlelo lokusebenza ukuthola nokucubungula imilayezo ye-MMS. Loku kuchaza ukuthi uhlelo lokusebenza lungangamela noma lesuse imilayezo ethunyelwe kudivayisi yakho ngaphandle kokukubonisa yona."</string>
<string name="permlab_receiveEmergencyBroadcast" msgid="1803477660846288089">"yamukela ukusakazwa okuphuthumayo"</string>
- <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Ivumela insiza ukuthi yamukele iphinde isebenze ukusakakwa kwemiyalezo yezokuphuthumayo. Imvume itholakla ezinsizeni zesistimu kuphela."</string>
+ <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Ivumela uhlelo lokusebenza ukuthi yamukele iphinde isebenze ukusakakwa kwemiyalezo yezokuphuthumayo. Imvume itholakla ezinsizeni zesistimu kuphela."</string>
<string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"funda imilayezo yokusakaza yeselula"</string>
<string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Ivumela uhlelo lokusebenza ukufunda imilayezo yokusakaza yeselula etholwe idivayisi yakho. Izaziso zokusakaza zeselula zilethwa kwezinye izindawo ukukuxwayisa ngezimo ezisheshayo. Izinhlelo zokusebenza ezingalungile zingaphazamisana nokusebenza noma umsebenzi wedivayisi yakho uma ukusakaza kweselula kwesimo esisheshayo kutholwa."</string>
<string name="permlab_sendSms" msgid="5600830612147671529">"thumela imiyalezo ye-SMS"</string>
@@ -261,11 +264,11 @@
<string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Ivumela uhlelo lokusebenza ukufunda imilayezo ye-SMS elondolozwe kuthebulethi noma ekhadini lakho le-SIM. Lokhu kuvumela uhlelo lokusebenza ukufunda yonke imilayezo ye-SMS, ngaphandle kokuqukethwe noma ukugcinwa kuyimfihlo."</string>
<string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Ivumela uhlelo lokusebenza ukufunda imilayezo ye-SMS elondolozwe efonini noma ekhadini lakho le-SIM. Lokhu kuvumela uhlelo lokusebenza ukufunda yonke imilayezo ye-SMS, ngaphandle kokuqukethwe noma ukugcinwa kuyimfihlo."</string>
<string name="permlab_writeSms" msgid="3216950472636214774">"hlela imiyalezo yakho yombhalo (i-SMS noma i-MMS)"</string>
- <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Ivumela insiza ukuthi ibhale imiylezo ye-SMS egcinwe ekhompyutheni yakho yepeni noma kwikhadi lakho le-SIM. Izinsiza ezinobungozi zingayisusa imiyalezo yakho."</string>
- <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Ivumela insiza ukuthi ibhale imiylezo ye-SMS egcinwe ocingweni lwakh noma kwikhadi lakho le-SIM. Izinsiza ezinobungozi zingayisusa imiyalezo yakho."</string>
+ <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Ivumela uhlelo lokusebenza ukuthi ibhale imiylezo ye-SMS egcinwe ekhompyutheni yakho yepeni noma kwikhadi lakho le-SIM. Izuhlelo lokusebenza ezinobungozi zingayisusa imiyalezo yakho."</string>
+ <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Ivumela uhlelo lokusebenza ukuthi ibhale imiylezo ye-SMS egcinwe ocingweni lwakh noma kwikhadi lakho le-SIM. Izuhlelo lokusebenza ezinobungozi zingayisusa imiyalezo yakho."</string>
<string name="permlab_receiveWapPush" msgid="5991398711936590410">"thola imiyalezo ebhaliwe (i-WAP)"</string>
<string name="permdesc_receiveWapPush" msgid="748232190220583385">"Ivumela uhlelo lokusebenza ukuthola nokucubungula imilayezo ye-WAP. Le mvume ifaka phakathi amandla okungamela noma okwesusa imilayezo ethunyelwe kuwe ngaphandle kokukubonisa."</string>
- <string name="permlab_getTasks" msgid="6466095396623933906">"thola izinsiza ezisebenzayo"</string>
+ <string name="permlab_getTasks" msgid="6466095396623933906">"thola izinhlelo zokusebenza ezisebenzayo"</string>
<string name="permdesc_getTasks" msgid="7454215995847658102">"Ivumela uhlelo lokusebenza ukubuyisa ulwazi mayelana nemisebenzi yamanje neyakamuva. Lokhu kungavumela uhlelo lokusebenza ukuthola ulwazi mayelana nokuthi iziphi izinhlelo zokusebenza ezisetshenziswa kudivayisi."</string>
<string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"ihlanganyela phakathi kwabasebenzisi"</string>
<string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Ivumela uhlelo lokusebenza ukwenza izenzo kubasebenzisi bonke kudivayisi. Izinhlelo zokusebenza ezingalungile zingasebenzisa lokhu ukwephula ukuvikela phakathi kwabasebenzisi."</string>
@@ -275,32 +278,32 @@
<string name="permdesc_manageUsers" msgid="8409306667645355638">"Ivumela izinhlelo zokusebenza ukuphatha abasebenzisi kudivayisi, kufaka phakathi umbuzo, ukudala nokususa."</string>
<string name="permlab_getDetailedTasks" msgid="6229468674753529501">"thola kabusha imininingwane yezinhlelo zokusebenza ezisebenzayo"</string>
<string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Ivumela uhlelo lokusebenza ukuthola kabusha ulwazi mayelana nezinto ezenzeka manje nezisanda kwenzeka. Izinhlelo zokusebenza ezingalungile zingathola imininingwane eyimfihlo mayelana nezinye izinhlelo zokusebenza."</string>
- <string name="permlab_reorderTasks" msgid="2018575526934422779">"misa kabusha izinsiza ezisebenzayo"</string>
+ <string name="permlab_reorderTasks" msgid="2018575526934422779">"misa kabusha izinhlelo zokusebenza ezisebenzayo"</string>
<string name="permdesc_reorderTasks" msgid="7734217754877439351">"Ivumela uhlelo lokusebenza ukugudluza imisebenzi ngaphambili nangasemuva. Uhlelo lokusebenza lungenza lokhu ngaphandle kwakho."</string>
- <string name="permlab_removeTasks" msgid="6821513401870377403">"misa izinsiza ezisebenzayo"</string>
- <string name="permdesc_removeTasks" msgid="1394714352062635493">"Vumela ukuthi insiza isuse okumele kwenziwe ibulale nezinsiza zakho. Izinsiza eziwubungozi zingaphazamisa ukusebenza kwezinye izinsiza."</string>
+ <string name="permlab_removeTasks" msgid="6821513401870377403">"misa izinhlelo zokusebenza ezisebenzayo"</string>
+ <string name="permdesc_removeTasks" msgid="1394714352062635493">"Vumela ukuthi uhlelo lokusebenza isuse okumele kwenziwe ibulale nezuhlelo lokusebenza zakho. Izuhlelo lokusebenza eziwubungozi zingaphazamisa ukusebenza kwezinye izinhlelo zokusebenza."</string>
<string name="permlab_manageActivityStacks" msgid="7391191384027303065">"phatha izitaki zomsebenzi"</string>
<string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Ivumela uhlelo lokusebenza ukuthi lingeze, lisuse, noma lilungise izitaki zomsebenzi lapho ezinye izinhlelo zokusebenza ziqalisa khona. Izinhlelo zokusebenza ezinobungozi zingaphazamisa ukuziphatha kwezinye izinhlelo zokusebenza."</string>
<string name="permlab_startAnyActivity" msgid="2918768238045206456">"qala noma imuphi umsebenzi"</string>
<string name="permdesc_startAnyActivity" msgid="997823695343584001">"Ivumela uhlelo lokusebenza ukuqala umsebenzi, ngaphandle kokuvukeleka kwemvume noma isimo sokukhishiwe."</string>
<string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"setha ukuhambelana kwesikrini"</string>
<string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Ivumela uhlelo lokusebenza ukulawula imodi yokuhambelana kwesikrini kwezinye izinhlelo zokusebenza. Izinhlelo zokusebenza ezinonya zingase zephule ukuziphatha kwezinye izinhlelo zokusebenza."</string>
- <string name="permlab_setDebugApp" msgid="3022107198686584052">"vumela insiza ilungise inkinga"</string>
- <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ivumela insiza ukuthi ivule uhlelo lokulungisa lwenye insiza. Izinsiza ezinobungozi zingasebenzisa lokhu ukubulala ezinye izinsiza."</string>
+ <string name="permlab_setDebugApp" msgid="3022107198686584052">"vumela uhlelo lokusebenza ilungise inkinga"</string>
+ <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ivumela uhlelo lokusebenza ukuthi ivule uhlelo lokulungisa lwenye uhlelo lokusebenza. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukubulala ezinye izinhlelo zokusebenza."</string>
<string name="permlab_changeConfiguration" msgid="4162092185124234480">"guqula izilungiselo zohlelo zokubonisa"</string>
<string name="permdesc_changeConfiguration" msgid="4372223873154296076">"Ivumela uhlelo lokusebenza ukushintsha ukumisa kwamanje, njengezici zakhona noma usayizi wefonti."</string>
<string name="permlab_enableCarMode" msgid="5684504058192921098">"vumela imodi yemoto"</string>
- <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Ivumela insiza ukuthi yenze isimo semoto sisebenze."</string>
+ <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Ivumela uhlelo lokusebenza ukuthi yenze isimo semoto sisebenze."</string>
<string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"vala ezinye izinhlelo zokusebenza"</string>
<string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Ivumela uhelo lokusebenza ukuqeda izinqubo zangokwasemuva zezinhlelo zokusebenza. Lokhu kungababangela ezinye izinhlelo zokusebenza ukuyeka ukusebenza."</string>
- <string name="permlab_forceStopPackages" msgid="2329627428832067700">"phoqelela ezinye izinsiza ukuthi zime"</string>
- <string name="permdesc_forceStopPackages" msgid="5253157296183940812">"Ivumela insiza ukuthi iphoze ezinye izinsiza ukuthi zime."</string>
- <string name="permlab_forceBack" msgid="652935204072584616">"phoqa insiza ukuthi ivaleke"</string>
- <string name="permdesc_forceBack" msgid="3892295830419513623">"Ivumela insiza ukuthi iphoqe nanoma isiphi isehlo esiphambili ukuthi sivale bese sibuyela emuva. Akudingeki ezinsizeni ezejwayelekile."</string>
+ <string name="permlab_forceStopPackages" msgid="2329627428832067700">"phoqelela ezinye izinhlelo zokusebenza ukuthi zime"</string>
+ <string name="permdesc_forceStopPackages" msgid="5253157296183940812">"Ivumela uhlelo lokusebenza ukuthi iphoze ezinye izinhlelo zokusebenza ukuthi zime."</string>
+ <string name="permlab_forceBack" msgid="652935204072584616">"phoqa uhlelo lokusebenza ukuthi ivaleke"</string>
+ <string name="permdesc_forceBack" msgid="3892295830419513623">"Ivumela uhlelo lokusebenza ukuthi iphoqe nanoma isiphi isehlo esiphambili ukuthi sivale bese sibuyela emuva. Akudingeki ezinsizeni ezejwayelekile."</string>
<string name="permlab_dump" msgid="1681799862438954752">"thola isimo sangaphakathi sesistimu"</string>
- <string name="permdesc_dump" msgid="1778299088692290329">"Ivumela insiza ukuthi ithole kabusha ingaphakathi lesistimu. izinsiza ezinobungozi zingathola kabusha inqwaba yolwazi oluyimfihlo noluvikelekile ezingajwayele ukuthi ziludinge."</string>
+ <string name="permdesc_dump" msgid="1778299088692290329">"Ivumela uhlelo lokusebenza ukuthi ithole kabusha ingaphakathi lesistimu. izinhlelo zokusebenza ezinobungozi zingathola kabusha inqwaba yolwazi oluyimfihlo noluvikelekile ezingajwayele ukuthi ziludinge."</string>
<string name="permlab_retrieve_window_content" msgid="8022588608994589938">"letha okuqukethwe kwesikrini"</string>
- <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Ivumela insiza ukuthi ithole okuqukethe kwi-Window. Izinsiza ezinobungozi zingathola kabush iwindi eliphelele bese ibheka konke okuqukethwe ngaphandle kwaaaphasiwedi."</string>
+ <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Ivumela uhlelo lokusebenza ukuthi ithole okuqukethe kwi-Window. Izuhlelo lokusebenza ezinobungozi zingathola kabush iwindi eliphelele bese ibheka konke okuqukethwe ngaphandle kwaaaphasiwedi."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"nika amandla okwesikhashana ukufinyelela"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Ivumela uhlelo lokusebenza ukunika amandla ukufinyelela kwesikhashana kuvidayisi. Izinhlelo zokusebenza ezingalungile zinganika amandla ukufinyelela ngaphandle kwemvume yomsebenzisi."</string>
<string name="permlab_retrieve_window_info" msgid="8532295199112519378">"buyisa ulwazi lewindi"</string>
@@ -314,19 +317,19 @@
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"gwema ukushintsha kohlelo lokusebenza"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Igwema umsebenzisi ukuthi ashintshele kolunye uhlelo lokusebenza."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"thola ulwazi lohlelo lokusebenza lwamanje"</string>
- <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Ivumela umphathi ukuthi athole ulwazi mayelana nohlelo lwakho lokusebenza lwamanje namasevisi ngaphambili kwesikrini."</string>
- <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"qapha futhi ulawule ukuqaliswa kwazo zonke izinsiza"</string>
+ <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Ivumela umphathi ukuthi athole ulwazi oluyimfihlo mayelana nohlelo lokusebenza lwamanje ngaphambili kwesikrini."</string>
+ <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"qapha futhi ulawule ukuqaliswa kwazo zonke izinhlelo zokusebenza"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Ivumela uhlelo lokusebebenza ukuthi luhlole futhi lulawule ukuthi isistimu iziqalisa kanjani imisebenzi. Izinhlelo zokusebenza ezinobungozi zingensa isistimu ibe sebungozini. Le mvume idingakalela intuthuku kuphela hhayi ukusetshenziswa okwejwayelekile."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"thumela iphakheji yomsakazo okhishiwe"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Ivumela insiza ukuthi isakaze isaziso sokuthi insiza ethize isusiwe. Izinsiza ezinobungozi zingasebenzisa lokhu ukubulala nanoma iyiphi enye insiza esebenzayo."</string>
+ <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Ivumela uhlelo lokusebenza ukuthi isakaze isaziso sokuthi uhlelo lokusebenza ethize isusiwe. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukubulala nanoma iyiphi enye uhlelo lokusebenza esebenzayo."</string>
<string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"thumela umsakazo otholwe nge-SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Ivumela insiza ukuthi isakaze isaziso sokuthi umyalezo we-SMS utholakele. Izinsiza ezinobungozi zingasebenzisa lokhu ukufoja imiyalezo ye-SMS engenayo."</string>
+ <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Ivumela uhlelo lokusebenza ukuthi isakaze isaziso sokuthi umyalezo we-SMS utholakele. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukufoja imiyalezo ye-SMS engenayo."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"thumela umsakazo otholwe nge-WAP-PUSH"</string>
- <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ivumela insiza ukuthi isakaze isaziso sokuthi umyalezo we-WAP PUSH utholakele. Izinsiza ezinobungozi zingasebenzisa lokhu ukufoja ukutholakala kwemiyalezo ye-S noma zisuse okuqukethwe kwanoma iliphi ikhasi lewebhu eliqukethe okunobungozi."</string>
+ <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ivumela uhlelo lokusebenza ukuthi isakaze isaziso sokuthi umyalezo we-WAP PUSH utholakele. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukufoja ukutholakala kwemiyalezo ye-S noma zisuse okuqukethwe kwanoma iliphi ikhasi lewebhu eliqukethe okunobungozi."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"khawula inani lezinqubo ezisebenzayo"</string>
- <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ivumela insiza ukuthi ilawule isibalo esikhulu sezinto eziqhubekayo eziyosebenza. Ayidingakeli izinsiza ezijwayelekile."</string>
+ <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ivumela uhlelo lokusebenza ukuthi ilawule isibalo esikhulu sezinto eziqhubekayo eziyosebenza. Ayidingakeli izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"phoqa izinhlelo zokusebenza ezingemuva ukuthi zivaleke"</string>
- <string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"Ivumela izinsiza ukuthi zilawule ukuthi izehlakalo ziyaphela yini emumva kokuba ziye ngemumva. Akudingakeli izinsiza ezijwayelekile."</string>
+ <string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"Ivumela izinhlelo zokusebenza ukuthi zilawule ukuthi izehlakalo ziyaphela yini emumva kokuba ziye ngemumva. Akudingakeli izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_batteryStats" msgid="2789610673514103364">"funda izibalo zebhethri"</string>
<string name="permdesc_batteryStats" msgid="5897346582882915114">"Ivumela uhlelo lokusebenza ukufunda idatha yokusebenza yebhethri leleveli ephansi yamanje. Ingavumela uhlelo lokusebenza ukuthola ulwazi lemininingwane mayelana nokuthi iziphi izinhlelo zokusebenza ozisebenzisayo."</string>
<string name="permlab_updateBatteryStats" msgid="3719689764536379557">"guqula izibalo zebhetri"</string>
@@ -336,24 +339,24 @@
<string name="permlab_updateAppOpsStats" msgid="8829097373851521505">"shintsha izinombolo zokusebenza zohlelo lokusebenza"</string>
<string name="permdesc_updateAppOpsStats" msgid="50784596594403483">"Ivumela uhlelo lokusebenza ukuthi lishintshe izinombolo zokusebenza kohlelo lokusebenza lokuqoqiwe. Akufanele kusetshenziswe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_backup" msgid="470013022865453920">"lawula ukusekela ngokulondoloza uhlelo bese ubuyisela esimweni"</string>
- <string name="permdesc_backup" msgid="6912230525140589891">"Ivumela insiza ukuthi ilawule isipele sesistimu kanye nohlelo lokubuyiselwa kabusha. Ayenzelwe ukusetshenziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_backup" msgid="6912230525140589891">"Ivumela uhlelo lokusebenza ukuthi ilawule isipele sesistimu kanye nohlelo lokubuyiselwa kabusha. Ayenzelwe ukusetshenziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_confirm_full_backup" msgid="5557071325804469102">"qinisekisa isipele sonke noma buyisela futhi ukusebenza"</string>
- <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Ivumela insiza ukuthi iqalise ukuqinisekiswa okuphelele kwesipele kwe-UI. Akumelwe kusetshenziswe noma iyiphi insiza."</string>
+ <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Ivumela uhlelo lokusebenza ukuthi iqalise ukuqinisekiswa okuphelele kwesipele kwe-UI. Akumelwe kusetshenziswe noma iyiphi uhlelo lokusebenza."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"bonisa amawindi angavunyelwe"</string>
- <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Ivumela insiza ukuthi yakhe amawindi enzelwe ukuthi asetshenziswe inkundla yokusetshenziswa kwangaphakathi kwesistimu. Ayisethsnziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Ivumela uhlelo lokusebenza ukuthi yakhe amawindi enzelwe ukuthi asetshenziswe inkundla yokusetshenziswa kwangaphakathi kwesistimu. Ayisethsnziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_systemAlertWindow" msgid="3543347980839518613">"dweba phezulu kwezinye izinhlelo zokusebenza"</string>
<string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Ivumela uhlelo lokusebenza ukudweba phezu kwezinye izinhlelo zokusebenza noma izingxene zokusetshenziswa ukubonwa. Zingaphazamisa ukusebenzisa kwakho kokusetshenziswa kubonwa kunoma uluphi uhlelo lokusebenza, noma ukushintsha ocabanga ukuthi uyakubona kwezinye izinhlelo zokusebenza."</string>
<string name="permlab_setAnimationScale" msgid="2805103241153907174">"guqula isivinini sokugqwayiza jikelele"</string>
<string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Ivumela uhlelo lokusebenza ukushintsha isivinini sokugqwayiza jikelele (ukugqwayiza okusheshayo noma okulengayo) nganoma isiphi isikhathi."</string>
<string name="permlab_manageAppTokens" msgid="1286505717050121370">"lawula amathokheni ezinsiza"</string>
- <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Ivumela insiza ukuthi idale iphinde futhi ilawule amathokheni ayo, ngokweqa uku-oda kuka-Z okwejwayelekile. Akufanele kudingakele izinsiza ezijwayelekile."</string>
+ <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Ivumela uhlelo lokusebenza ukuthi idale iphinde futhi ilawule amathokheni ayo, ngokweqa uku-oda kuka-Z okwejwayelekile. Akufanele kudingakele izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_freezeScreen" msgid="4708181184441880175">"misa kancane isikrini"</string>
<string name="permdesc_freezeScreen" msgid="8558923789222670064">"Ivumela uhlelo lokusebenza ukumisa okwesikhashana isikrini ngokushintshwa kwesikrini esigcwele."</string>
<string name="permlab_injectEvents" msgid="1378746584023586600">"chofoza okhiye nezinkinobho zokulawula"</string>
<string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"Ivumela uhlelo lokusebenza ukuthi lizenzele izehlakalo zalo zokufaka (ukucindezela kokhiye, njll) kwezinye izinhlelo zokusebenza. Izinhlelo zokusebenza ezinobungozi zingasebenzisa lokhu ukuthi zilawule ithebhulethi."</string>
- <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Ivumela insiza ukuthi ithumele imicimbi yayo (ukucindezelwa kwezinkinobho, njll) kwezinye izinsiza. Izinsiza ezinobungozi zingasebenzisa lokhu ukuthi zilawule ucingo."</string>
+ <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Ivumela uhlelo lokusebenza ukuthi ithumele imicimbi yayo (ukucindezelwa kwezinkinobho, njll) kwezinye izinhlelo zokusebenza. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukuthi zilawule ucingo."</string>
<string name="permlab_readInputState" msgid="469428900041249234">"qopha lokho okuthayiphayo nezinyathelo ozithathayo"</string>
- <string name="permdesc_readInputState" msgid="8387754901688728043">"Ivumela insiza ukuthi ibheke izinkinobho ozicindezelayo ngisho ngabe usebenzisana nezinye izinsiza (njengokubhala amaphasiwedi). Akufanele kudingakele izinsiza ezijwayelekile."</string>
+ <string name="permdesc_readInputState" msgid="8387754901688728043">"Ivumela uhlelo lokusebenza ukuthi ibheke izinkinobho ozicindezelayo ngisho ngabe usebenzisana nezinye izinhlelo zokusebenza (njengokubhala amaphasiwedi). Akufanele kudingakele izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"hlanganisa indlela yokufakwayo"</string>
<string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Ivumela isimeli ukuhlanganisa uxhumano nomsebenzisi wezinga eliphezulu lendlela yokufaka. Ayisoze yadingeka kwizinhlelo ezivamile."</string>
<string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"hlanganisa kusevisi yokufinyeleleka"</string>
@@ -367,7 +370,7 @@
<string name="permlab_bindTextService" msgid="7358378401915287938">"bophezela kunsizakalo yombhalo"</string>
<string name="permdesc_bindTextService" msgid="8151968910973998670">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lwesixhumi esibonakalayo sensizakalo yombhalo(isb. InsizakaloYokuhlolaUkubhala). Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
<string name="permlab_bindVpnService" msgid="4708596021161473255">"hlanganisa kwinsizakalo ye-VPN"</string>
- <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ivumela umnini ukuthi abophele kwissekelo esingaphezulu sesevisi ye-Vpm. Ayidingakeli izinsiza ezejwayelekile."</string>
+ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ivumela umnini ukuthi abophele kwissekelo esingaphezulu sesevisi ye-Vpm. Ayidingakeli izinhlelo zokusebenza ezejwayelekile."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"hlanganisa kwiphephadonga"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lwephephadonga. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bophezela kube isevisi yesinqunjana"</string>
@@ -377,56 +380,56 @@
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"engeza noma susa umlawuli wedivayisi"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ivumela umnikazi ukuthi angeze noma asuse abalawuli bedivayisi esebenzayo. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"shintsha ukujikeleza kwesikrini"</string>
- <string name="permdesc_setOrientation" msgid="3046126619316671476">"Ivumela insiza ukuthi iguqule ukujikeleza kweskrini nganoma isiphi isikhathi. Akudingakeli izinsiza ezejwayelekile."</string>
+ <string name="permdesc_setOrientation" msgid="3046126619316671476">"Ivumela uhlelo lokusebenza ukuthi iguqule ukujikeleza kweskrini nganoma isiphi isikhathi. Akudingakeli izinhlelo zokusebenza ezejwayelekile."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"guqula isivinini sesikhombi"</string>
- <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Ivumela insiza ukuthi iguqule ijubane legundane noma lendawo yokukhomba ngomunwe. Akufanele kudingakele izinsiza ezijwayelekile."</string>
+ <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Ivumela uhlelo lokusebenza ukuthi iguqule ijubane legundane noma lendawo yokukhomba ngomunwe. Akufanele kudingakele izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"shintsha isendlalelo sekhibhodi"</string>
<string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Ivumela uhlelo lokusebenza ukushintsha isendlalelo sekhibhodi. Kufanele ingadingi izinhlelo zokusebenza ezivamile."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Thumela imifanekiso ye-Linu ezinsizeni"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Ivumela insiza ukuthi icele ukuthi isiginali ethunyelwe idluliselwe kuzo zonke izinqubeko ezisalelayo."</string>
- <string name="permlab_persistentActivity" msgid="8841113627955563938">"yenza insiza ukuthi ihlale isebenza"</string>
+ <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Ivumela uhlelo lokusebenza ukuthi icele ukuthi isiginali ethunyelwe idluliselwe kuzo zonke izinqubeko ezisalelayo."</string>
+ <string name="permlab_persistentActivity" msgid="8841113627955563938">"yenza uhlelo lokusebenza ukuthi ihlale isebenza"</string>
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Ivumela uhlelo kusebenza ukwenza izingxenye yazo ezicindezelayo kumemori. Lokhu kungakhawulela imemori ekhona kwezinye izinhlelo zokusebenza ukwenza ukuthi ithebhulethi ingasheshi."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Ivumela uhlelo kusebenza ukwenza izingxenye yazo ezicindezelayo kumemori. Lokhu kungakhawulela imemori ekhona kwezinye izinhlelo zokusebenza ukwenza ukuthi ifoni ingasheshi."</string>
- <string name="permlab_deletePackages" msgid="184385129537705938">"susa izinsiza"</string>
- <string name="permdesc_deletePackages" msgid="7411480275167205081">"Ivumela insiza ukuthi isuse amaphakheji e=Android. Izinsiza ezinobungozi zingasebenzisa lokhu ukusasa izinsiza ezibalulekile."</string>
+ <string name="permlab_deletePackages" msgid="184385129537705938">"susa izinhlelo zokusebenza"</string>
+ <string name="permdesc_deletePackages" msgid="7411480275167205081">"Ivumela uhlelo lokusebenza ukuthi isuse amaphakheji e=Android. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukusasa izinhlelo zokusebenza ezibalulekile."</string>
<string name="permlab_clearAppUserData" msgid="274109191845842756">"susa eminye imininingwane yezinsiza"</string>
- <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"Ivumela insiza ukuth isule imininingwane yomsebenzisi."</string>
+ <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"Ivumela uhlelo lokusebenza ukuth isule imininingwane yomsebenzisi."</string>
<string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"susa eminye imininingwane yezinsiza"</string>
- <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"Ivumela insiza ukuthi isuse amafayela alondolozwe okwesikhashana."</string>
- <string name="permlab_getPackageSize" msgid="7472921768357981986">"linganisa isikhala sokugcina insiza"</string>
- <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Ivuela insiza ukuthi ithole kabusha ikhodi yayo, i-dat kanye nosayizi abagcinwe okwesikhashana."</string>
- <string name="permlab_installPackages" msgid="2199128482820306924">"faka ngqo izinsiza"</string>
- <string name="permdesc_installPackages" msgid="5628530972548071284">"Ivumela insiza ukuthi ifake amaphakheji e-Android amasha noma abuyekeziwe. Izinsiza ezinobungozi zngasebenzisa lokhu ukwengeza izinsiza ezintsha ezinemvume emndla."</string>
+ <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"Ivumela uhlelo lokusebenza ukuthi isuse amafayela alondolozwe okwesikhashana."</string>
+ <string name="permlab_getPackageSize" msgid="7472921768357981986">"linganisa isikhala sokugcina uhlelo lokusebenza"</string>
+ <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Ivuela uhlelo lokusebenza ukuthi ithole kabusha ikhodi yayo, i-dat kanye nosayizi abagcinwe okwesikhashana."</string>
+ <string name="permlab_installPackages" msgid="2199128482820306924">"faka ngqo izinhlelo zokusebenza"</string>
+ <string name="permdesc_installPackages" msgid="5628530972548071284">"Ivumela uhlelo lokusebenza lufake amaphakheji e-Android amasha noma abuyekeziwe. Izinhlelo zokusebenza ezinobungozi zingasebenzisa lokhu ukwengeza izinhlelo ezinemvume enamandla."</string>
<string name="permlab_clearAppCache" msgid="7487279391723526815">"Susa yonke i-data egcinwe okwesikhashana yensiza"</string>
<string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"Ivumela uhlelo lokusebenza ukukhulula isitoreji se-tablet ngokususa amafayela enqolobaneni yezinye izinhlelo zokusebenza. Lokhu kungabangela ezinye izinhlelo zokusebenza ukuqala kancane njengoba zidinga ukubuyisa idatha yazo."</string>
<string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"Ivumela uhlelo lokusebenza ukukhulula isitoreji sefoni ngokususa amafayela enqolobaneni yezinye izinhlelo zokusebenza. Lokhu kungabangela ezinye izinhlelo zokusebenza ukuqala kancane njengoba zidinga ukubuyisa idatha yazo."</string>
<string name="permlab_movePackage" msgid="3289890271645921411">"hambis izinto zensiz"</string>
- <string name="permdesc_movePackage" msgid="319562217778244524">"Ivumela insiza ukuthi ihambise izinto eziqukethwe insiz izisusa emidiyeni yangaphakathi kuya kweyangaphandle njalonjalo."</string>
+ <string name="permdesc_movePackage" msgid="319562217778244524">"Ivumela uhlelo lokusebenza ukuthi ihambise izinto eziqukethwe insiz izisusa emidiyeni yangaphakathi kuya kweyangaphandle njalonjalo."</string>
<string name="permlab_readLogs" msgid="6615778543198967614">"funda idatha yefayela lokungena ebucayi"</string>
<string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Ivumela uhlelo lokusebenza ukufunda umafayela okungena ohlelo oluhlukene. Lokhu kuvumela ukuthola ukwaziswa okuvamile mayelana nokuthi wenzani ngethebhulethi, kodwa akumele kuqukethe ukwaziswa komuntu siqu noma okuyimfihlo."</string>
<string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Ivumela uhlelo lokusebenza ukufunda kumafayela okungena ahlukene esistimu. Lokhu kuvumela ukuthola ukwaziswa okuvamile mayelana nokuthi wenzani ngefoni, kuhlanganise ukwaziswa komuntu siqu noma kwangasese."</string>
<string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"sebenzisa noma isiphi isiqophi semidiya ukudlala"</string>
- <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ivumela insiza ukusebenzisa noma isiphi isiqophi semidiya esifakiwe ukuqopha ukudlala."</string>
+ <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ivumela uhlelo lokusebenza ukusebenzisa noma isiphi isiqophi semidiya esifakiwe ukuqopha ukudlala."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"phatha ukuqinisekisa okuthenjiwe"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ivumela uhlelo lokusebenza ukuthi lifake liphinde likhiphe izitifiketi ze-CA njengokuqinisekiswa okuthenjiwe."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"funda/bhalela emithombweni ephethwe idayegi"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Ivumela uhlelo lokusebenza ukufunda nokubhala kunoma yimuphi umthombo weqembu ledayegi; ngokwesibonelo, amafayela akwi/dev. Lokhu kungase kuthinte kakhulu ukuba nokuphepha kohlelo. Lokhu kumele kusebenziselwe KUPHELA ukuhlola ihadiwe okucacile ngumkhiqizi noma u-opheretha."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"vumela noma vimbela izingxenye zensiza"</string>
- <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"Ivumela ukuthi insiza iguqule ukuthi okuqukethwe kwenye insiza kuyasebenza noma cha. Izinsiza ezinobungozi zingasebenzisa lokhu ukwenza ukuthi izinto ezisemqoka ekhompyutheni yepeni zingasebenzi. Kufanele kuqashelwe uma kukhishwa lemvume njengoba kungenzeka kwenze izinto zensiza zibe sesimweni esingazinzile, nesiguquguqukayo."</string>
- <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"Ivumela ukuthi insiza iguqule ukuthi okuqukethwe kwenye insiza kuyasebenza noma cha. Izinsiza ezinobungozi zingasebenzisa lokhu ukwenza ukuthi izinto ezisemqoka ocingweni zingasebenzi. Kufanele kuqashelwe uma kukhishwa lemvume njengoba kungenzeka kwenze izinto zensiza zibe sesmweni esingazinzile, nesiguquguqukayo."</string>
+ <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"Ivumela ukuthi uhlelo lokusebenza iguqule ukuthi okuqukethwe kwenye uhlelo lokusebenza kuyasebenza noma cha. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukwenza ukuthi izinto ezisemqoka ekhompyutheni yepeni zingasebenzi. Kufanele kuqashelwe uma kukhishwa lemvume njengoba kungenzeka kwenze izinto zensiza zibe sesimweni esingazinzile, nesiguquguqukayo."</string>
+ <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"Ivumela ukuthi uhlelo lokusebenza iguqule ukuthi okuqukethwe kwenye uhlelo lokusebenza kuyasebenza noma cha. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukwenza ukuthi izinto ezisemqoka ocingweni zingasebenzi. Kufanele kuqashelwe uma kukhishwa lemvume njengoba kungenzeka kwenze izinto zensiza zibe sesmweni esingazinzile, nesiguquguqukayo."</string>
<string name="permlab_grantRevokePermissions" msgid="4627315351093508795">"nika noma buyisa izimvume"</string>
<string name="permdesc_grantRevokePermissions" msgid="4088642654085850662">"Ivumela izinhlelo zokusebenza ukunika noma ukubuyisa izimvume ezithile zayo noma ezinye izinhlelo zokusebenza. Izinhlelo zokusebenza ezingalungile zingasebenzisa lokhu ukufinyelela izici ongazinikanga zona."</string>
- <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"setha izinsiza ezincamelwayo"</string>
- <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"Ivuela insiza ukuthi iguqule izinsiza ezincanyelwayo. Izinsiza ezinobungozi zingashintsha izinsiz buthule ezisebenzyo okwenza ukuthi izinsiza zakho ezikhona zingasebenzi ukuthola ze zithole imininingwane yakho eyimfihlo."</string>
+ <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"setha izinhlelo zokusebenza ezincamelwayo"</string>
+ <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"Ivuela uhlelo lokusebenza ukuthi iguqule izinhlelo zokusebenza ezincanyelwayo. Izuhlelo lokusebenza ezinobungozi zingashintsha izinsiz buthule ezisebenzyo okwenza ukuthi izinhlelo zokusebenza zakho ezikhona zingasebenzi ukuthola ze zithole imininingwane yakho eyimfihlo."</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"guqula izilungiselelo zohlelo"</string>
- <string name="permdesc_writeSettings" msgid="7775723441558907181">"Ivumela insiza ukuthi iguqule i-data yezisetho zesistimu. Izinsiza ezinobungozi zingona ukusebenz kwesistimu yakho."</string>
+ <string name="permdesc_writeSettings" msgid="7775723441558907181">"Ivumela uhlelo lokusebenza ukuthi iguqule i-data yezisetho zesistimu. Izuhlelo lokusebenza ezinobungozi zingona ukusebenz kwesistimu yakho."</string>
<string name="permlab_writeSecureSettings" msgid="204676251876718288">"guqula izilungiselelo zohlelo oluphephile"</string>
- <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"Ivumela insiza ukuthi iguqule imioniningwane yezisetho zokuphepha kwesistimu. Ayisetshenziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"Ivumela uhlelo lokusebenza ukuthi iguqule imioniningwane yezisetho zokuphepha kwesistimu. Ayisetshenziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_writeGservices" msgid="2149426664226152185">"guqula ibalazwe lesevisi ye-Google"</string>
- <string name="permdesc_writeGservices" msgid="1287309437638380229">"Ivumela insiza ukuthi iguqule imephu yezinsizakalo ze-Google. Ayisetshenziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_writeGservices" msgid="1287309437638380229">"Ivumela uhlelo lokusebenza ukuthi iguqule imephu yezuhlelo lokusebenzakalo ze-Google. Ayisetshenziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"qalisa esiqalisweni sezinhlelo"</string>
<string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Ivumela uhlelo lokusebenza ukuthi luziqalise ngokushesha emuva kokuba isistimu isiqedile ukubhutha. Lokhu kwenza ukuthi ithathe isikhathi esithe ukuba side ukuqalise ithebhulethi nokuvumela izinhlelo zokusebenza ukuthi inciphise yonke ithebhulethi ngokuthi isebenze njalo."</string>
- <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Ivumela insiza ukuthi iziqalise ngokushesha uma isistiu isiqedile ukubhutha. Lokhu kungenz ukuthi kuthathe isikhathi esithe ukuba side ukuqalisa ucingo nokuvuela insiz ukuthi inciphise ucingo lonke ngokuthi luhlale lusebenza."</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Ivumela uhlelo lokusebenza ukuthi iziqalise ngokushesha uma isistiu isiqedile ukubhutha. Lokhu kungenz ukuthi kuthathe isikhathi esithe ukuba side ukuqalisa ucingo nokuvuela insiz ukuthi inciphise ucingo lonke ngokuthi luhlale lusebenza."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"thumela ukusakaza okunamathelayo"</string>
<string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Ivumela uhlelo lokusebenza ukuthumela ukusakaza okunamathelayo, okusalayo emva kokuba ukusakazwa sekuphelile. Ukusebenzisa kakhulu kuhle kwenze ithebhulethi ukuthi ingasheshi noma ingahlali kahle ngokuyibangela ukusebenzisa imemori eningi."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Ivumela uhlelo lokusebenza ukuthumela ukusakaza okunamathelayo, okusalayo emva kokuba ukusakazwa sekuphelile. Ukusebenzisa kakhulu kuhle kwenze ifoni ukuthi ingasheshi noma ingahlali kahle ngokuyibangela ukusebenzisa imemori eningi."</string>
@@ -467,15 +470,17 @@
<string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"indawo eseduze (kususelwe kunethiwekhi)"</string>
<string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Ivumela uhlelo lokusebenza ukuthola cishe indawo yakho. Le ndawo isuselwe kumasevisi endawo kusetshenziswa imithombo yendawo yenethiwekhi njengama-cell tower ne-Wi-Fi. Lawo masevisi endawo kufanele akhanyiswe futhi atholakale kudivayisi yakho ukuze asetshenziswe uhlelo lakho lokusebenza. Izinhlelo zokusebenza zingasebenzisa lokhu ukucacisa cishe lapho ukhona."</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"finyelela i-SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Ivumela insiza ukuthi isebenzise okuqukethwe i-SurfaceFlinger okusezingeni eliphansi."</string>
+ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Ivumela uhlelo lokusebenza ukuthi isebenzise okuqukethwe i-SurfaceFlinger okusezingeni eliphansi."</string>
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"funda isikhumbuli sesikhashana sendikimba"</string>
- <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Ivumela insiza ukuthi ifunde okuqukethwe ifreyimu yebhafa."</string>
+ <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Ivumela uhlelo lokusebenza ukuthi ifunde okuqukethwe ifreyimu yebhafa."</string>
<string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"lungisa ukubukwa kwe-Wi-Fi"</string>
<string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Ivumela uhlelo lokusebenza ukulungisa nokuxhuma ekubukisweni kwe-Wi-Fi."</string>
<string name="permlab_controlWifiDisplay" msgid="393641276723695496">"lawula ukubukwa kwe-Wi-Fi"</string>
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Uvumela uhlelo lokusebenza ukulawula izici zeleveli ephansi zokuboniswa kwe-Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"shutha okukhipha umsindo"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Kuvumela uhlelo lokusebenza ukuba lushuthe futhi luqondise kabusha okukhipha umsindo."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Ukutholwa kwe-Hotword"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Ivumela uhlelo lokusebenza ukuthi lishuthele umsindo ukutholwa kwe-Hotword. Ukushutha kungenzeka ngemuva kodwa akuvimbeli okunye ukushutha komsindo (isb. i-Camcorder)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"shutha okokukhipha ividiyo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Kuvumela uhlelo lokusebenza ukuba lushuthe futhi luqondise kabusha okukhipha ividiyo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"shutha okukhipha ividiyo ephephile"</string>
@@ -507,7 +512,7 @@
<string name="permlab_asec_create" msgid="6414757234789336327">"dala isitoreji sangaphakathi"</string>
<string name="permdesc_asec_create" msgid="4558869273585856876">"Ivumela uhlelo lokusebenza ukwenza ukugcina kwangaphakathi"</string>
<string name="permlab_asec_destroy" msgid="526928328301618022">"yonakalisa isitoreji sangaphakathi"</string>
- <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Ivumela insiza ukuthi ibulale ukulondolozwa kwangaphakathi."</string>
+ <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Ivumela uhlelo lokusebenza ukuthi ibulale ukulondolozwa kwangaphakathi."</string>
<string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"khweza / yehlisa isitoreji sangaphakathi"</string>
<string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Ivumela uhlelo ukukhuphula / ukwehlisa isitoreji sangaphakathi."</string>
<string name="permlab_asec_rename" msgid="7496633954080472417">"yetha kabusha isitoreji sangaphakathi"</string>
@@ -525,24 +530,27 @@
<string name="permlab_callPhone" msgid="3925836347681847954">"ngokuqondile shayela izinombolo zocingo"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Ivumela uhlelo lokusebenza ukushayela izinombolo zefoni ngaphandle kokuhlanganyela kwakho. Lokhu kungaholela emashajini noma amakholi angalindelekile. Qaphela ukuthi lokhu akuvumeli uhlelo lokusebenza ukushayela izinombolo zesimo esiphuthumayo. Izinhlelo zokusebenza ezingalungile zingabiza imali ngokwenze amakholi ngaphandle kokuqinisekisa kwakho."</string>
<string name="permlab_callPrivileged" msgid="4198349211108497879">"ngokuqondile shayela noma iziphi izinombolo zocingo."</string>
- <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Ivumela insiza ukuth ishayele noma iyiphi inombolo okubandakanya nezinombolo eziphuthumayo ngaphandle kokugammbukela. zinsiza ezinobungozi zingafaka izingcingo ezingenasiidngo nezingekho emthethweni esevisini ephuthumayo."</string>
+ <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Ivumela uhlelo lokusebenza ukuth ishayele noma iyiphi inombolo okubandakanya nezinombolo eziphuthumayo ngaphandle kokugammbukela. zuhlelo lokusebenza ezinobungozi zingafaka izingcingo ezingenasiidngo nezingekho emthethweni esevisini ephuthumayo."</string>
<string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"ngokuqondile qalisa ukumisa ithebhulethi nge-CDMA"</string>
<string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"ngokuqondile qalisa ukumisa ifoni nge-CDMA"</string>
- <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Ivumela insiza ukuqalisa amalungiselelo e-CDMA. Izinsiza ezinobungozi ingaqalisa amalungiselelo e-CDMA ngokungenasidingo."</string>
+ <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Ivumela uhlelo lokusebenza ukuqalisa amalungiselelo e-CDMA. Izuhlelo lokusebenza ezinobungozi ingaqalisa amalungiselelo e-CDMA ngokungenasidingo."</string>
<string name="permlab_locationUpdates" msgid="7785408253364335740">"lawula izaziso zokubuyekeza indawo"</string>
- <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Ivumela ukuthi insiza yenze izaziso zendawo zisebenze noma zingasebenzi emsakazweni. Ayenzelwe ukuthi isetshenziswe izinsiza ezijwayelekile."</string>
+ <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Ivumela ukuthi uhlelo lokusebenza yenze izaziso zendawo zisebenze noma zingasebenzi emsakazweni. Ayenzelwe ukuthi isetshenziswe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_checkinProperties" msgid="7855259461268734914">"finyelela kwizakhiwo zokuhlola"</string>
- <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Ivumela insiza ukuthi ifunde/ibhale ukufinyelela ezintweni ezilayishwe ngokubheka amasevisi. Akusetshenziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Ivumela uhlelo lokusebenza ukuthi ifunde/ibhale ukufinyelela ezintweni ezilayishwe ngokubheka amasevisi. Akusetshenziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_bindGadget" msgid="776905339015863471">"khetha izinqunjwana"</string>
- <string name="permdesc_bindGadget" msgid="8261326938599049290">"Ivumela insiza ukuthi itshele isistimu ukuthi amaphi amawijethi angasetshenziswa yiyiphi insiza. Insiza enalemvume inganikez ukufinyelela kwi-data yomuntu kwezinye izinsiza. Ayisetshenziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_bindGadget" msgid="8261326938599049290">"Ivumela uhlelo lokusebenza ukuthi itshele isistimu ukuthi amaphi amawijethi angasetshenziswa yiyiphi uhlelo lokusebenza. Insiza enalemvume inganikez ukufinyelela kwi-data yomuntu kwezinye izinhlelo zokusebenza. Ayisetshenziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_modifyPhoneState" msgid="8423923777659292228">"guqula isimo sefoni"</string>
- <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Ivumela ukuthi insiza ilawule okuqukethwe ocingweni edivayisini. Insiza enalemvume ingaguquguqula amanethwekhi, ivule umsakazo wocingo iphinde iwucishe kanye nokunye okufana nalokho ngaphandle kokukwazisa."</string>
+ <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Ivumela ukuthi uhlelo lokusebenza ilawule okuqukethwe ocingweni edivayisini. Insiza enalemvume ingaguquguqula amanethwekhi, ivule umsakazo wocingo iphinde iwucishe kanye nokunye okufana nalokho ngaphandle kokukwazisa."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"funda isimo sefoni kanye nesazisi"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ivumela uhlelo lokusebenza ukufinyelela izici zefoni zedivayisi. Le mvume ivumela uhlelo lokusebenza ukucacisa inombolo yefoni nobunikazi bedivayisi, ukuthi noma ikholi iyasebenza, futhi nenombolo yesilawuli kude zixhunywe ngekholi."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"gwema ithebhulethi ukuba ingalali"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"gwema ifoni ukuba ingalali"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ivumela uhlelo lokusebenza ukuthi linqande ithebulethi yakho ukuthi ilale."</string>
- <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Ivumela insiza ukuthi inqande ucingo ukuthi lulale."</string>
+ <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Ivumela uhlelo lokusebenza ukuthi inqande ucingo ukuthi lulale."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"hambisa okungabonwa ngeso"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Ivumela uhlelo lokusebenza ukuthi lusebenzise isihambisi esinombala ongabonwa ngeso wethebulethi."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Ivumela uhlelo lokusebenza ukuthi lusebenzise isihambisi esinombala ongabonwa ngeso wefoni."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"amandla efoni avuliwe noma avaliwe"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"amandla efoni avuliwe noma avaliwe"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Ivumela uhlelo lokusebenza ukuvala noma ukuvula ithebhulethi."</string>
@@ -555,15 +563,15 @@
<string name="permlab_setWallpaperHints" msgid="3278608165977736538">"shintsha usayizi wesithombe sakho sangemuva"</string>
<string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Ivumela uhlelo lokusebenza ukuhlela izihlawumbisela zosayizi wephephadonga lohlelo."</string>
<string name="permlab_masterClear" msgid="2315750423139697397">"setha kabusha kube okumisiwe kwemboni"</string>
- <string name="permdesc_masterClear" msgid="3665380492633910226">"Ivuela insiza ukuthi isethe kabusha isistiu ngokuphelele iyibuyisele ezisethweni eyafika nazo, isusa konke ukumisw kwemininingwane, kanye nezinsiza ezifakiwe."</string>
+ <string name="permdesc_masterClear" msgid="3665380492633910226">"Ivuela uhlelo lokusebenza ukuthi isethe kabusha isistiu ngokuphelele iyibuyisele ezisethweni eyafika nazo, isusa konke ukumisw kwemininingwane, kanye nezuhlelo lokusebenza ezifakiwe."</string>
<string name="permlab_setTime" msgid="2021614829591775646">"setha isikhathi"</string>
- <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"Ivumela insiza ukuthi iguqule isikhathi esisekhompyutheni yepeni."</string>
- <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Ivumela insiza ukuth iguqule isikhathi esisocingweni."</string>
+ <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"Ivumela uhlelo lokusebenza ukuthi iguqule isikhathi esisekhompyutheni yepeni."</string>
+ <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Ivumela uhlelo lokusebenza ukuth iguqule isikhathi esisocingweni."</string>
<string name="permlab_setTimeZone" msgid="2945079801013077340">"setha umkhawulo wesikhathi"</string>
- <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Ivumela insiza ukuthi iguqule umkhawulo wesikhathi sekhompyutha yepeni."</string>
- <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Ivumela insiza ukuth iguqule isikhathi esisocingweni."</string>
+ <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Ivumela uhlelo lokusebenza ukuthi iguqule umkhawulo wesikhathi sekhompyutha yepeni."</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Ivumela uhlelo lokusebenza ukuth iguqule isikhathi esisocingweni."</string>
<string name="permlab_accountManagerService" msgid="4829262349691386986">"yenza njenge Nsizakalo Yemeneja ye-Akhawunti"</string>
- <string name="permdesc_accountManagerService" msgid="1948455552333615954">"Ivumela insiza ukuthi ishaye izingcingo Kokokuqinisekisa Ama-akhawunti."</string>
+ <string name="permdesc_accountManagerService" msgid="1948455552333615954">"Ivumela uhlelo lokusebenza ukuthi ishaye izingcingo Kokokuqinisekisa Ama-akhawunti."</string>
<string name="permlab_getAccounts" msgid="1086795467760122114">"thola ama-akhawunti edivayisini"</string>
<string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Ivumela uhlelo lokusebenza ukuthola uhlu lwama-akhawunti aziwa ithebhulethi. Lokhu kufaka phakathi noma yimaphi ama-akhawunti adalwe izinhlelo zokusebenza ozifakile."</string>
<string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Ivumela uhlelo lokusebenza ukuthola uhlu lwama-akhawunti aziwa ifoni. Lokhu kufaka phakathi noma yimaphi ama-akhawunti adalwe izinhlelo zokusebenza ozifakile."</string>
@@ -572,17 +580,17 @@
<string name="permlab_manageAccounts" msgid="4983126304757177305">"engeza noma ukhiphe ama-akhawunti"</string>
<string name="permdesc_manageAccounts" msgid="8698295625488292506">"Ivumela uhlelo lokusebenza ukwenza imisebenzi enjengokufaka, nokukhipha ama-akhawunti nokususa iphasiwedi yawo"</string>
<string name="permlab_useCredentials" msgid="235481396163877642">"sebenzisa ama-akhawunti edivayisini"</string>
- <string name="permdesc_useCredentials" msgid="7984227147403346422">"Ivumela insiza ukuthi icele amathokheni okuqinisekisa."</string>
+ <string name="permdesc_useCredentials" msgid="7984227147403346422">"Ivumela uhlelo lokusebenza ukuthi icele amathokheni okuqinisekisa."</string>
<string name="permlab_accessNetworkState" msgid="4951027964348974773">"buka ukuxhumeka kunethiwekhi"</string>
<string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Ivumela uhlelo lokusebenza ukubuka ulwazi mayelana noxhumo lenethiwekhi njengokuthi imaphi amanethiwekhi akhona futhi axhunyiwe."</string>
<string name="permlab_createNetworkSockets" msgid="8018758136404323658">"ukufinyelela kwenethiwekhi okugcwele"</string>
<string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Ivumela uhlelo lokusebenza ukudala amasokethi enethiwekhi nokusebenzisa iziphakamiso eziyisisekelo zenethiwekhi yezifiso. Iziphequluli nezinye izinhlelo zokusebenza zinikela ngezindlela zokuthumela idatha ku-intanethi, ngakho-le le mvume ayidingekile ukuthumela idatha ku-intanethi."</string>
<string name="permlab_writeApnSettings" msgid="505660159675751896">"shintsha/ngenelela izilungiselelo kanye nokuhamba kuhleloxhumano"</string>
- <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Ivumela insiza ukuthi iguqule izilungiselelo zenethiwekhi kanye nokunciphisa kanye nokuhlola konke ukuphithizela kwenethiwekhi, isibonelo ukushintsha i-proy kanye ne-port yanom iyiphi i-APN. Izinhlelo zokusebenza ezinobungozi zingabheka, zithumele kabusha noma ziguqule okuqukethwe enethiwekhini ngaphandle kokwazi kwakho."</string>
+ <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Ivumela uhlelo lokusebenza ukuthi iguqule izilungiselelo zenethiwekhi kanye nokunciphisa kanye nokuhlola konke ukuphithizela kwenethiwekhi, isibonelo ukushintsha i-proy kanye ne-port yanom iyiphi i-APN. Izinhlelo zokusebenza ezinobungozi zingabheka, zithumele kabusha noma ziguqule okuqukethwe enethiwekhini ngaphandle kokwazi kwakho."</string>
<string name="permlab_changeNetworkState" msgid="958884291454327309">"shintsha uxhumano lwenethiwekhi"</string>
- <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Ivumela insiza ukuthi iguqule isimo sokuxhuaniseka kwenethiwekhi."</string>
+ <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Ivumela uhlelo lokusebenza ukuthi iguqule isimo sokuxhuaniseka kwenethiwekhi."</string>
<string name="permlab_changeTetherState" msgid="5952584964373017960">"Shintsha uxhumano lokusebenzisa njengemodemu"</string>
- <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Ivumela insiza ukuthi iguqule isimo sokuxhuaniseka kwenethiwekhi ehunyiwe."</string>
+ <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Ivumela uhlelo lokusebenza ukuthi iguqule isimo sokuxhuaniseka kwenethiwekhi ehunyiwe."</string>
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"shintsha idatha yasemuva yelungiselelo lokusebenzisa"</string>
<string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Ivumela uhlelo lokusebenza ukuthi luguqule izilungiselelo zemininingwane yokusetshenziswa kwedatha."</string>
<string name="permlab_accessWifiState" msgid="5202012949247040011">"buka ukuxhumaneka kwi-Wi-Fi"</string>
@@ -604,7 +612,7 @@
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Ivumela uhlelo lokusebenza ukubuka ukucushwa kwe-Bluetooth kuthebhulethi, nokwenza futhi nokwamukela uxhumo namadivayisi amatanisiwe."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ivumela uhlelo lokusebenza ukubuka ukucushwa kwe-Bluetooth efonini, ukwenza futhi nokwamukela uxhumo namadivayisi amatanisiwe."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"lawula Uxhumano Lwenkambu Eseduze"</string>
- <string name="permdesc_nfc" msgid="7120611819401789907">"Ivuela insiza ukuthi ixhumane ne-Near Field Communication (NFC) amathegi, amakhadi kanye nezinhlelo zokufunda."</string>
+ <string name="permdesc_nfc" msgid="7120611819401789907">"Ivuela uhlelo lokusebenza ukuthi ixhumane ne-Near Field Communication (NFC) amathegi, amakhadi kanye nezinhlelo zokufunda."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"khubaza ukukhiya kwakho iskrini"</string>
<string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Ivumela uhlelo lokusebenza ukukhubaza ukuvala ukhiye nanoma yikuphi ukuphepha kwephasiwedi okuhlobene. Isibonelo, ifoni ikhubaza ukuvala ukhiye lapho ithola ikholi yefoni engenayo, bese inike amandla kabusha ukuvala ukhiye lapho ikholi isiqedile."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"funda izilungiselelo zokuvumelanisa"</string>
@@ -614,37 +622,37 @@
<string name="permlab_readSyncStats" msgid="7396577451360202448">"funda izibalo zokuvumelanisa"</string>
<string name="permdesc_readSyncStats" msgid="1510143761757606156">"Ivumela uhlelo lokusebenza ukufunda izibalo zokuvumelanisa ze-akhawunti, kufaka phakathi umlando wezehlakalo ezivumelanisiwe nokuthi ingakanani idatha evumelanisiwe."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"funda izifunzo ezikhokhelwayo"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Ivumela insiza ukuthi ithole imininingwane mayelana namafidi avumelnisiwe njengamanje."</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Ivumela uhlelo lokusebenza ukuthi ithole imininingwane mayelana namafidi avumelnisiwe njengamanje."</string>
<string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"bhala izifunzo ezikhokhelwayo"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Ivumela insiza ukuthi iguqule amafidi akho avumelanisiwe njengamanje. Izinsiza ezinobungozi zingaguqula amafidi akho avumelanisiwe."</string>
+ <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Ivumela uhlelo lokusebenza ukuthi iguqule amafidi akho avumelanisiwe njengamanje. Izuhlelo lokusebenza ezinobungozi zingaguqula amafidi akho avumelanisiwe."</string>
<string name="permlab_readDictionary" msgid="4107101525746035718">"funda imibandela oyengezile esichazimazwini"</string>
<string name="permdesc_readDictionary" msgid="659614600338904243">"Ivumela uhlelo lokusebenza ukufunda onke amabizo, amagama, namatemu umsebenzisi awalondolozile kusichazamazwi somsebenzisi."</string>
<string name="permlab_writeDictionary" msgid="2183110402314441106">"engeza amagama kusichazamazwi ezichazwe umsebenzisi"</string>
- <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Ivumela insiza ukuthi ibhale amagama amasha esichazinimazwi."</string>
+ <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Ivumela uhlelo lokusebenza ukuthi ibhale amagama amasha esichazinimazwi."</string>
<string name="permlab_sdcardRead" product="nosdcard" msgid="8235341515605559677">"ukufinyelela kokuhlola esilondolozini esivikelekile"</string>
<string name="permlab_sdcardRead" product="default" msgid="8235341515605559677">"ukufinyelela kokuhlola esilondolozini esivikelekile"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3642473292348132072">"Ivumela uhlelo lokusebenza ukuhlola imvume yesitoreji se-USB okuzotholakala kumadivayisi alandelayo."</string>
<string name="permdesc_sdcardRead" product="default" msgid="5914402684685848828">"Ivumela uhlelo lokusebenza ukuhlola imvume yekhadi le-SD okuzotholakala kumadivayisi alandelayo."</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"guqula noma ususe okuqukethwe kwakho okugciniwe okufinyeleleka nge-USB"</string>
<string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"shintsha noma ususe okuqukethwe ekhadini lakho le-SD"</string>
- <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Ivumela insiza ukuthi ibhalele ekulondolozweni kwe-USB."</string>
- <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Ivumela insiza ukuthi ibhalele ekhadini le-SD."</string>
+ <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Ivumela uhlelo lokusebenza ukuthi ibhalele ekulondolozweni kwe-USB."</string>
+ <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Ivumela uhlelo lokusebenza ukuthi ibhalele ekhadini le-SD."</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"guqula/susa okuqukethwe kwisitoreji semidiya yangaphakathi"</string>
- <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Ivumela insiza ukuthi iguqule okuqukethwe kokulondoloza imidiya yangaphakathi."</string>
+ <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Ivumela uhlelo lokusebenza ukuthi iguqule okuqukethwe kokulondoloza imidiya yangaphakathi."</string>
<string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"phatha isitoreji sedokhumenti"</string>
<string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Ivumela uhlelo lokusebenza ukuthi luphathe isitoreji sedokhumenti."</string>
<string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"ukufinyelela isilondolozi sangaphandle sabo bonke abasebenzisi"</string>
<string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Vumela uhlelo lokusebenza ukufinyelela isilondolozi sangaphandle kubo bonke abasebenzisi."</string>
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"finyelela kunqolobane yesistimu yefayela"</string>
- <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Ivumela insiza ukuthi ifunde futhi ibhale isistimu yokufayila amafayela esikhashana."</string>
+ <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Ivumela uhlelo lokusebenza ukuthi ifunde futhi ibhale isistimu yokufayila amafayela esikhashana."</string>
<string name="permlab_use_sip" msgid="5986952362795870502">"yena/thola amakholi e-Inthanethi"</string>
- <string name="permdesc_use_sip" msgid="4717632000062674294">"Ivumela insiza ukuthi isebenzise isevisi ye-SIP ukwenza/ukuthola izingcingo ze-inthanethi."</string>
+ <string name="permdesc_use_sip" msgid="4717632000062674294">"Ivumela uhlelo lokusebenza ukuthi isebenzise isevisi ye-SIP ukwenza/ukuthola izingcingo ze-inthanethi."</string>
<string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"funda ukusetshenziswa komlando wohleloxhumano"</string>
- <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Ivumela insiza ukuthi ifunde umlando wokusetshenziswa kwenethiwekhi emanethiwekhini athize kanye nasezinsizeni."</string>
+ <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Ivumela uhlelo lokusebenza ukuthi ifunde umlando wokusetshenziswa kwenethiwekhi emanethiwekhini athize kanye nasezinsizeni."</string>
<string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"phatha inqubomgomo yenethiwekhi"</string>
- <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ivumela insiza ukuthi yengamele iigomo iphinde ichaze imithetho ehambisana ngqo nensiza."</string>
+ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ivumela uhlelo lokusebenza 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>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ivumela uhlelo lokusebenza ukuthi iguqule ukuthii ukusetshenziswa kwenethiwekhi kumiswa kanjani ezinsizeni. Ayisetshenziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_markNetworkSocket" msgid="3658527214914959749">"shintsha izimpawu zesokhethi"</string>
<string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Ivumela uhlelo lokusebenza ukuthi lilungise izimpawu zesokhethi zomzila"</string>
<string name="permlab_accessNotifications" msgid="7673416487873432268">"finyelela kuzaziso"</string>
@@ -926,11 +934,11 @@
<string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Ivumela uhlelo lokusebenza ukushintsha umlando wamabhukhimakhi noma wesiphequluli alondolozwe kuthebhulethi yakho. Lokhu kungavumela uhlelo lokusebenza ukususa noma ukushintsha idatha yesiphequluli. Qaphela: le mvume kungenzeka ingaphoqelelwa iziphequluli ezivela eceleni noma ezinye izinhlelo zokusebenza ezinamandla okuphequlula iwebhu."</string>
<string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Ivumela uhlelo lokusebenza ukushintsha umlando wamabhukhimakhi noma wesiphequluli alondolozwe efonini yakho. Lokhu kungavumela uhlelo lokusebenza ukususa noma ukushintsha idatha yesiphequluli. Qaphela: le mvume kungenzeka ingaphoqelelwa iziphequluli ezivela eceleni noma ezinye izinhlelo zokusebenza ezinamandla okuphequlula iwebhu."</string>
<string name="permlab_setAlarm" msgid="1379294556362091814">"setha i-alamu"</string>
- <string name="permdesc_setAlarm" msgid="316392039157473848">"Ivumela insiza ukuthi isethe i-alamu ensizeni efkiwe ye-alamu. Ezinye izinsiza ze-alamu kungenzeka zingakusebenzisi lokho."</string>
+ <string name="permdesc_setAlarm" msgid="316392039157473848">"Ivumela uhlelo lokusebenza ukuthi isethe i-alamu ensizeni efkiwe ye-alamu. Ezinye izinhlelo zokusebenza ze-alamu kungenzeka zingakusebenzisi lokho."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"engeza imeyili yezwi"</string>
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"Ivumela uhlelo lokusebenza ukwengeza imiyalezo kwibhokisi lakho lemeyili yezwi."</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Gugula izimvume zendawo Yesiphequluli"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Ivumela insiza ukuthi iguqule izimvume eziphathelene nezindawo Zesiphequluli. Izinsiza eziyingozi zingasebenzisa lokhu ukuvumela ukuvumela imininingwane yendawo kunoma imaphi amawebusayithi."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Ivumela uhlelo lokusebenza ukuthi iguqule izimvume eziphathelene nezindawo Zesiphequluli. Izuhlelo lokusebenza eziyingozi zingasebenzisa lokhu ukuvumela ukuvumela imininingwane yendawo kunoma imaphi amawebusayithi."</string>
<string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"qinisekisa amaphakheji"</string>
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ivumela ukuthi isisetshenziswa siqinisekise ukuthi ngabe iphakheji iyafakeka."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bopha okokuqinisekisa iphakheji"</string>
@@ -1099,8 +1107,8 @@
<string name="alwaysUse" msgid="4583018368000610438">"Sebenzisa ngokuzenzakalelayo kulesenzo."</string>
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"Susa izilungiselelo zesistimu; Izinhlelo zokusebenza & Okulandiwe"</string>
<string name="chooseActivity" msgid="7486876147751803333">"Khetha okufanele kwenziwe"</string>
- <string name="chooseUsbActivity" msgid="6894748416073583509">"Kheth insiza yedivayisi ye-USB"</string>
- <string name="noApplications" msgid="2991814273936504689">"Azikho izinsiza ezingenza lokhu"</string>
+ <string name="chooseUsbActivity" msgid="6894748416073583509">"Kheth uhlelo lokusebenza yedivayisi ye-USB"</string>
+ <string name="noApplications" msgid="2991814273936504689">"Azikho izinhlelo zokusebenza ezingenza lokhu"</string>
<string name="aerr_title" msgid="1905800560317137752"></string>
<string name="aerr_application" msgid="932628488013092776">"Ngeshwa, <xliff:g id="APPLICATION">%1$s</xliff:g> kumile."</string>
<string name="aerr_process" msgid="4507058997035697579">"Ngeshwa, uhlelo <xliff:g id="PROCESS">%1$s</xliff:g> luvele lwama."</string>
@@ -1118,21 +1126,21 @@
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> iqalisiwe."</string>
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Isilinganisi"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Bonisa njalo"</string>
- <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Yenza ukuthi kuphinde kusebenze lokhu ezisethweni Zesistimue > Izinsiza > Kulayishiwe."</string>
+ <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Yenza kuphinde kusebenze kuzilungiselelo Zesistimue > Izinhlelo zokusebenza > Okulayishiwe."</string>
<string name="smv_application" msgid="3307209192155442829">"Inqubo <xliff:g id="APPLICATION">%1$s</xliff:g> (yohlelo <xliff:g id="PROCESS">%2$s</xliff:g>) iphule inqubomgomo oziphoqelela yona Yemodi Ebukhali."</string>
<string name="smv_process" msgid="5120397012047462446">"Inqubo <xliff:g id="PROCESS">%1$s</xliff:g> yephule inqubomgomo yokuziphoqelela Yemodi Ebukhali."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"I-Android ifaka ezakamuva..."</string>
- <string name="android_upgrading_apk" msgid="7904042682111526169">"Ukubeka ezingeni eliphezulu <xliff:g id="NUMBER_0">%1$d</xliff:g> insiza <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
- <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Qalisa izinsiza."</string>
+ <string name="android_upgrading_apk" msgid="7904042682111526169">"Ukubeka ezingeni eliphezulu <xliff:g id="NUMBER_0">%1$d</xliff:g> uhlelo lokusebenza <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
+ <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Qalisa izinhlelo zokusebenza."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Qedela ukuqala kabusha."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> iyasebenza"</string>
<string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Thinta ukuguqukela ensizeni"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Shintsha izinsiza?"</string>
+ <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Shintsha izinhlelo zokusebenza?"</string>
<string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Olunye uhlelo lokusebenza luvele luyasebenza lokho kumele kumiswe ngaphambi kokuba uqalise olusha."</string>
<string name="old_app_action" msgid="493129172238566282">"Buyisela ku:<xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Ungayiqali insiza entsha."</string>
+ <string name="old_app_description" msgid="2082094275580358049">"Ungayiqali uhlelo lokusebenza entsha."</string>
<string name="new_app_action" msgid="5472756926945440706">"Qala <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Misa insiza endala ngaphandle kokulondoloza."</string>
+ <string name="new_app_description" msgid="1932143598371537340">"Misa uhlelo lokusebenza endala ngaphandle kokulondoloza."</string>
<string name="sendText" msgid="5209874571959469142">"Khetha okufanele kwenziwe okomqhafazo"</string>
<string name="volume_ringtone" msgid="6885421406845734650">"Ivolumu yesishayeli"</string>
<string name="volume_music" msgid="5421651157138628171">"Ivolumu yemidiya"</string>
@@ -1227,7 +1235,7 @@
<string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"Vala isitoreji se-USB"</string>
<string name="usb_storage_stop_error_message" msgid="1970374898263063836">"Kube nenkinga yokuvala okokulondoloza kwe-USB. Hlola ukuqiniseka ukuthi wehlise isikhungo se-USB, bese uzama futhi."</string>
<string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Vula isitoreji se-USB"</string>
- <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Uma uvula okokulondoloza kwe-USB, ezinye izinsiza ozisebenzisayo ziyoma futhi kungenzeka zingatholakali kuze kube ucisha ukulondoloza kwe-USB."</string>
+ <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Uma uvula okokulondoloza kwe-USB, ezinye izinhlelo zokusebenza ozisebenzisayo ziyoma futhi kungenzeka zingatholakali kuze kube ucisha ukulondoloza kwe-USB."</string>
<string name="dlg_error_title" msgid="7323658469626514207">"Ukusebenza kwe-USB kwehlulekile"</string>
<string name="dlg_ok" msgid="7376953167039865701">"KULUNGILE"</string>
<string name="usb_mtp_notification_title" msgid="3699913097391550394">"Ixhunyiwe njengedivayisi yemidiya"</string>
@@ -1276,9 +1284,9 @@
<string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"Ikhadi le-SD likhishiwe. Faka elisha."</string>
<string name="activity_list_empty" msgid="1675388330786841066">"Ayikho imisebenzi efanayo etholakele"</string>
<string name="permlab_pkgUsageStats" msgid="8787352074326748892">"buyekeza izibalo zokusebenzisa ingxenye"</string>
- <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"Ivumela insiza ukuthi iguqule imininingwane yokusetshenziswa kokuqoqiwe. Akwenzelwe ukuthi kusetshenziswe izinsiza ezijwayelekile."</string>
+ <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"Ivumela uhlelo lokusebenza ukuthi iguqule imininingwane yokusetshenziswa kokuqoqiwe. Akwenzelwe ukuthi kusetshenziswe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_copyProtectedData" msgid="4341036311211406692">"Kopisha okuqukethwe"</string>
- <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Ivumela insiza ukuthi inqabe okutholakala kukhona ukukopisha okuqukethwe. Akusetshenziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Ivumela uhlelo lokusebenza ukuthi inqabe okutholakala kukhona ukukopisha okuqukethwe. Akusetshenziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_route_media_output" msgid="1642024455750414694">"Yenza umzila wemidiya wokukhiphayo"</string>
<string name="permdesc_route_media_output" msgid="4932818749547244346">"Ivumela uhlelo lokusebenza ukwenza umzila wokukhiphayo wemidiya kuya kumadivayisi angaphandle."</string>
<string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Finyelela kusitoreji esiqashwa ngesikhiya esiphephile"</string>
@@ -1393,7 +1401,7 @@
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Ukushintsha kwendlela esetshenziswayo"</string>
<string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Beka kwenye indawo"</string>
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Faka"</string>
- <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Khetha insiza"</string>
+ <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Khetha uhlelo lokusebenza"</string>
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Yabelana no"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Yabelana no <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Ihaambis isibambo. Thinta & ubambe."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a47e518..275afb8 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2184,6 +2184,18 @@
<enum name="no" value="2" />
</attr>
+ <!-- Indicates to accessibility services whether the user should be notified when
+ this view changes. -->
+ <attr name="accessibilityLiveRegion" format="integer">
+ <!-- Accessibility services should not announce changes to this view. -->
+ <enum name="none" value="0" />
+ <!-- Accessibility services should announce changes to this view. -->
+ <enum name="polite" value="1" />
+ <!-- Accessibility services should interrupt ongoing speech to immediately
+ announce changes to this view. -->
+ <enum name="assertive" value="2" />
+ </attr>
+
<!-- Specifies the id of a view for which this view serves as a label for
accessibility purposes. For example, a TextView before an EditText in
the UI usually specifies what infomation is contained in the EditText.
@@ -4544,7 +4556,7 @@
</declare-styleable>
<!-- Use <code>target</code> as the root tag of the XML resource that
- describes a {@link android.transition.Transition#addTargetId(int)
+ describes a {@link android.transition.Transition#addTarget(int)
targetId} of a transition. There can be one or more targets inside
a <code>targets</code> tag, which is itself inside an appropriate
{@link android.R.styleable#Transition Transition} tag.
@@ -6128,8 +6140,4 @@
<attr name="textView" format="reference" />
</declare-styleable>
- <declare-styleable name="DocumentsProviderInfo">
- <attr name="customRoots" format="boolean" />
- </declare-styleable>
-
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 05ca120..80810d5 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1048,6 +1048,11 @@
tag; often this is one of the {@link android.Manifest.permission standard
system permissions}. -->
<attr name="name" />
+ <!-- Optional: specify the maximum version of the Android OS for which the
+ application wishes to request the permission. When running on a version
+ of Android higher than the number given here, the permission will not
+ be requested. -->
+ <attr name="maxSdkVersion" format="integer" />
<!-- Specify whether this permission is required for the application.
The default is true, meaning the application requires the
permission, and it must always be granted when it is installed.
@@ -1129,7 +1134,7 @@
on. You can use this to ensure your application is filtered out
of later versions of the platform when you know you have
incompatibility with them. -->
- <attr name="maxSdkVersion" format="integer" />
+ <attr name="maxSdkVersion" />
</declare-styleable>
<!-- The <code>library</code> tag declares that this apk is providing itself
@@ -1379,9 +1384,6 @@
component specific values). -->
<attr name="enabled" />
<attr name="exported" />
- <!-- If set to true, onProvideAssistData will be called on this service when this service
- is running in the foreground. -->
- <attr name="provideAssistData" format="boolean" />
<!-- If set to true, this service with be automatically stopped
when the user remove a task rooted in an activity owned by
the application. The default is false. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ab95d40..2c1a3c1 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -450,6 +450,13 @@
The default is false. -->
<bool name="config_lidControlsSleep">false</bool>
+ <!-- Indicate whether to allow the device to suspend when the screen is off
+ due to the proximity sensor. This resource should only be set to true
+ if the sensor HAL correctly handles the proximity sensor as a wake-up source.
+ Otherwise, the device may fail to wake out of suspend reliably.
+ The default is false. -->
+ <bool name="config_suspendWhenScreenOffDueToProximity">false</bool>
+
<!-- Control the behavior when the user long presses the power button.
0 - Nothing
1 - Global actions menu
@@ -793,6 +800,11 @@
<!-- 2 means give warning -->
<integer name="config_datause_notification_type">2</integer>
+ <!-- If Voice Radio Technology is RIL_RADIO_TECHNOLOGY_LTE:14 this is the value
+ that should be used instead. A value of RIL_RADIO_TECHNOLOGY_UNKNOWN:0 means
+ there is no replacement value and VoLTE is assumed to be supported -->
+ <integer name="config_volte_replacement_rat">0</integer>
+
<!-- Flag indicating whether the current device is "voice capable".
If true, this means that the device supports circuit-switched
(i.e. voice) phone calls over the telephony network, and is
@@ -1229,4 +1241,8 @@
To do this, add 21407 item to values-mcc214-mnc04/config.xml -->
<string-array translatable="false" name="config_operatorConsideredNonRoaming">
</string-array>
+
+ <!-- Threshold (in ms) under which a screen off / screen on will be considered a reset of the
+ transient navigation confirmation prompt.-->
+ <integer name="config_transient_navigation_confirmation_panic">5000</integer>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 6c3856e..c5d4810 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2073,11 +2073,10 @@
<public type="attr" name="vendor" />
<public type="attr" name="category" />
<public type="attr" name="isAsciiCapable" />
- <public type="attr" name="customRoots" />
<public type="attr" name="autoMirrored" />
<public type="attr" name="supportsSwitchingToNextInputMethod" />
<public type="attr" name="requireDeviceUnlock" />
<public type="attr" name="apduServiceBanner" />
- <public type="attr" name="provideAssistData" />
+ <public type="attr" name="accessibilityLiveRegion" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 68acd8c..99b703b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -273,6 +273,18 @@
<!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. -->
<string name="low_memory" product="default">Phone storage is full. Delete some files to free space.</string>
+ <!-- SSL CA cert notification --> <skip />
+ <!-- Shows up when there is a user SSL CA Cert installed on the
+ device. Indicates to the user that SSL traffic can be intercepted. [CHAR LIMIT=NONE] -->
+ <string name="ssl_ca_cert_warning">Network may be monitored</string>
+ <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning",
+ i.e. "Network may be monitored". This says that an unknown party is doing the monitoring.
+ [CHAR LIMIT=100]-->
+ <string name="ssl_ca_cert_noti_by_unknown">By an unknown third party</string>
+ <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning",
+ i.e. "Network may be monitored". This indicates who is doing the monitoring.
+ [CHAR LIMIT=100]-->
+ <string name="ssl_ca_cert_noti_managed">By <xliff:g id="managing_domain">%s</xliff:g></string>
<!-- Display name for any time a piece of data refers to the owner of the phone. For example, this could be used in place of the phone's phone number. -->
<string name="me">Me</string>
@@ -831,7 +843,7 @@
<string name="permlab_getTopActivityInfo">get current app info</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_getTopActivityInfo">Allows the holder to retrieve private information
- about the current application and services in the foreground of the screen.</string>
+ about the current application in the foreground of the screen.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_runSetActivityWatcher">monitor and control all app launching</string>
@@ -1405,6 +1417,12 @@
<string name="permdesc_captureAudioOutput">Allows the app to capture and redirect audio output.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_captureAudioHotword">Hotword detection</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_captureAudioHotword">Allows the app to capture audio for Hotword detection. The capture can
+ happen in the background but does not prevent other audio capture (e.g. Camcorder).</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_captureVideoOutput">capture video output</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_captureVideoOutput">Allows the app to capture and redirect video output.</string>
@@ -1596,6 +1614,14 @@
<string name="permdesc_wakeLock" product="default">Allows the app to prevent the phone from going to sleep.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_transmitIr">transmit infrared</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_transmitIr" product="tablet">Allows the app to use the tablet\'s infrared transmitter.</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_transmitIr" product="default">Allows the app to use the phone\'s infrared transmitter.</string>
+
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_devicePower" product="tablet">power tablet on or off</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_devicePower" product="default">power phone on or off</string>
@@ -1872,6 +1898,11 @@
<string name="permdesc_use_sip">Allows the app to use the SIP service to make/receive Internet calls.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bind_call_service">interact with in-call screen</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bind_call_service">Allows the app to control when and how the user sees the in-call screen.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readNetworkUsageHistory">read historical network usage</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_readNetworkUsageHistory">Allows the app to read historical network usage for specific networks and apps.</string>
@@ -1911,11 +1942,6 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_accessNetworkConditions">Allows an application to listen for observations on network conditions. Should never be needed for normal apps.</string>
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_hotwordRecognition">request hotword recognition</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_hotwordRecognition">Allows an application to request for hotword recognition. Should never be needed for normal apps.</string>
-
<!-- Policy administration -->
<!-- Title of policy access to limiting the user's password choices -->
@@ -4275,19 +4301,111 @@
<!-- ISO (European standard) C10 media (paper) size: 1.10" x 1.57" -->
<string name="mediaSize_iso_c10">ISO C10</string>
- <!-- North America Letter media (paper) size: 8.5" × 11" -->
+ <!-- North America Letter media (paper) size: 8.5" × 11" (279mm x 216mm) -->
<string name="mediaSize_na_letter">Letter</string>
- <!-- North America Government Letter media (paper) size: 8.0" × 10.5" -->
+ <!-- North America Government Letter media (paper) size: 8.0" × 10.5" (203mm x 267mm) -->
<string name="mediaSize_na_gvrnmt_letter">Government Letter</string>
- <!-- North America Legal media (paper) size: 8.5" × 14" -->
+ <!-- North America Legal media (paper) size: 8.5" × 14" (216mm x 356mm) -->
<string name="mediaSize_na_legal">Legal</string>
- <!-- North America Junior Legal media (paper) size: 8.0" × 5.0" -->
+ <!-- North America Junior Legal media (paper) size: 8.0" × 5.0" (203mm × 127mm) -->
<string name="mediaSize_na_junior_legal">Junior Legal</string>
- <!-- North America Ledger media (paper) size: 17" × 11" -->
+ <!-- North America Ledger media (paper) size: 17" × 11" (432mm × 279mm) -->
<string name="mediaSize_na_ledger">Ledger</string>
- <!-- North America Tabloid media (paper) size: 11" × 17" -->
+ <!-- North America Tabloid media (paper) size: 11" × 17" (279mm × 432mm) -->
<string name="mediaSize_na_tabloid">Tabloid</string>
+ <!-- North America Index Card 3x5 media (paper) size: 3" x 5" (76mm x 127mm) -->
+ <string name="mediaSize_na_index_3x5">Index Card 3x5</string>
+ <!-- North America Index Card 4x6 media (paper) size: 4" x 6" (102mm x 152mm) -->
+ <string name="mediaSize_na_index_4x6">Index Card 4x6</string>
+ <!-- North America Index Card 5x8 media (paper) size: 5" x 8" (127mm x 203mm) -->
+ <string name="mediaSize_na_index_5x8">Index Card 5x8</string>
+ <!-- North America Monarch media (paper) size: 7.25" x 10.5" (184mm x 267mm) -->
+ <string name="mediaSize_na_monarch">Monarch</string>
+ <!-- North America Quarto media (paper) size: 8" x 10" (203mm x 254mm) -->
+ <string name="mediaSize_na_quarto">Quarto</string>
+ <!-- North America Foolscap media (paper) size: 8" x 13" (203mm x 330mm) -->
+ <string name="mediaSize_na_foolscap">Foolscap</string>
+
+ <!-- Chinese Roc 8k media (paper) size: 270mm x 390mm (10.629" x 15.3543") -->
+ <string name="mediaSize_chinese_roc_8k">ROC 8K</string>
+ <!-- Chinese Roc 16k media (paper) size: 195mm x 270mm (7.677" x 10.629") -->
+ <string name="mediaSize_chinese_roc_16k">ROC 16K</string>
+
+ <!-- Chinese PRC 1 media (paper) size: 102mm x 165mm (4.015" x 6.496") -->
+ <string name="mediaSize_chinese_prc_1">PRC 1</string>
+ <!-- Chinese PRC 2 media (paper) size: 102mm x 176mm (4.015" x 6.929") -->
+ <string name="mediaSize_chinese_prc_2">PRC 2</string>
+ <!-- Chinese PRC 3 media (paper) size: 125mm x 176mm (4.921" x 6.929") -->
+ <string name="mediaSize_chinese_prc_3">PRC 3</string>
+ <!-- Chinese PRC 4 media (paper) size: 110mm x 208mm (4.330" x 8.189") -->
+ <string name="mediaSize_chinese_prc_4">PRC 4</string>
+ <!-- Chinese PRC 5 media (paper) size: 110mm x 220mm (4.330" x 8.661") -->
+ <string name="mediaSize_chinese_prc_5">PRC 5</string>
+ <!-- Chinese PRC 6 media (paper) size: 120mm x 320mm (4.724" x 12.599") -->
+ <string name="mediaSize_chinese_prc_6">PRC 6</string>
+ <!-- Chinese PRC 7 media (paper) size: 160mm x 230mm (6.299" x 9.055") -->
+ <string name="mediaSize_chinese_prc_7">PRC 7</string>
+ <!-- Chinese PRC 8 media (paper) size: 120mm x 309mm (4.724" x 12.165") -->
+ <string name="mediaSize_chinese_prc_8">PRC 8</string>
+ <!-- Chinese PRC 9 media (paper) size: 229mm x 324mm (9.016" x 12.756") -->
+ <string name="mediaSize_chinese_prc_9">PRC 9</string>
+ <!-- Chinese PRC 10 media (paper) size: 324mm x 458mm (12.756" x 18.032") -->
+ <string name="mediaSize_chinese_prc_10">PRC 10</string>
+
+ <!-- Chinese RPC 16K media (paper) size: 146mm x 215mm (5.749" x 8.465") -->
+ <string name="mediaSize_chinese_prc_16k">PRC 16K</string>
+ <!-- Chinese Pa Kai media (paper) size: 146mm x 215mm (5.749" x 8.465") -->
+ <string name="mediaSize_chinese_om_pa_kai">Pa Kai</string>
+ <!-- Chinese Dai Pa Kai media (paper) size: 275mm x 395mm (10.827" x 15.551") -->
+ <string name="mediaSize_chinese_om_dai_pa_kai">Dai Pa Kai</string>
+ <!-- Chinese Jurro Ku Kai media (paper) size: 275mm x 395mm (10.827" x 15.551") -->
+ <string name="mediaSize_chinese_om_jurro_ku_kai">Jurro Ku Kai</string>
+
+ <!-- Japanese JIS B10 media (paper) size: 32mm x 45mm (1.259" x 1.772") -->
+ <string name="mediaSize_japanese_jis_b10">JIS B10</string>
+ <!-- Japanese JIS B9 media (paper) size: 45mm x 64mm (1.772" x 2.52") -->
+ <string name="mediaSize_japanese_jis_b9">JIS B9</string>
+ <!-- Japanese JIS B8 media (paper) size: 64mm x 91mm (2.52" x 3.583") -->
+ <string name="mediaSize_japanese_jis_b8">JIS B8</string>
+ <!-- Japanese JIS B7 media (paper) size: 91mm x 128mm (3.583" x 5.049") -->
+ <string name="mediaSize_japanese_jis_b7">JIS B7</string>
+ <!-- Japanese JIS B6 media (paper) size: 128mm x 182mm (5.049" x 7.165") -->
+ <string name="mediaSize_japanese_jis_b6">JIS B6</string>
+ <!-- Japanese JIS B5 media (paper) size: 182mm x 257mm (7.165" x 10.118") -->
+ <string name="mediaSize_japanese_jis_b5">JIS B5</string>
+ <!-- Japanese JIS B4 media (paper) size: 257mm x 364mm (10.118" x 14.331") -->
+ <string name="mediaSize_japanese_jis_b4">JIS B4</string>
+ <!-- Japanese JIS B3 media (paper) size: 364mm x 515mm (14.331" x 20.276") -->
+ <string name="mediaSize_japanese_jis_b3">JIS B3</string>
+ <!-- Japanese JIS B2 media (paper) size: 515mm x 728mm (20.276" x 28.661") -->
+ <string name="mediaSize_japanese_jis_b2">JIS B2</string>
+ <!-- Japanese JIS B1 media (paper) size: 728mm x 1030mm (28.661" x 40.551") -->
+ <string name="mediaSize_japanese_jis_b1">JIS B1</string>
+ <!-- Japanese JIS B0 media (paper) size: 1030mm x 1456mm (40.551" x 57.323") -->
+ <string name="mediaSize_japanese_jis_b0">JIS B0</string>
+
+ <!-- Japanese JIS Exec media (paper) size: 216mm x 330mm (8.504" x 12.992") -->
+ <string name="mediaSize_japanese_jis_exec">JIS Exec</string>
+
+ <!-- Japanese Chou4 media (paper) size: 90mm x 205mm (3.543" x 8.071") -->
+ <string name="mediaSize_japanese_chou4">Chou4</string>
+ <!-- Japanese Chou3 media (paper) size: 120mm x 235mm (4.724" x 9.252") -->
+ <string name="mediaSize_japanese_chou3">Chou3</string>
+ <!-- Japanese Chou2 media (paper) size: 111.1mm x 146mm (4.374" x 5.748") -->
+ <string name="mediaSize_japanese_chou2">Chou2</string>
+
+ <!-- Japanese Hagaki media (paper) size: 100mm x 148mm (3.937" x 5.827") -->
+ <string name="mediaSize_japanese_hagaki">Hagaki </string>
+ <!-- Japanese Oufuku media (paper) size: 148mm x 200mm (5.827" x 7.874") -->
+ <string name="mediaSize_japanese_oufuku">Oufuku </string>
+ <!-- Japanese Kahu media (paper) size: 240mm x 322.1mm (9.449" x 12.681") -->
+ <string name="mediaSize_japanese_kahu">Kahu</string>
+ <!-- Japanese Kaku2 media (paper) size: 240mm x 332mm (9.449" x 13.071") -->
+ <string name="mediaSize_japanese_kaku2">Kaku2</string>
+ <!-- Japanese You4 media (paper) size: 105mm x 235mm (4.134" x 9.252") -->
+ <string name="mediaSize_japanese_you4">You4</string>
+
<!-- Write fail reason: printing was cancelled.[CHAR LIMIT=none] -->
<string name="write_fail_reason_cancelled">Cancelled</string>
<!-- Write fail reason: couldn't write the printed content. [CHAR LIMIT=none] -->
@@ -4323,9 +4441,7 @@
<!-- PIN entry dialog tells the user to not enter a PIN for a while. [CHAR LIMIT=none] -->
<string name="restr_pin_try_later">Try again later</string>
- <!-- Toast bar message when hiding the transient navigation bar [CHAR LIMIT=35] -->
- <string name="transient_navigation_confirmation">Swipe edge of screen to reveal bar</string>
+ <!-- Toast bar message when hiding the transient navigation bar [CHAR LIMIT=45] -->
+ <string name="transient_navigation_confirmation">Swipe down from the top to exit full screen</string>
- <!-- Longer version of toast bar message when hiding the transient navigation bar (if room) -->
- <string name="transient_navigation_confirmation_long">Swipe from edge of screen to reveal system bar</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 39e7127..e82c0e1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -260,6 +260,7 @@
<java-symbol type="bool" name="config_sip_wifi_only" />
<java-symbol type="bool" name="config_sms_capable" />
<java-symbol type="bool" name="config_sms_utf8_support" />
+ <java-symbol type="bool" name="config_suspendWhenScreenOffDueToProximity" />
<java-symbol type="bool" name="config_swipeDisambiguation" />
<java-symbol type="bool" name="config_syncstorageengine_masterSyncAutomatically" />
<java-symbol type="bool" name="config_telephony_use_own_number_for_voicemail" />
@@ -300,6 +301,7 @@
<java-symbol type="integer" name="config_ntpThreshold" />
<java-symbol type="integer" name="config_ntpTimeout" />
<java-symbol type="integer" name="config_toastDefaultGravity" />
+ <java-symbol type="integer" name="config_transient_navigation_confirmation_panic" />
<java-symbol type="integer" name="config_wifi_framework_scan_interval" />
<java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
<java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
@@ -313,6 +315,7 @@
<java-symbol type="integer" name="config_multiuserMaximumUsers" />
<java-symbol type="integer" name="config_safe_media_volume_index" />
<java-symbol type="integer" name="config_mobile_mtu" />
+ <java-symbol type="integer" name="config_volte_replacement_rat"/>
<java-symbol type="color" name="tab_indicator_text_v4" />
@@ -875,6 +878,48 @@
<java-symbol type="string" name="mediaSize_na_junior_legal" />
<java-symbol type="string" name="mediaSize_na_ledger" />
<java-symbol type="string" name="mediaSize_na_tabloid" />
+ <java-symbol type="string" name="mediaSize_na_index_3x5" />
+ <java-symbol type="string" name="mediaSize_na_index_4x6" />
+ <java-symbol type="string" name="mediaSize_na_index_5x8" />
+ <java-symbol type="string" name="mediaSize_na_monarch" />
+ <java-symbol type="string" name="mediaSize_na_quarto" />
+ <java-symbol type="string" name="mediaSize_na_foolscap" />
+ <java-symbol type="string" name="mediaSize_chinese_roc_8k" />
+ <java-symbol type="string" name="mediaSize_chinese_roc_16k" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_1" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_2" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_3" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_4" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_5" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_6" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_7" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_8" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_9" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_10" />
+ <java-symbol type="string" name="mediaSize_chinese_prc_16k" />
+ <java-symbol type="string" name="mediaSize_chinese_om_pa_kai" />
+ <java-symbol type="string" name="mediaSize_chinese_om_dai_pa_kai" />
+ <java-symbol type="string" name="mediaSize_chinese_om_jurro_ku_kai" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b10" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b9" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b8" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b7" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b6" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b5" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b4" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b3" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b2" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b1" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_b0" />
+ <java-symbol type="string" name="mediaSize_japanese_jis_exec" />
+ <java-symbol type="string" name="mediaSize_japanese_chou4" />
+ <java-symbol type="string" name="mediaSize_japanese_chou3" />
+ <java-symbol type="string" name="mediaSize_japanese_chou2" />
+ <java-symbol type="string" name="mediaSize_japanese_hagaki" />
+ <java-symbol type="string" name="mediaSize_japanese_oufuku" />
+ <java-symbol type="string" name="mediaSize_japanese_kahu" />
+ <java-symbol type="string" name="mediaSize_japanese_kaku2" />
+ <java-symbol type="string" name="mediaSize_japanese_you4" />
<java-symbol type="string" name="reason_unknown" />
<java-symbol type="string" name="restr_pin_enter_admin_pin" />
<java-symbol type="string" name="restr_pin_enter_pin" />
@@ -883,7 +928,9 @@
<java-symbol type="string" name="write_fail_reason_cancelled" />
<java-symbol type="string" name="write_fail_reason_cannot_write" />
<java-symbol type="string" name="transient_navigation_confirmation" />
- <java-symbol type="string" name="transient_navigation_confirmation_long" />
+ <java-symbol type="string" name="ssl_ca_cert_noti_by_unknown" />
+ <java-symbol type="string" name="ssl_ca_cert_noti_managed" />
+ <java-symbol type="string" name="ssl_ca_cert_warning" />
<java-symbol type="plurals" name="abbrev_in_num_days" />
<java-symbol type="plurals" name="abbrev_in_num_hours" />
@@ -1006,6 +1053,7 @@
<java-symbol type="drawable" name="stat_notify_rssi_in_range" />
<java-symbol type="drawable" name="stat_sys_gps_on" />
<java-symbol type="drawable" name="stat_sys_tether_wifi" />
+ <java-symbol type="drawable" name="stat_sys_certificate_info" />
<java-symbol type="drawable" name="status_bar_background" />
<java-symbol type="drawable" name="sym_keyboard_shift" />
<java-symbol type="drawable" name="sym_keyboard_shift_locked" />
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index 54881d5..1649268 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -16,21 +16,13 @@
<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.connectivitymanagertest"
- android:sharedUserId="android.uid.system">
+ package="com.android.connectivitymanagertest">
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
which is needed when building test cases. -->
<application>
<uses-library android:name="android.test.runner" />
- <activity android:name="ConnectivityManagerTestActivity"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
</application>
<!--
@@ -80,10 +72,14 @@
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <!-- This permission is added for API call setAirplaneMode() in ConnectivityManager -->
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
+ <uses-permission android:name="android.permission.DEVICE_POWER" />
+
</manifest>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index 0461c0b..b942eb6 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -32,13 +32,11 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.RouteInfo;
-import android.util.Log;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
similarity index 87%
rename from core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
rename to core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
index 463e999..30eda75 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
@@ -16,7 +16,7 @@
package com.android.connectivitymanagertest;
-import android.app.Activity;
+import android.app.KeyguardManager;
import android.content.Context;
import android.content.BroadcastReceiver;
import android.content.Intent;
@@ -26,21 +26,14 @@
import android.net.NetworkInfo.State;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.os.Bundle;
import android.os.Handler;
-import android.os.IPowerManager;
import android.os.Message;
import android.os.PowerManager;
-import android.os.ServiceManager;
import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.Settings;
+import android.test.InstrumentationTestCase;
import android.util.Log;
import android.view.KeyEvent;
-import android.widget.LinearLayout;
import com.android.internal.util.AsyncChannel;
@@ -52,13 +45,17 @@
/**
- * An activity registered with connectivity manager broadcast
- * provides network connectivity information and
- * can be used to set device states: Cellular, Wifi, Airplane mode.
+ * Base InstrumentationTestCase for Connectivity Manager (CM) test suite
+ *
+ * It registers connectivity manager broadcast and WiFi broadcast to provide
+ * network connectivity information, also provides a set of utility functions
+ * to modify and verify connectivity states.
+ *
+ * A CM test case should extend this base class.
*/
-public class ConnectivityManagerTestActivity extends Activity {
+public class ConnectivityManagerTestBase extends InstrumentationTestCase {
- public static final String LOG_TAG = "ConnectivityManagerTestActivity";
+ public static final String LOG_TAG = "ConnectivityManagerTestBase";
public static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
public static final int WIFI_SCAN_TIMEOUT = 50 * 1000; // 50 seconds
public static final int SHORT_TIMEOUT = 5 * 1000; // 5 seconds
@@ -94,14 +91,9 @@
private Context mContext;
public boolean scanResultAvailable = false;
- /*
- * Control Wifi States
- */
+ /* Control Wifi States */
public WifiManager mWifiManager;
-
- /*
- * Verify connectivity state
- */
+ /* Verify connectivity state */
public static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
NetworkState[] connectivityState = new NetworkState[NUM_NETWORK_TYPES];
@@ -208,26 +200,28 @@
}
}
- public ConnectivityManagerTestActivity() {
+ @Override
+ public void setUp() throws Exception {
mState = State.UNKNOWN;
scanResultAvailable = false;
- }
+ mContext = getInstrumentation().getContext();
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- log("onCreate, inst=" + Integer.toHexString(hashCode()));
+ // Get an instance of ConnectivityManager
+ mCM = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ // Get an instance of WifiManager
+ mWifiManager =(WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
- // Create a simple layout
- LinearLayout contentView = new LinearLayout(this);
- contentView.setOrientation(LinearLayout.VERTICAL);
- setContentView(contentView);
- setTitle("ConnectivityManagerTestActivity");
+ if (mWifiManager.isWifiApEnabled()) {
+ // if soft AP is enabled, disable it
+ mWifiManager.setWifiApEnabled(null, false);
+ log("Disable soft ap");
+ }
+ initializeNetworkStates();
// register a connectivity receiver for CONNECTIVITY_ACTION;
mConnectivityReceiver = new ConnectivityReceiver();
- registerReceiver(mConnectivityReceiver,
+ mContext.registerReceiver(mConnectivityReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
mWifiReceiver = new WifiReceiver();
@@ -238,28 +232,15 @@
mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
- registerReceiver(mWifiReceiver, mIntentFilter);
+ mContext.registerReceiver(mWifiReceiver, mIntentFilter);
- // Get an instance of ConnectivityManager
- mCM = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
- // Get an instance of WifiManager
- mWifiManager =(WifiManager)getSystemService(Context.WIFI_SERVICE);
- mContext = this;
-
- if (mWifiManager.isWifiApEnabled()) {
- // if soft AP is enabled, disable it
- mWifiManager.setWifiApEnabled(null, false);
- log("Disable soft ap");
- }
-
- initializeNetworkStates();
log("Clear Wifi before we start the test.");
removeConfiguredNetworksAndDisableWifi();
mWifiRegexs = mCM.getTetherableWifiRegexs();
}
public List<WifiConfiguration> loadNetworkConfigurations() throws Exception {
- InputStream in = getAssets().open(ACCESS_POINT_FILE);
+ InputStream in = mContext.getAssets().open(ACCESS_POINT_FILE);
mParseHelper = new AccessPointParserHelper(in);
return mParseHelper.getNetworkConfigurations();
}
@@ -277,6 +258,12 @@
public void recordNetworkState(int networkType, State networkState) {
log("record network state for network " + networkType +
", state is " + networkState);
+ if (connectivityState == null) {
+ log("ConnectivityState is null");
+ }
+ if (connectivityState[networkType] == null) {
+ log("connectivityState[networkType] is null");
+ }
connectivityState[networkType].recordState(networkState);
}
@@ -503,7 +490,7 @@
public void turnScreenOff() {
log("Turn screen off");
PowerManager pm =
- (PowerManager) getSystemService(Context.POWER_SERVICE);
+ (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
pm.goToSleep(SystemClock.uptimeMillis());
}
@@ -511,8 +498,13 @@
public void turnScreenOn() {
log("Turn screen on");
PowerManager pm =
- (PowerManager) getSystemService(Context.POWER_SERVICE);
+ (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
pm.wakeUp(SystemClock.uptimeMillis());
+ // disable lock screen
+ KeyguardManager km = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ if (km.inKeyguardRestrictedInputMode()) {
+ sendKeys(KeyEvent.KEYCODE_MENU);
+ }
}
/**
@@ -607,7 +599,12 @@
mWifiManager.setWifiEnabled(true);
sleep(SHORT_TIMEOUT);
}
+
List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
+ if (wifiConfigList == null) {
+ log("no configuration list is null");
+ return true;
+ }
log("size of wifiConfigList: " + wifiConfigList.size());
for (WifiConfiguration wifiConfig: wifiConfigList) {
log("remove wifi configuration: " + wifiConfig.networkId);
@@ -651,75 +648,20 @@
} catch (InterruptedException e) {}
}
- /**
- * Set airplane mode
- */
- public void setAirplaneMode(Context context, boolean enableAM) {
- //set the airplane mode
- Settings.Global.putInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
- enableAM ? 1 : 0);
- // Post the intent
- Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- intent.putExtra("state", enableAM);
- context.sendBroadcastAsUser(intent, UserHandle.ALL);
- }
-
protected static String convertToQuotedString(String string) {
return "\"" + string + "\"";
}
@Override
- protected void onDestroy() {
- super.onDestroy();
-
+ public void tearDown() throws Exception{
//Unregister receiver
if (mConnectivityReceiver != null) {
- unregisterReceiver(mConnectivityReceiver);
+ mContext.unregisterReceiver(mConnectivityReceiver);
}
if (mWifiReceiver != null) {
- unregisterReceiver(mWifiReceiver);
+ mContext.unregisterReceiver(mWifiReceiver);
}
- log("onDestroy, inst=" + Integer.toHexString(hashCode()));
- }
-
- @Override
- public void onStart() {
- super.onStart();
- mContext = this;
- Bundle bundle = this.getIntent().getExtras();
- if (bundle != null){
- mPowerSsid = bundle.getString("power_ssid");
- }
- }
- //A thread to set the device into airplane mode then turn on wifi.
- Thread setDeviceWifiAndAirplaneThread = new Thread(new Runnable() {
- public void run() {
- setAirplaneMode(mContext, true);
- connectToWifi(mPowerSsid);
- }
- });
-
- //A thread to set the device into wifi
- Thread setDeviceInWifiOnlyThread = new Thread(new Runnable() {
- public void run() {
- connectToWifi(mPowerSsid);
- }
- });
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- switch (keyCode) {
- //This is a tricky way for the scripted monkey to
- //set the device in wifi and wifi in airplane mode.
- case KeyEvent.KEYCODE_1:
- setDeviceWifiAndAirplaneThread.start();
- break;
-
- case KeyEvent.KEYCODE_2:
- setDeviceInWifiOnlyThread.start();
- break;
- }
- return super.onKeyDown(keyCode, event);
+ super.tearDown();
}
private void log(String message) {
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
index 3a78f26..0e57a00 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
@@ -16,10 +16,8 @@
package com.android.connectivitymanagertest;
-import android.os.Bundle;
import android.test.InstrumentationTestRunner;
import android.test.InstrumentationTestSuite;
-import android.util.Log;
import com.android.connectivitymanagertest.unit.WifiClientTest;
import com.android.connectivitymanagertest.unit.WifiSoftAPTest;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index 3111489..05462b4 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -24,31 +24,24 @@
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.provider.Settings;
-import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
import com.android.connectivitymanagertest.NetworkState;
public class ConnectivityManagerMobileTest extends
- ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
- private static final String LOG_TAG = "ConnectivityManagerMobileTest";
+ ConnectivityManagerTestBase {
+ private static final String TAG = "ConnectivityManagerMobileTest";
private String mTestAccessPoint;
- private ConnectivityManagerTestActivity cmActivity;
private WakeLock wl;
private boolean mWifiOnlyFlag;
- public ConnectivityManagerMobileTest() {
- super(ConnectivityManagerTestActivity.class);
- }
-
@Override
public void setUp() throws Exception {
super.setUp();
- cmActivity = getActivity();
ConnectivityManagerTestRunner mRunner =
(ConnectivityManagerTestRunner)getInstrumentation();
mTestAccessPoint = mRunner.mTestSsid;
@@ -62,12 +55,12 @@
if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON) == 1) {
log("airplane is not disabled, disable it.");
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+ mCM.setAirplaneMode(false);
}
if (!mWifiOnlyFlag) {
- if (!cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT)) {
+ if (!waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT)) {
// Note: When the test fails in setUp(), tearDown is not called. In that case,
// the activity is destroyed which blocks the next test at "getActivity()".
// tearDown() is called here to avoid that situation.
@@ -79,29 +72,22 @@
@Override
public void tearDown() throws Exception {
- cmActivity.finish();
- log("tear down ConnectivityManagerTestActivity");
wl.release();
- cmActivity.removeConfiguredNetworksAndDisableWifi();
- // if airplane mode is set, disable it.
- if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON) == 1) {
- log("disable airplane mode if it is enabled");
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
- }
+ removeConfiguredNetworksAndDisableWifi();
+ mCM.setAirplaneMode(false);
super.tearDown();
}
// help function to verify 3G connection
public void verifyCellularConnection() {
- NetworkInfo extraNetInfo = cmActivity.mCM.getActiveNetworkInfo();
+ NetworkInfo extraNetInfo = mCM.getActiveNetworkInfo();
assertEquals("network type is not MOBILE", ConnectivityManager.TYPE_MOBILE,
extraNetInfo.getType());
assertTrue("not connected to cellular network", extraNetInfo.isConnected());
}
private void log(String message) {
- Log.v(LOG_TAG, message);
+ Log.v(TAG, message);
}
private void sleep(long sleeptime) {
@@ -115,46 +101,46 @@
@LargeTest
public void test3GToWifiNotification() {
if (mWifiOnlyFlag) {
- Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+ Log.v(TAG, this.getName() + " is excluded for wifi-only test");
return;
}
// Enable Wi-Fi to avoid initial UNKNOWN state
- cmActivity.enableWifi();
- sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ enableWifi();
+ sleep(2 * SHORT_TIMEOUT);
// Wi-Fi is disabled
- cmActivity.disableWifi();
+ disableWifi();
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT));
// Wait for 10 seconds for broadcasts to be sent out
sleep(10 * 1000);
// As Wifi stays in DISCONNETED, Mobile statys in CONNECTED,
// the connectivity manager will not broadcast any network connectivity event for Wifi
- NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ NetworkInfo networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(), NetworkState.DO_NOTHING, State.CONNECTED);
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.DO_NOTHING, State.DISCONNECTED);
// Eanble Wifi without associating with any AP
- cmActivity.enableWifi();
- sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ enableWifi();
+ sleep(2 * SHORT_TIMEOUT);
// validate state and broadcast
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("the state for WIFI is changed");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue("state validation fail", false);
}
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("the state for MOBILE is changed");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue("state validation fail", false);
}
// Verify that the device is still connected to MOBILE
@@ -168,40 +154,39 @@
NetworkInfo networkInfo;
if (!mWifiOnlyFlag) {
//Prepare for connectivity verification
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(), NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
}
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.TO_CONNECTION, State.CONNECTED);
// Enable Wifi and connect to a test access point
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
+ connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
log("wifi state is enabled");
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
}
// validate states
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
if (!mWifiOnlyFlag) {
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("Mobile state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
}
@@ -213,61 +198,59 @@
assertNotNull("SSID is null", mTestAccessPoint);
// Connect to mTestAccessPoint
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ connectToWifi(mTestAccessPoint));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
- sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ sleep(SHORT_TIMEOUT);
// Disable Wifi
log("Disable Wifi");
- if (!cmActivity.disableWifi()) {
+ if (!disableWifi()) {
log("disable Wifi failed");
return;
}
// Wait for the Wifi state to be DISABLED
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_DISABLED, LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT));
}
NetworkInfo networkInfo;
if (!mWifiOnlyFlag) {
//Prepare for connectivity state verification
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(), NetworkState.DO_NOTHING,
State.DISCONNECTED);
}
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.TO_CONNECTION, State.CONNECTED);
// wait for 2 minutes before restart wifi
- sleep(ConnectivityManagerTestActivity.WIFI_STOP_START_INTERVAL);
+ sleep(WIFI_STOP_START_INTERVAL);
// Enable Wifi again
log("Enable Wifi again");
- cmActivity.enableWifi();
+ enableWifi();
// Wait for Wifi to be connected and mobile to be disconnected
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
}
// validate wifi states
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
}
@@ -279,48 +262,48 @@
// connect to Wifi
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
+ connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
// Wait for a few seconds to avoid the state that both Mobile and Wifi is connected
- sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ sleep(SHORT_TIMEOUT);
NetworkInfo networkInfo;
if (!mWifiOnlyFlag) {
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(),
NetworkState.TO_CONNECTION,
State.CONNECTED);
}
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
// clear Wifi
- cmActivity.removeConfiguredNetworksAndDisableWifi();
+ removeConfiguredNetworksAndDisableWifi();
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT));
}
// validate states
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
if (!mWifiOnlyFlag) {
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("Mobile state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
}
@@ -330,62 +313,62 @@
@LargeTest
public void testDataConnectionWith3GToAmTo3G() {
if (mWifiOnlyFlag) {
- Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+ Log.v(TAG, this.getName() + " is excluded for wifi-only test");
return;
}
//Prepare for state verification
- NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ NetworkInfo networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(),
NetworkState.TO_DISCONNECTION,
State.DISCONNECTED);
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
assertEquals(State.DISCONNECTED, networkInfo.getState());
// Enable airplane mode
log("Enable airplane mode");
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
- sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ mCM.setAirplaneMode(true);
+ sleep(SHORT_TIMEOUT);
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
assertEquals(State.DISCONNECTED, networkInfo.getState());
// wait until mobile is turn off
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("Mobile state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
// reset state recorder
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(),
NetworkState.TO_CONNECTION,
State.CONNECTED);
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.DO_NOTHING, State.DISCONNECTED);
// disable airplane mode
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+ mCM.setAirplaneMode(false);
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT));
// Validate the state transition
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("Mobile state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
}
@@ -394,107 +377,107 @@
@LargeTest
public void testDataConnectionOverAMWithWifi() {
if (mWifiOnlyFlag) {
- Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+ Log.v(TAG, this.getName() + " is excluded for wifi-only test");
return;
}
assertNotNull("SSID is null", mTestAccessPoint);
// Eanble airplane mode
log("Enable airplane mode");
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
+ mCM.setAirplaneMode(true);
NetworkInfo networkInfo;
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(),
NetworkState.DO_NOTHING,
State.DISCONNECTED);
}
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.TO_CONNECTION, State.CONNECTED);
// Connect to Wifi
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ connectToWifi(mTestAccessPoint));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
// validate state and broadcast
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("state validate for Wifi failed");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue("State validation failed", false);
}
if (!mWifiOnlyFlag) {
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("state validation for Mobile failed");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue("state validation failed", false);
}
}
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+ mCM.setAirplaneMode(false);
}
// Test case 7: test connectivity while transit from Wifi->AM->Wifi
@LargeTest
public void testDataConnectionWithWifiToAMToWifi () {
if (mWifiOnlyFlag) {
- Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+ Log.v(TAG, this.getName() + " is excluded for wifi-only test");
return;
}
// Connect to mTestAccessPoint
assertNotNull("SSID is null", mTestAccessPoint);
// Connect to Wifi
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
+ connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
try {
- Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ Thread.sleep(SHORT_TIMEOUT);
} catch (Exception e) {
log("exception: " + e.toString());
}
// Enable airplane mode without clearing Wifi
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
+ mCM.setAirplaneMode(true);
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
try {
- Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ Thread.sleep(SHORT_TIMEOUT);
} catch (Exception e) {
log("exception: " + e.toString());
}
// Prepare for state validation
- NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ NetworkInfo networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
assertEquals(State.DISCONNECTED, networkInfo.getState());
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI,
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI,
networkInfo.getState(), NetworkState.TO_CONNECTION, State.CONNECTED);
// Disable airplane mode
- cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
+ mCM.setAirplaneMode(false);
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
}
// validate the state transition
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
}
@@ -505,35 +488,33 @@
assertNotNull("SSID is null", mTestAccessPoint);
//Connect to mTestAccessPoint
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ connectToWifi(mTestAccessPoint));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
assertNotNull("Not associated with any AP",
- cmActivity.mWifiManager.getConnectionInfo().getBSSID());
+ mWifiManager.getConnectionInfo().getBSSID());
try {
- Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ Thread.sleep(SHORT_TIMEOUT);
} catch (Exception e) {
log("exception: " + e.toString());
}
// Disconnect from the current AP
log("disconnect from the AP");
- if (!cmActivity.disconnectAP()) {
+ if (!disconnectAP()) {
log("failed to disconnect from " + mTestAccessPoint);
}
// Verify the connectivity state for Wifi is DISCONNECTED
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
- if (!cmActivity.disableWifi()) {
+ if (!disableWifi()) {
log("disable Wifi failed");
return;
}
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_DISABLED, LONG_TIMEOUT));
}
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
index f12e62e..183f2a9 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
@@ -16,7 +16,7 @@
package com.android.connectivitymanagertest.functional;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import com.android.connectivitymanagertest.WifiAssociationTestRunner;
import android.content.Context;
@@ -32,7 +32,6 @@
import android.net.ConnectivityManager;
import android.net.NetworkInfo.State;
import android.test.suitebuilder.annotation.LargeTest;
-import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
/**
@@ -43,30 +42,22 @@
* -w com.android.connectivitymanagertest/.WifiAssociationTestRunner"
*/
public class WifiAssociationTest
- extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+ extends ConnectivityManagerTestBase {
private static final String TAG = "WifiAssociationTest";
- private ConnectivityManagerTestActivity mAct;
private String mSsid = null;
private String mPassword = null;
private String mSecurityType = null;
private String mFrequencyBand = null;
private int mBand;
- private WifiManager mWifiManager = null;
enum SECURITY_TYPE {
OPEN, WEP64, WEP128, WPA_TKIP, WPA2_AES
- };
-
- public WifiAssociationTest() {
- super(ConnectivityManagerTestActivity.class);
}
@Override
public void setUp() throws Exception {
super.setUp();
WifiAssociationTestRunner mRunner = (WifiAssociationTestRunner)getInstrumentation();
- mWifiManager = (WifiManager) mRunner.getContext().getSystemService(Context.WIFI_SERVICE);
- mAct = getActivity();
Bundle arguments = mRunner.getArguments();
mSecurityType = arguments.getString("security-type");
mSsid = arguments.getString("ssid");
@@ -77,17 +68,15 @@
assertNotNull("Ssid is empty", mSsid);
validateFrequencyBand();
// enable Wifi and verify wpa_supplicant is started
- assertTrue("enable Wifi failed", mAct.enableWifi());
- sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT,
- "interrupted while waiting for WPA_SUPPLICANT to start");
- WifiInfo mConnection = mAct.mWifiManager.getConnectionInfo();
+ assertTrue("enable Wifi failed", enableWifi());
+ sleep(2 * SHORT_TIMEOUT, "interrupted while waiting for WPA_SUPPLICANT to start");
+ WifiInfo mConnection = mWifiManager.getConnectionInfo();
assertNotNull(mConnection);
- assertTrue("wpa_supplicant is not started ", mAct.mWifiManager.pingSupplicant());
+ assertTrue("wpa_supplicant is not started ", mWifiManager.pingSupplicant());
}
@Override
public void tearDown() throws Exception {
- log("tearDown()");
super.tearDown();
}
@@ -107,16 +96,16 @@
private void connectToWifi(WifiConfiguration config) {
// step 1: connect to the test access point
assertTrue("failed to associate with " + config.SSID,
- mAct.connectToWifiWithConfiguration(config));
+ connectToWifiWithConfiguration(config));
// step 2: verify Wifi state and network state;
assertTrue("failed to connect with " + config.SSID,
- mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.CONNECTED, ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
// step 3: verify the current connected network is the given SSID
- assertNotNull("Wifi connection returns null", mAct.mWifiManager.getConnectionInfo());
- assertTrue(config.SSID.contains(mAct.mWifiManager.getConnectionInfo().getSSID()));
+ assertNotNull("Wifi connection returns null", mWifiManager.getConnectionInfo());
+ assertTrue(config.SSID.contains(mWifiManager.getConnectionInfo().getSSID()));
}
private void sleep(long sometime, String errorMsg) {
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
index de0298e..ad73ee1 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
@@ -16,35 +16,19 @@
package com.android.connectivitymanagertest.functional;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
-import android.R;
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Intent;
import android.content.Context;
-import android.content.res.Resources;
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WifiConfiguration.Status;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.ConnectivityManager;
-import android.net.DhcpInfo;
-import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.Settings;
import android.test.suitebuilder.annotation.LargeTest;
-import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
-import com.android.internal.util.AsyncChannel;
-
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -56,39 +40,25 @@
* -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner
*/
public class WifiConnectionTest
- extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+ extends ConnectivityManagerTestBase {
private static final String TAG = "WifiConnectionTest";
private static final boolean DEBUG = false;
private List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
- private ConnectivityManagerTestActivity mAct;
- private ConnectivityManagerTestRunner mRunner;
- private WifiManager mWifiManager = null;
- private Set<WifiConfiguration> enabledNetworks = null;
-
- public WifiConnectionTest() {
- super(ConnectivityManagerTestActivity.class);
- }
@Override
public void setUp() throws Exception {
super.setUp();
- mRunner = ((ConnectivityManagerTestRunner)getInstrumentation());
- mWifiManager = (WifiManager) mRunner.getContext().getSystemService(Context.WIFI_SERVICE);
-
- mAct = getActivity();
-
- networks = mAct.loadNetworkConfigurations();
+ networks = loadNetworkConfigurations();
if (DEBUG) {
printNetworkConfigurations();
}
// enable Wifi and verify wpa_supplicant is started
- assertTrue("enable Wifi failed", mAct.enableWifi());
- sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT,
- "interrupted while waiting for WPA_SUPPLICANT to start");
- WifiInfo mConnection = mAct.mWifiManager.getConnectionInfo();
+ assertTrue("enable Wifi failed", enableWifi());
+ sleep(2 * SHORT_TIMEOUT, "interrupted while waiting for WPA_SUPPLICANT to start");
+ WifiInfo mConnection = mWifiManager.getConnectionInfo();
assertNotNull(mConnection);
- assertTrue("wpa_supplicant is not started ", mAct.mWifiManager.pingSupplicant());
+ assertTrue("wpa_supplicant is not started ", mWifiManager.pingSupplicant());
}
private void printNetworkConfigurations() {
@@ -101,8 +71,7 @@
@Override
public void tearDown() throws Exception {
- log("tearDown()");
- mAct.removeConfiguredNetworksAndDisableWifi();
+ removeConfiguredNetworksAndDisableWifi();
super.tearDown();
}
@@ -114,20 +83,20 @@
private void connectToWifi(WifiConfiguration config) {
// step 1: connect to the test access point
assertTrue("failed to connect to " + config.SSID,
- mAct.connectToWifiWithConfiguration(config));
+ connectToWifiWithConfiguration(config));
// step 2: verify Wifi state and network state;
- assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.CONNECTED, ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
// step 3: verify the current connected network is the given SSID
- assertNotNull("Wifi connection returns null", mAct.mWifiManager.getConnectionInfo());
+ assertNotNull("Wifi connection returns null", mWifiManager.getConnectionInfo());
if (DEBUG) {
log("config.SSID = " + config.SSID);
- log("mAct.mWifiManager.getConnectionInfo.getSSID()" +
- mAct.mWifiManager.getConnectionInfo().getSSID());
+ log("mWifiManager.getConnectionInfo.getSSID()" +
+ mWifiManager.getConnectionInfo().getSSID());
}
- assertTrue(config.SSID.contains(mAct.mWifiManager.getConnectionInfo().getSSID()));
+ assertTrue(config.SSID.contains(mWifiManager.getConnectionInfo().getSSID()));
}
private void sleep(long sometime, String errorMsg) {
@@ -149,8 +118,7 @@
log("-- START Wi-Fi connection test to : " + ssid + " --");
connectToWifi(networks.get(i));
// wait for 2 minutes between wifi stop and start
- sleep(ConnectivityManagerTestActivity.WIFI_STOP_START_INTERVAL,
- "interruped while connected to wifi");
+ sleep(WIFI_STOP_START_INTERVAL, "interruped while connected to wifi");
log("-- END Wi-Fi connection test to " + ssid + " -- ");
}
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
index 60595fb..790ca38 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
@@ -18,19 +18,13 @@
import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
-import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.AuthAlgorithm;
import android.net.wifi.WifiManager;
import android.os.Environment;
-import android.os.IPowerManager;
-import android.os.PowerManager;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
@@ -42,30 +36,24 @@
* Stress the wifi driver as access point.
*/
public class WifiApStress
- extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+ extends ConnectivityManagerTestBase {
private final static String TAG = "WifiApStress";
private static String NETWORK_ID = "AndroidAPTest";
private static String PASSWD = "androidwifi";
private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
- private ConnectivityManagerTestActivity mAct;
private int iterations;
private BufferedWriter mOutputWriter = null;
private int mLastIteration = 0;
private boolean mWifiOnlyFlag;
- public WifiApStress() {
- super(ConnectivityManagerTestActivity.class);
- }
-
@Override
public void setUp() throws Exception {
super.setUp();
- mAct = getActivity();
ConnectivityManagerStressTestRunner mRunner =
(ConnectivityManagerStressTestRunner)getInstrumentation();
iterations = mRunner.mSoftapIterations;
mWifiOnlyFlag = mRunner.mWifiOnlyFlag;
- mAct.turnScreenOn();
+ turnScreenOn();
}
@Override
@@ -92,30 +80,28 @@
config.preSharedKey = PASSWD;
// If Wifi is enabled, disable it
- if (mAct.mWifiManager.isWifiEnabled()) {
- mAct.disableWifi();
+ if (mWifiManager.isWifiEnabled()) {
+ disableWifi();
}
int i;
for (i = 0; i < iterations; i++) {
Log.v(TAG, "iteration: " + i);
mLastIteration = i;
// enable Wifi tethering
- assertTrue(mAct.mWifiManager.setWifiApEnabled(config, true));
+ assertTrue(mWifiManager.setWifiApEnabled(config, true));
// Wait for wifi ap state to be ENABLED
- assertTrue(mAct.waitForWifiAPState(WifiManager.WIFI_AP_STATE_ENABLED,
- 2 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForWifiAPState(WifiManager.WIFI_AP_STATE_ENABLED, 2 * LONG_TIMEOUT));
// Wait for wifi tethering result
- assertEquals(ConnectivityManagerTestActivity.SUCCESS,
- mAct.waitForTetherStateChange(2*ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+ assertEquals(SUCCESS, waitForTetherStateChange(2 * SHORT_TIMEOUT));
// Allow the wifi tethering to be enabled for 10 seconds
try {
- Thread.sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ Thread.sleep(2 * SHORT_TIMEOUT);
} catch (Exception e) {
fail("thread in sleep is interrupted");
}
- assertTrue("no uplink data connection after Wi-Fi tethering", mAct.pingTest(null));
+ assertTrue("no uplink data connection after Wi-Fi tethering", pingTest(null));
// Disable soft AP
- assertTrue(mAct.mWifiManager.setWifiApEnabled(config, false));
+ assertTrue(mWifiManager.setWifiApEnabled(config, false));
// Wait for 30 seconds until Wi-Fi tethering is stopped
try {
Thread.sleep(30 * 1000);
@@ -123,7 +109,7 @@
} catch (Exception e) {
fail("thread in sleep is interrupted");
}
- assertFalse("Wi-Fi AP disable failed", mAct.mWifiManager.isWifiApEnabled());
+ assertFalse("Wi-Fi AP disable failed", mWifiManager.isWifiApEnabled());
}
if (i == iterations) {
mLastIteration = iterations;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index e3c7cc4..04ce4b7 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -29,12 +29,11 @@
import android.os.PowerManager;
import android.provider.Settings;
import android.view.KeyEvent;
-import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import java.io.BufferedWriter;
import java.io.File;
@@ -50,7 +49,7 @@
* -w com.android.connectivitymanagertest/.ConnectivityManagerStressTestRunner
*/
public class WifiStressTest
- extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+ extends ConnectivityManagerTestBase {
private final static String TAG = "WifiStressTest";
/**
@@ -67,7 +66,6 @@
private final static long WIFI_SHUTDOWN_DELAY = 2 * 60 * 1000;
private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
- private ConnectivityManagerTestActivity mAct;
private int mReconnectIterations;
private int mWifiSleepTime;
private int mScanIterations;
@@ -77,15 +75,10 @@
private BufferedWriter mOutputWriter = null;
private boolean mWifiOnlyFlag;
- public WifiStressTest() {
- super(ConnectivityManagerTestActivity.class);
- }
-
@Override
public void setUp() throws Exception {
super.setUp();
- mAct = getActivity();
mRunner = (ConnectivityManagerStressTestRunner) getInstrumentation();
mReconnectIterations = mRunner.mReconnectIterations;
mSsid = mRunner.mReconnectSsid;
@@ -98,15 +91,14 @@
mPassword, mScanIterations, mWifiSleepTime));
mOutputWriter = new BufferedWriter(new FileWriter(new File(
Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
- mAct.turnScreenOn();
- if (!mAct.mWifiManager.isWifiEnabled()) {
+ turnScreenOn();
+ if (!mWifiManager.isWifiEnabled()) {
log("Enable wi-fi before stress tests.");
- if (!mAct.enableWifi()) {
+ if (!enableWifi()) {
tearDown();
fail("enable wifi failed.");
}
- sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT,
- "Interruped while waiting for wifi on");
+ sleep(SHORT_TIMEOUT, "Interruped while waiting for wifi on");
}
}
@@ -166,33 +158,32 @@
writeOutput(String.format("ssid appear %d out of %d scan iterations",
ssidAppearInScanResultsCount, i));
long startTime = System.currentTimeMillis();
- mAct.scanResultAvailable = false;
- assertTrue("start scan failed", mAct.mWifiManager.startScan());
+ scanResultAvailable = false;
+ assertTrue("start scan failed", mWifiManager.startScan());
while (true) {
if ((System.currentTimeMillis() - startTime) >
- ConnectivityManagerTestActivity.WIFI_SCAN_TIMEOUT) {
- fail("Wifi scanning takes more than " +
- ConnectivityManagerTestActivity.WIFI_SCAN_TIMEOUT + " ms");
+ WIFI_SCAN_TIMEOUT) {
+ fail("Wifi scanning takes more than " + WIFI_SCAN_TIMEOUT + " ms");
}
- synchronized(mAct) {
+ synchronized(this) {
try {
- mAct.wait(ConnectivityManagerTestActivity.WAIT_FOR_SCAN_RESULT);
+ wait(WAIT_FOR_SCAN_RESULT);
} catch (InterruptedException e) {
e.printStackTrace();
}
- if (mAct.scanResultAvailable) {
+ if (scanResultAvailable) {
long scanTime = (System.currentTimeMillis() - startTime);
scanTimeSum += scanTime;
break;
}
}
}
- if ((mAct.mWifiManager.getScanResults() == null) ||
- (mAct.mWifiManager.getScanResults().size() <= 0)) {
+ if ((mWifiManager.getScanResults() == null) ||
+ (mWifiManager.getScanResults().size() <= 0)) {
fail("Scan results are empty ");
}
- List<ScanResult> netList = mAct.mWifiManager.getScanResults();
+ List<ScanResult> netList = mWifiManager.getScanResults();
if (netList != null) {
log("size of scan result list: " + netList.size());
for (int s = 0; s < netList.size(); s++) {
@@ -244,13 +235,13 @@
config.proxySettings = ProxySettings.NONE;
assertTrue("Failed to connect to Wi-Fi network: " + mSsid,
- mAct.connectToWifiWithConfiguration(config));
- assertTrue(mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.SHORT_TIMEOUT));
- assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ connectToWifiWithConfiguration(config));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+ SHORT_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
// Run ping test to verify the data connection
- assertTrue("Wi-Fi is connected, but no data connection.", mAct.pingTest(null));
+ assertTrue("Wi-Fi is connected, but no data connection.", pingTest(null));
int i;
long sum = 0;
@@ -263,33 +254,33 @@
writeOutput(String.format("iteration %d out of %d",
i, mReconnectIterations));
log("iteration: " + i);
- mAct.turnScreenOff();
+ turnScreenOff();
PowerManager pm =
(PowerManager)mRunner.getContext().getSystemService(Context.POWER_SERVICE);
assertFalse(pm.isScreenOn());
sleep(WIFI_IDLE_MS + WIFI_SHUTDOWN_DELAY, "Interruped while wait for wifi to be idle");
assertTrue("Wait for Wi-Fi to idle timeout",
- mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
- 6 * ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
+ 6 * SHORT_TIMEOUT));
if (!mWifiOnlyFlag) {
// use long timeout as the pppd startup may take several retries.
assertTrue("Wait for cellular connection timeout",
- mAct.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
- 2 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+ 2 * LONG_TIMEOUT));
}
sleep(mWifiSleepTime, "Interrupted while device is in sleep mode");
// Verify the wi-fi is still off and data connection is on
assertEquals("Wi-Fi is reconnected", State.DISCONNECTED,
- mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
+ mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
if (!mWifiOnlyFlag) {
assertEquals("Cellular connection is down", State.CONNECTED,
- mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
- assertTrue("Mobile is connected, but no data connection.", mAct.pingTest(null));
+ mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
+ assertTrue("Mobile is connected, but no data connection.", pingTest(null));
}
// Turn screen on again
- mAct.turnScreenOn();
+ turnScreenOn();
// Wait for 2 seconds for the lock screen
sleep(2 * 1000, "wait 2 seconds for lock screen");
// Disable lock screen by inject menu key event
@@ -298,16 +289,16 @@
// Measure the time for Wi-Fi to get connected
long startTime = System.currentTimeMillis();
assertTrue("Wait for Wi-Fi enable timeout after wake up",
- mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+ waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+ SHORT_TIMEOUT));
assertTrue("Wait for Wi-Fi connection timeout after wake up",
- mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
long connectionTime = System.currentTimeMillis() - startTime;
sum += connectionTime;
log("average reconnection time is: " + sum/(i+1));
- assertTrue("Reconnect to Wi-Fi network, but no data connection.", mAct.pingTest(null));
+ assertTrue("Reconnect to Wi-Fi network, but no data connection.", pingTest(null));
}
if (i == mReconnectIterations) {
writeOutput(String.format("iteration %d out of %d",
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
index e44023b..7a9bc78 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
@@ -20,9 +20,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.Context;
-import android.app.Instrumentation;
-import android.os.Handler;
-import android.os.Message;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiConfiguration;
@@ -33,11 +30,8 @@
import android.test.suitebuilder.annotation.LargeTest;
import android.test.AndroidTestCase;
-import java.util.ArrayList;
import java.util.List;
-import android.util.Log;
-
/**
* Test wifi client
*/
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
index 3f43e48..f202862 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
@@ -16,13 +16,7 @@
package com.android.connectivitymanagertest.unit;
-import android.content.BroadcastReceiver;
-import android.content.Intent;
import android.content.Context;
-import android.app.Instrumentation;
-import android.os.Handler;
-import android.os.Message;
-import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -30,8 +24,6 @@
import android.test.suitebuilder.annotation.LargeTest;
import android.test.AndroidTestCase;
-import java.util.ArrayList;
-
import android.util.Log;
/**
diff --git a/core/tests/coretests/src/android/database/MatrixCursorTest.java b/core/tests/coretests/src/android/database/MatrixCursorTest.java
index fc48c17..aa805dc 100644
--- a/core/tests/coretests/src/android/database/MatrixCursorTest.java
+++ b/core/tests/coretests/src/android/database/MatrixCursorTest.java
@@ -132,18 +132,18 @@
MatrixCursor cursor = newMatrixCursor();
cursor.newRow()
- .offer("float", 4.2f)
- .offer("string", "foobar")
- .offer("blob", new byte[] {(byte) 0xaa, (byte) 0x55})
- .offer("lolwat", "kittens");
+ .add("float", 4.2f)
+ .add("string", "foobar")
+ .add("blob", new byte[] {(byte) 0xaa, (byte) 0x55})
+ .add("lolwat", "kittens");
cursor.newRow();
cursor.newRow()
- .offer("string", "zero")
- .offer("string", "one")
- .offer("string", "two")
- .offer("lolwat", "kittens");
+ .add("string", "zero")
+ .add("string", "one")
+ .add("string", "two")
+ .add("lolwat", "kittens");
assertTrue(cursor.moveToFirst());
assertEquals("foobar", cursor.getString(0));
diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
index ebecf2e3..a2e9ae8 100644
--- a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
+++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
@@ -83,8 +83,8 @@
mImageReaderLock.lock();
try {
- mImageReader = new ImageReader(WIDTH, HEIGHT, PixelFormat.RGBA_8888, 2);
- mImageReader.setImageAvailableListener(mImageListener, mHandler);
+ mImageReader = ImageReader.newInstance(WIDTH, HEIGHT, PixelFormat.RGBA_8888, 2);
+ mImageReader.setOnImageAvailableListener(mImageListener, mHandler);
mSurface = mImageReader.getSurface();
} finally {
mImageReaderLock.unlock();
@@ -409,19 +409,11 @@
}
Log.d(TAG, "New image available from virtual display.");
- Image image = reader.getNextImage();
+
+ // Get the latest buffer.
+ Image image = reader.acquireLatestImage();
if (image != null) {
try {
- // Get the latest buffer.
- for (;;) {
- Image nextImage = reader.getNextImage();
- if (nextImage == null) {
- break;
- }
- reader.releaseImage(image);
- image = nextImage;
- }
-
// Scan for colors.
int color = scanImage(image);
synchronized (this) {
@@ -431,7 +423,7 @@
}
}
} finally {
- reader.releaseImage(image);
+ image.close();
}
}
} finally {
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 0d9a386..2846e61 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -138,8 +138,7 @@
DroidSansHebrew-Regular.ttf \
DroidSansHebrew-Bold.ttf \
DroidSansArmenian.ttf \
- DroidSansGeorgian.ttf \
- AndroidEmoji.ttf
+ DroidSansGeorgian.ttf
endif # !MINIMAL_FONT
diff --git a/data/fonts/AndroidEmoji.ttf b/data/fonts/AndroidEmoji.ttf
deleted file mode 100644
index 569cbab..0000000
--- a/data/fonts/AndroidEmoji.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index d9170c9..69db6aa 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -175,12 +175,18 @@
</family>
<family>
<fileset>
+ <file>Padauk-book.ttf</file>
+ <file>Padauk-bookbold.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
<file>NotoSansSymbols-Regular.ttf</file>
</fileset>
</family>
<family>
<fileset>
- <file>AndroidEmoji.ttf</file>
+ <file>NotoColorEmoji.ttf</file>
</fileset>
</family>
<family>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 05cca13e..a677c4f 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -43,7 +43,6 @@
DroidSansMono.ttf \
DroidSansArmenian.ttf \
DroidSansGeorgian.ttf \
- AndroidEmoji.ttf \
Clockopia.ttf \
AndroidClock.ttf \
AndroidClock_Highlight.ttf \
diff --git a/data/videos/VideoPackage1.mk b/data/videos/VideoPackage1.mk
index 0089657..ee3b5ed 100644
--- a/data/videos/VideoPackage1.mk
+++ b/data/videos/VideoPackage1.mk
@@ -19,8 +19,8 @@
LOCAL_PATH := frameworks/base/data/videos
TARGET_PATH := system/media/video
-PRODUCT_COPY_FILES += \
- $(LOCAL_PATH)/AndroidInSpace.240p.mp4:$(TARGET_PATH)/AndroidInSpace.240p.mp4 \
- $(LOCAL_PATH)/AndroidInSpace.480p.lq.mp4:$(TARGET_PATH)/AndroidInSpace.480p.mp4 \
- $(LOCAL_PATH)/Sunset.240p.mp4:$(TARGET_PATH)/Sunset.240p.mp4 \
- $(LOCAL_PATH)/Sunset.480p.lq.mp4:$(TARGET_PATH)/Sunset.480p.mp4
+#PRODUCT_COPY_FILES += \
+# $(LOCAL_PATH)/AndroidInSpace.240p.mp4:$(TARGET_PATH)/AndroidInSpace.240p.mp4 \
+# $(LOCAL_PATH)/AndroidInSpace.480p.lq.mp4:$(TARGET_PATH)/AndroidInSpace.480p.mp4 \
+# $(LOCAL_PATH)/Sunset.240p.mp4:$(TARGET_PATH)/Sunset.240p.mp4 \
+# $(LOCAL_PATH)/Sunset.480p.lq.mp4:$(TARGET_PATH)/Sunset.480p.mp4
diff --git a/data/videos/VideoPackage2.mk b/data/videos/VideoPackage2.mk
index b53fd9f..f799bea 100644
--- a/data/videos/VideoPackage2.mk
+++ b/data/videos/VideoPackage2.mk
@@ -19,8 +19,8 @@
LOCAL_PATH := frameworks/base/data/videos
TARGET_PATH := system/media/video
-PRODUCT_COPY_FILES += \
- $(LOCAL_PATH)/AndroidInSpace.240p.mp4:$(TARGET_PATH)/AndroidInSpace.240p.mp4 \
- $(LOCAL_PATH)/AndroidInSpace.480p.mq.mp4:$(TARGET_PATH)/AndroidInSpace.480p.mp4 \
- $(LOCAL_PATH)/Sunset.240p.mp4:$(TARGET_PATH)/Sunset.240p.mp4 \
- $(LOCAL_PATH)/Sunset.480p.mq.mp4:$(TARGET_PATH)/Sunset.480p.mp4
+#PRODUCT_COPY_FILES += \
+# $(LOCAL_PATH)/AndroidInSpace.240p.mp4:$(TARGET_PATH)/AndroidInSpace.240p.mp4 \
+# $(LOCAL_PATH)/AndroidInSpace.480p.mq.mp4:$(TARGET_PATH)/AndroidInSpace.480p.mp4 \
+# $(LOCAL_PATH)/Sunset.240p.mp4:$(TARGET_PATH)/Sunset.240p.mp4 \
+# $(LOCAL_PATH)/Sunset.480p.mq.mp4:$(TARGET_PATH)/Sunset.480p.mp4
diff --git a/docs/downloads/training/LocationProvider.zip b/docs/downloads/training/LocationProvider.zip
new file mode 100644
index 0000000..d5ee311
--- /dev/null
+++ b/docs/downloads/training/LocationProvider.zip
Binary files differ
diff --git a/docs/html/google/play/billing/gp-purchase-status-api.jd b/docs/html/google/play/billing/gp-purchase-status-api.jd
index c5b8461..25ef28b 100644
--- a/docs/html/google/play/billing/gp-purchase-status-api.jd
+++ b/docs/html/google/play/billing/gp-purchase-status-api.jd
@@ -88,7 +88,7 @@
<h3 id="quota">Quota</h3>
<p>Applications using the Google Play Android Developer API are limited to an
-initial courtesy usage quota of <strong>15000 requests per day</strong> (per
+initial courtesy usage quota of <strong>200,000 requests per day</strong> (per
application). This should provide enough access for normal
subscription-validation needs, assuming that you follow the recommendation in
this section.</p>
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
index 18e479f..07b08f6 100644
--- a/docs/html/guide/topics/manifest/uses-sdk-element.jd
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -1,4 +1,4 @@
-fpage.title=<uses-sdk>
+page.title=<uses-sdk>
page.tags="api levels","sdk version","minsdkversion","targetsdkversion","maxsdkversion"
@jd:body
diff --git a/docs/html/guide/topics/renderscript/compute.jd b/docs/html/guide/topics/renderscript/compute.jd
index 607d16e..14a1682 100644
--- a/docs/html/guide/topics/renderscript/compute.jd
+++ b/docs/html/guide/topics/renderscript/compute.jd
@@ -10,6 +10,11 @@
<ol>
<li><a href="#writing-an-rs-kernel">Writing a RenderScript Kernel</a></li>
+ <li><a href="#access-rs-apis">Accessing RenderScript Java APIs</a>
+ <ol>
+ <li><a href="#ide-setup">Setting Up Your Development Environment</a></li>
+ </ol>
+ </li>
<li><a href="#using-rs-from-java">Using RenderScript from Java Code</a></li>
</ol>
@@ -144,9 +149,85 @@
beneficial on some architectures due to additional optimizations only available with relaxed
precision (such as SIMD CPU instructions).</p>
+
+<h2 id="access-rs-apis">Accessing RenderScript Java APIs</h2>
+
+<p>When developing an Android application that uses RenderScript, you can access its Java API in
+ one of two ways. The APIs are available in the {@link android.renderscript} package
+ on devices running Android 3.0 (API level 11) and higher. These are the original APIs for
+ RenderScript. The APIs are also available as a Support Library in the
+ {@link android.support.v8.renderscript} package, which allow you to use them on devices running
+ Android 2.2 (API level 8) and higher.</p>
+
+<p>We strongly recommend using the Support Library APIs for accessing RenderScript because they
+ include the latest improvements to the RenderScript compute framework and provide a wider range
+ of device compatibility. Using the RenderScript APIs in the Support Library requires specific
+ setup procedures for your development environment, which is described in the next section.</p>
+
+
+<h3 id="ide-setup">Using the RenderScript Support Library APIs</h3>
+
+<p>In order to use the Support Library RenderScript APIs, you must configure your development
+ environment to be able to access them. The following Android SDK tools are required for using
+ these APIs:</p>
+
+<ul>
+ <li>Android SDK Tools revision 22.2 or higher</li>
+ <li>Android SDK Build-tools revision 18.1.0 or higher</li>
+</ul>
+
+<p>You can check and update the installed version of these tools in the
+ <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>.</p>
+
+<p class="note">
+ <strong>Note:</strong> Use of Support Library RenderScript APIs is not currently supported with
+ Android Studio or Gradle-based builds.
+</p>
+
+<p>To use the Support Library RenderScript APIs in Eclipse:</p>
+
+<ol>
+ <li>Make sure you have the required Android SDK version and Build Tools version installed.</li>
+ <li>Open the {@code project.properties} file in the root folder of your application project.</li>
+ <li>Add the following lines to the file:
+<pre>
+renderscript.target=18
+renderscript.support.mode=true
+sdk.buildtools=18.1.0
+</pre>
+ </li>
+ <li>In your application classes that use RenderScript, add an import for the Support Library
+ classes:
+<pre>
+import android.support.v8.renderscript.*;
+</pre>
+ </li>
+</ol>
+
+<p>The {@code project.properties} settings listed above control specific behavior in the Android
+ build process:</p>
+
+<ul>
+ <li>{@code renderscript.target} - Specifies the bytecode version to be generated. We
+ recommend you set this value the highest available API level and set {@code
+ renderscript.support.mode} to {@code true}. Valid values for this setting are any integer value
+ from 11 to the most recently released API level. If your minimum SDK version specified in your
+ application manifest is set to a higher value, this value is ignored and the target value is set
+ to the minimum SDK version.</li>
+ <li>{@code renderscript.support.mode} - Specifies that the generated bytecode should fall
+ back to a compatible version if the device it is running on does not support the target version.
+ </li>
+ <li>{@code sdk.buildtools} - The version of the Android SDK build tools to use. This value
+ should be set to 18.1.0 or higher. If this option is not specified, the highest installed build
+ tools version is used. You should always set this value to ensure the consistency of builds
+ across development machines with different configurations.</li>
+</ul>
+
+
<h2 id="using-rs-from-java">Using RenderScript from Java Code</h2>
-<p>Using RenderScript from Java code relies on the {@link android.renderscript} APIs. Most
+<p>Using RenderScript from Java code relies on the API classes located in the
+{@link android.renderscript} or the {@link android.support.v8.renderscript} package. Most
applications follow the same basic usage patterns:</p>
<ol>
diff --git a/docs/html/guide/topics/ui/how-android-draws.jd b/docs/html/guide/topics/ui/how-android-draws.jd
index 6a8cd86..168f77b 100644
--- a/docs/html/guide/topics/ui/how-android-draws.jd
+++ b/docs/html/guide/topics/ui/how-android-draws.jd
@@ -4,15 +4,19 @@
@jd:body
-<p>When an Activity receives focus, it will be requested to draw its layout.
-The Android framework will handle the procedure for drawing, but the Activity must provide
+<p>When an {@link android.app.Activity} receives focus, it will be requested to
+draw its layout.
+The Android framework will handle the procedure for drawing, but the
+{@link android.app.Activity} must provide
the root node of its layout hierarchy.</p>
<p>Drawing begins with the root node of the layout. It is requested to measure and
-draw the layout tree. Drawing is handled by walking the tree and rendering each View that
- intersects the invalid region. In turn, each View group is responsible for requesting
-each of its children to be drawn (with the <code>{@link android.view.View#draw(Canvas) draw()}</code> method)
-and each View is responsible for drawing itself.
+draw the layout tree. Drawing is handled by walking the tree and rendering each
+{@link android.view.View} that intersects the invalid region. In turn, each
+{@link android.view.ViewGroup} is responsible for requesting
+each of its children to be drawn
+(with the {@link android.view.View#draw(Canvas) draw()} method)
+and each {@link android.view.View} is responsible for drawing itself.
Because the tree is traversed in-order,
this means that parents will be drawn before (i.e., behind) their children, with
siblings drawn in the order they appear in the tree.
@@ -20,76 +24,107 @@
<div class="sidebox-wrapper">
<div class="sidebox">
- <p>The framework will not draw Views that are not in the invalid region, and also
- will take care of drawing the Views background for you.</p>
- <p>You can force a View to draw, by calling <code>{@link android.view.View#invalidate()}</code>.
+ <p>The framework will not draw {@link android.view.View} objects that are not
+in the invalid region, and also
+ will take care of drawing the {@link android.view.View} background for you.</p>
+ <p>You can force a {@link android.view.View} to draw, by calling
+{@link android.view.View#invalidate()}.
</p>
</div>
</div>
<p>
- Drawing the layout is a two pass process: a measure pass and a layout pass. The measuring
- pass is implemented in <code>{@link android.view.View#measure(int, int)}</code> and is a top-down traversal
- of the View tree. Each View pushes dimension specifications down the tree
- during the recursion. At the end of the measure pass, every View has stored
+ Drawing the layout is a two pass process: a measure pass and a layout pass.
+The measuring pass is implemented in {@link android.view.View#measure(int, int)}
+and is a top-down traversal of the {@link android.view.View} tree. Each {@link android.view.View}
+pushes dimension specifications down the tree
+ during the recursion. At the end of the measure pass, every
+{@link android.view.View} has stored
its measurements. The second pass happens in
- <code>{@link android.view.View#layout(int,int,int,int)}</code> and is also top-down. During
+ {@link android.view.View#layout(int,int,int,int)} and is also top-down. During
this pass each parent is responsible for positioning all of its children
using the sizes computed in the measure pass.
</p>
<p>
- When a View's <code>measure()</code> method returns, its <code>{@link android.view.View#getMeasuredWidth()}</code> and
- <code>{@link android.view.View#getMeasuredHeight()}</code> values must be set, along with those for all of
- that View's descendants. A View's measured width and measured height values
- must respect the constraints imposed by the View's parents. This guarantees
+ When a {@link android.view.View} object's
+{@link android.view.View#measure(int, int) measure()} method
+returns, its {@link android.view.View#getMeasuredWidth()} and
+ {@link android.view.View#getMeasuredHeight()} values must be set, along
+ with those for all of that {@link android.view.View} object's descendants.
+A {@link android.view.View} object's measured width and
+measured height values must respect the constraints imposed by the
+{@link android.view.View} object's parents. This guarantees
that at the end of the measure pass, all parents accept all of their
- children's measurements. A parent View may call <code>measure()</code> more than once on
+ children's measurements. A parent {@link android.view.View} may call
+{@link android.view.View#measure(int, int) measure()} more than once on
its children. For example, the parent may measure each child once with
unspecified dimensions to find out how big they want to be, then call
- <code>measure()</code> on them again with actual numbers if the sum of all the children's
- unconstrained sizes is too big or too small (i.e., if the children don't agree among themselves
- as to how much space they each get, the parent will intervene and set the rules on the second pass).
+ {@link android.view.View#measure(int, int) measure()} on them again with
+actual numbers if the sum of all the children's
+ unconstrained sizes is too big or too small (that is, if the children
+don't agree among themselves
+ as to how much space they each get, the parent will intervene and set
+the rules on the second pass).
</p>
<div class="sidebox-wrapper">
<div class="sidebox"><p>
- To initiate a layout, call <code>{@link android.view.View#requestLayout}</code>. This method is typically
- called by a View on itself when it believes that is can no longer fit within
+ To initiate a layout, call {@link android.view.View#requestLayout}.
+This method is typically
+ called by a {@link android.view.View} on itself
+when it believes that is can no longer fit within
its current bounds.</p>
</div>
</div>
<p>
The measure pass uses two classes to communicate dimensions. The
- {@link android.view.ViewGroup.LayoutParams} class is used by Views to tell their parents how they
- want to be measured and positioned. The base LayoutParams class just
- describes how big the View wants to be for both width and height. For each
+ {@link android.view.ViewGroup.LayoutParams} class is used by
+{@link android.view.View} objects to tell their parents how they
+ want to be measured and positioned. The base
+{@link android.view.ViewGroup.LayoutParams} class just
+ describes how big the {@link android.view.View} wants to be for both
+width and height. For each
dimension, it can specify one of:</p>
<ul>
<li> an exact number
- <li><var>FILL_PARENT</var>, which means the View wants to be as big as its parent
+ <li>{@link android.view.ViewGroup.LayoutParams#MATCH_PARENT MATCH_PARENT},
+which means the {@link android.view.View} wants to be as big as its parent
(minus padding)</li>
- <li><var>WRAP_CONTENT</var>, which means that the View wants to be just big enough to
+ <li>{@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT WRAP_CONTENT},
+which means that the {@link android.view.View} wants to be just big enough to
enclose its content (plus padding).</li>
</ul>
- <p>There are subclasses of LayoutParams for different subclasses of ViewGroup.
- For example, RelativeLayout has its own subclass of LayoutParams, which includes
- the ability to center child Views horizontally and vertically.
+ <p>There are subclasses of {@link android.view.ViewGroup.LayoutParams} for
+different subclasses of {@link android.view.ViewGroup}.
+ For example, {@link android.widget.RelativeLayout} has its own subclass of
+{@link android.view.ViewGroup.LayoutParams}, which includes
+ the ability to center child {@link android.view.View} objects
+horizontally and vertically.
</p>
<p>
- MeasureSpecs are used to push requirements down the tree from parent to
- child. A MeasureSpec can be in one of three modes:</p>
+ {@link android.view.View.MeasureSpec MeasureSpec} objects are used to push
+requirements down the tree from parent to
+ child. A {@link android.view.View.MeasureSpec MeasureSpec} can be in one of
+three modes:</p>
<ul>
- <li><var>UNSPECIFIED</var>: This is used by a parent to determine the desired dimension
- of a child View. For example, a LinearLayout may call <code>measure()</code> on its child
- with the height set to <var>UNSPECIFIED</var> and a width of <var>EXACTLY</var> 240 to find out how
- tall the child View wants to be given a width of 240 pixels.</li>
- <li><var>EXACTLY</var>: This is used by the parent to impose an exact size on the
+ <li>{@link android.view.View.MeasureSpec#UNSPECIFIED UNSPECIFIED}: This is
+used by a parent to determine the desired dimension
+ of a child {@link android.view.View}. For example, a
+{@link android.widget.LinearLayout} may call
+{@link android.view.View#measure(int, int) measure()} on its child
+ with the height set to {@link android.view.View.MeasureSpec#UNSPECIFIED UNSPECIFIED}
+and a width of {@link android.view.View.MeasureSpec#EXACTLY EXACTLY} 240 to
+find out how tall the child {@link android.view.View} wants to be given a
+width of 240 pixels.</li>
+ <li>{@link android.view.View.MeasureSpec#EXACTLY EXACTLY}: This is used
+by the parent to impose an exact size on the
child. The child must use this size, and guarantee that all of its
descendants will fit within this size.</li>
- <li><var>AT_MOST</var>: This is used by the parent to impose a maximum size on the
+ <li>{@link android.view.View.MeasureSpec#AT_MOST AT MOST}: This is used by
+the parent to impose a maximum size on the
child. The child must guarantee that it and all of its descendants will fit
within this size.</li>
</ul>
diff --git a/docs/html/samples/index.jd b/docs/html/samples/index.jd
index 028fbe9..3ea5245 100644
--- a/docs/html/samples/index.jd
+++ b/docs/html/samples/index.jd
@@ -1,77 +1,11 @@
page.title=Samples
-header.hide=1
@jd:body
-<style>
-div.landing-cell,
-div.cell-icon {
- height:150px;
-}
-div.cell-icon {
- float:left;
- margin-right:20px;
-}
-div.cell-icon img {
- margin:0;
-}
-</style>
-<div class="landing-banner">
-
-<div class="col-6" style="min-height:0">
- <img src="{@docRoot}images/google/google-services.png" alt="" width="340" height="193" />
-</div>
-<div class="col-6">
-
- <h1 itemprop="name" style="margin-bottom:0;">Samples</h1>
- <p itemprop="description">Some intro here. Overview of Samples, where to get them,
- links to related tools and SDK, and what's new in samples. </p>
-
-</div>
-</div>
-<div> </div>
-
-
-
-
-<div style="margin-top:10px">
-<div class="col-6 normal-links" style="margin-left:0">
-
-<div class="landing-cell">
- <div class="cell-icon">
- <img src="{@docRoot}images/google/maps-pin.png" width="40" >
- </div>
- <h4><a href="{@docRoot}google/play-services/maps.html"
- >Google Maps</a></h4>
- <p>The power of Google Maps is available to your app
- with an embeddable map view. You can customize the map with
- markers and overlays, control the user's perspective, draw lines
- and shapes, and much more.</p>
+<div id="samples">
+<p>Some kind of sample sorting will appear here.</p>
</div>
-</div><!-- col-6 -->
-
-
-
-<div class="col-6" style="margin-right:0">
-
-<div class="landing-cell">
- <div class="cell-icon">
- <img src="{@docRoot}images/google/iab-99c.png" width="40" />
- </div>
- <h4><a href="{@docRoot}google/play/billing/index.html"
- >Google Play In-App Billing</a></h4>
- <p>Build an app with a steady revenue stream that keeps users engaged
- by offering new content or virtual goods directly in your app. All transactions are handled
- by Google Play Store for a simple user experience.
- </p>
-</div>
-
-</div><!-- col-6 -->
-
-</div><!-- margin wrapper -->
-
-
-
-
+<script>
+</script>
diff --git a/docs/html/samples/topic.jd b/docs/html/samples/topic.jd
new file mode 100644
index 0000000..cac9b10
--- /dev/null
+++ b/docs/html/samples/topic.jd
@@ -0,0 +1,26 @@
+page.title=Samples
+@jd:body
+
+
+<div id="samples">
+</div>
+
+
+
+<script>
+ $(document).ready(showSamples);
+
+ /** Display links and other information about samples that match the
+ group specified by the URL */
+ function showSamples() {
+ var group = getGroup();
+ $("#body-content h1").html(group);
+ $("#samples").html("<p>OK, here are some samples about <b>" + group + "</b>.</p>");
+ }
+
+ /** Return the group provided by the URL */
+ function getGroup() {
+ var hashParts = location.hash.split('t=');
+ return hashParts[1];
+ }
+</script>
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 4ea3752..0581435 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -5,43 +5,43 @@
page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
-sdk.linux32_bundle_download=adt-bundle-linux-x86-20130729.zip
-sdk.linux32_bundle_bytes=457716139
-sdk.linux32_bundle_checksum=b3686d10dc1cbceba1074404d4386283
+sdk.linux32_bundle_download=adt-bundle-linux-x86-20130911.zip
+sdk.linux32_bundle_bytes=474916528
+sdk.linux32_bundle_checksum=7eacc7124299ea99a8fa15c59123540f
-sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130729.zip
-sdk.linux64_bundle_bytes=458006784
-sdk.linux64_bundle_checksum=1fabcc3f772ba8b2fc194d6e0449da17
+sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130911.zip
+sdk.linux64_bundle_bytes=475207785
+sdk.linux64_bundle_checksum=daa5794a27be7c7fa708c3d28833b0d3
-sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130729.zip
-sdk.mac64_bundle_bytes=428792424
-sdk.mac64_bundle_checksum=6c42b9966abcfa8a75c0ee83d0d95882
+sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130911.zip
+sdk.mac64_bundle_bytes=448575446
+sdk.mac64_bundle_checksum=a1e0cbcc820ae734cfdf439c40811b4c
-sdk.win32_bundle_download=adt-bundle-windows-x86-20130729.zip
-sdk.win32_bundle_bytes=463931746
-sdk.win32_bundle_checksum=51faf4e5fdf9c5b4a176179a99ce3511
+sdk.win32_bundle_download=adt-bundle-windows-x86-20130911.zip
+sdk.win32_bundle_bytes=481794820
+sdk.win32_bundle_checksum=88a2f4f242aac44f4b1c53e6eccc8710
-sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130729.zip
-sdk.win64_bundle_bytes=464064756
-sdk.win64_bundle_checksum=e8f05c1fddb8e609e880de23113c7426
+sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130911.zip
+sdk.win64_bundle_bytes=481927327
+sdk.win64_bundle_checksum=e3fa9b7e38af9ed9ac0e99fce3c7026c
-sdk.linux_download=android-sdk_r22.0.5-linux.tgz
-sdk.linux_bytes=105641005
-sdk.linux_checksum=8201b10c21510f082c54f58a9bb082c8
+sdk.linux_download=android-sdk_r22.2-linux.tgz
+sdk.linux_bytes=100909403
+sdk.linux_checksum=2a3776839e823ba9acb7a87a3fe26e02
-sdk.mac_download=android-sdk_r22.0.5-macosx.zip
-sdk.mac_bytes=77225724
-sdk.mac_checksum=94f3cbe896c332b94ee0408ae610a4b8
+sdk.mac_download=android-sdk_r22.2-macosx.zip
+sdk.mac_bytes=74857114
+sdk.mac_checksum=9dfef6404e2f842c433073796aed8b7d
-sdk.win_download=android-sdk_r22.0.5-windows.zip
-sdk.win_bytes=113510621
-sdk.win_checksum=30695dffc41e0d7cf9ff948ab0c48920
+sdk.win_download=android-sdk_r22.2-windows.zip
+sdk.win_bytes=108790714
+sdk.win_checksum=1ac4c104378cd53049daa6c4458ec544
-sdk.win_installer=installer_r22.0.5-windows.exe
-sdk.win_installer_bytes=93505782
-sdk.win_installer_checksum=940849be19ac6151e3e35c8706c81d86
+sdk.win_installer=installer_r22.2-windows.exe
+sdk.win_installer_bytes=88788974
+sdk.win_installer_checksum=e5503fa059297d2b18475c086ac6e80c
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index bdc07d0..e038d20 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=22.0.5
-adt.zip.download=ADT-22.0.5.zip
-adt.zip.bytes=16839757
-adt.zip.checksum=1097fccf32063e3638a9d27aa0f295ca
+adt.zip.version=22.2.0
+adt.zip.download=ADT-22.2.0.zip
+adt.zip.bytes=14474195
+adt.zip.checksum=52892c9e3b1ad2d1e6edd50e48b2a127
@jd:body
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index e9c514e..151707a 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -57,6 +57,44 @@
<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 22.2</a> <em>(September 2013)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+<dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r22.2</a>.
+ If you haven't already installed SDK Tools r22.2 into your SDK, use the
+ Android SDK Manager to do so.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Updated build tools to allow use of RenderScript on older versions of Android
+ using new features in the
+ <a href="{@docRoot}tools/support-library/features.html#v8">Support Library</a>.</li>
+ <li>Reverted signing changes that sometimes trigger a signing verification problem on older
+ platforms.</li>
+ <li>Fixed problem with gradle export function for the Windows platform.</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 22.0.5</a> <em>(July 2013)</em>
</p>
@@ -78,7 +116,7 @@
<dt>General Notes:</dt>
<dd>
<ul>
- <li>Fixed Renderscript compilation issue for Windows platforms.</li>
+ <li>Fixed RenderScript compilation issue for Windows platforms.</li>
<li>Updated <a href="{@docRoot}tools/help/systrace.html">Systrace</a> report generation
in the Monitor and DDMS perspectives.</li>
</ul>
@@ -113,7 +151,7 @@
<dt>General Notes:</dt>
<dd>
<ul>
- <li>Fixed problem with compiling Renderscript code.</li>
+ <li>Fixed problem with compiling RenderScript code.</li>
<li>Improved Gradle export with better workflow and error reporting.</li>
<li>Improved Gradle multi-module export feature.</li>
<li>Updated build logic to force exporting of the classpath containers unless you are using
@@ -1005,7 +1043,7 @@
<dt>Bug fixes:</dt>
<dd>
<ul>
- <li>Fixed build issue when using Renderscript in projects that target API levels 11-13
+ <li>Fixed build issue when using RenderScript in projects that target API levels 11-13
(<a href="http://code.google.com/p/android/issues/detail?id=21006">Issue 21006</a>).</li>
<li>Fixed issue when creating projects from existing source code.</li>
<li>Fixed issues in the SDK Manager
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index 4aef8a0..e8c4717 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -30,6 +30,54 @@
<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 22.2</a> <em>(September 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 this version of SDK Tools is
+ designed for use with ADT 22.2 and later. If you haven't already, update your
+ <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 22.2.</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>Updated build tools to allow use of RenderScript on older versions of Android
+ using new features in the
+ <a href="{@docRoot}tools/support-library/features.html#v8">Support Library</a>.</li>
+ <li>Moved the Systrace tool to the {@code >sdk</platform-tools/} directory. </li>
+ <li>Modified <a href="{@docRoot}tools/help/gltracer.html">Tracer for OpenGL ES</a> to
+ support OpenGL ES 3.0.</li>
+ <li>Lint
+ <ul>
+ <li>Fixed problem with lint not detecting custom namespaces.
+ (<a href="http://b.android.com/55673">Issue 55673</a>)</li>
+ <li>Fixed problem with the XML report including invalid characters.
+ (<a href="http://b.android.com/56205">Issue 56205</a>)</li>
+ <li>Fixed command-line execution of lint to work in headless mode to support execution
+ by build servers. (<a href="http://b.android.com/55820">Issue 55820</a>)</li>
+ </ul>
+ </li>
+ <li>Improved support for path names with spaces in the Windows command-line tools.</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 22.0.5</a> <em>(July 2013)</em>
</p>
@@ -55,10 +103,10 @@
<dt>General Notes:</dt>
<dd>
<ul>
- <li>Fixed Renderscript compilation issue for Windows platforms with ant.</li>
+ <li>Fixed RenderScript compilation issue for Windows platforms with ant.</li>
<li>Updated <a href="{@docRoot}tools/help/systrace.html">Systrace</a> to work with the
Android 4.3 platform image.</li>
- <li>Fixed packaging of Renderscript compiler.</li>
+ <li>Fixed packaging of RenderScript compiler.</li>
<li>Build tools 18.0.0 is obsolete and 18.0.1 should be used instead.</li>
</ul>
</dd>
@@ -95,7 +143,7 @@
<dt>General Notes:</dt>
<dd>
<ul>
- <li>Fixed problem with compiling Renderscript code.</li>
+ <li>Fixed problem with compiling RenderScript code.</li>
</ul>
</dd>
</dl>
@@ -274,17 +322,17 @@
</ul>
</li>
- <li>Renderscript
+ <li>RenderScript
<ul>
<li>Added support for
<a href="{@docRoot}guide/topics/renderscript/compute.html#filterscript">Filterscript</a>
compilation.</li>
- <li>Added new project setting to control the Renderscript compilation target separately
+ <li>Added new project setting to control the RenderScript compilation target separately
from an Android project. Adding the following line to a {@code project.properties}
- file causes Renderscript code to be compiled for Android API Level 17, while the
+ file causes RenderScript code to be compiled for Android API Level 17, while the
containing application can target a different (lower) API level:
<pre>renderscript.target = 17</pre>
- Previously, the Renderscript compilation target was tied to the
+ Previously, the RenderScript compilation target was tied to the
{@code android:minSdkVersion} setting in the manifest.
(<a href="http://code.google.com/p/android/issues/detail?id=40487">Issue 40487</a>)
</li>
@@ -483,7 +531,7 @@
<li>Improved resize algorithm for better rendering on scaled emulator windows.</li>
<li>Fixed a bug in the {@code lint} check for unprotected broadcast receivers to ignore
unprotected receivers for default Android actions.</li>
- <li>Fixed build issue for projects using Renderscript.</li>
+ <li>Fixed build issue for projects using RenderScript.</li>
<li>Fixed memory leak in the emulator.</li>
</ul>
</dd>
@@ -823,7 +871,7 @@
<li>Fixed emulator crash on Linux due to improper webcam detection
(<a href="http://code.google.com/p/android/issues/detail?id=20952">Issue 20952</a>).</li>
<li>Fixed emulator issue when using the <code>-wipe-data</code> argument.</li>
- <li>Fixed build issue when using Renderscript in projects that target API levels 11-13
+ <li>Fixed build issue when using RenderScript in projects that target API levels 11-13
(<a href="http://code.google.com/p/android/issues/detail?id=21006">Issue 21006</a>).</li>
<li>Fixed issue when creating an AVD using the GoogleTV addon
(<a href="http://code.google.com/p/android/issues/detail?id=20963">Issue 20963</a>).</li>
diff --git a/docs/html/tools/support-library/features.jd b/docs/html/tools/support-library/features.jd
index 8d25d96..65148bf 100644
--- a/docs/html/tools/support-library/features.jd
+++ b/docs/html/tools/support-library/features.jd
@@ -15,6 +15,7 @@
<li><a href="#v7-mediarouter">v7 mediarouter library</a></li>
</ol>
</li>
+ <li><a href="#v8">v8 Support Library</a></li>
<li><a href="#v13">v13 Support Library</a></li>
</ol>
@@ -252,7 +253,7 @@
where "18.0.0" is the minimum revision at which the library is available. For example:</p>
<pre>
-com.android.support:support-v7-mediarouter:18.0.0
+com.android.support:mediarouter-v7:18.0.+
</pre>
<p class="caution">The v7 mediarouter library APIs introduced in Support Library
@@ -262,6 +263,24 @@
developer preview</a>. </p>
+<h2 id="v8">v8 Support Library</h2>
+
+<p>This library is designed to be used with Android (API level 8) and higher. It adds support for
+ the <a href="{@docRoot}guide/topics/renderscript/compute.html">RenderScript</a> computation
+ framework. These APIs are included in the {@link android.support.v8.renderscript} package. You
+ should be aware that the steps for including these APIs in your application is <em>very
+ different</em> from other support library APIs. For more information about using these APIs
+ in your application, see the
+ <a href="{@docRoot}guide/topics/renderscript/compute.html#access-rs-apis">RenderScript</a>
+ developer guide.</p>
+
+<p class="note">
+ <strong>Note:</strong> Use of RenderScript with the support library is supported with the Android
+ Eclipse plugin and Ant build tools. It is <em>not currently</em> supported with Android Studio or
+ Gradle-based builds.
+</p>
+
+
<h2 id="v13">v13 Support Library</h2>
<p>This library is designed to be used for Android 3.2 (API level 13) and higher. It adds support
diff --git a/docs/html/tools/support-library/index.jd b/docs/html/tools/support-library/index.jd
index 06c7a3f..4ee8c12 100644
--- a/docs/html/tools/support-library/index.jd
+++ b/docs/html/tools/support-library/index.jd
@@ -58,6 +58,7 @@
<p>This section provides details about the Support Library package releases.</p>
+
<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=""
diff --git a/docs/html/training/location/activity-recognition.jd b/docs/html/training/location/activity-recognition.jd
index 47ba5f8..d50064b 100644
--- a/docs/html/training/location/activity-recognition.jd
+++ b/docs/html/training/location/activity-recognition.jd
@@ -31,13 +31,13 @@
</div>
<p>
- This lesson shows you how to request activity recognition updates from Location Services.
Activity recognition tries to detect the user's current physical activity, such as walking,
driving, or standing still. Requests for updates go through an activity recognition client,
which, while different from the location client used by location or geofencing, follows a
similar pattern. Based on the update interval you choose, Location Services sends out
activity information containing one or more possible activities and the confidence level for
- each one.
+ each one. This lesson shows you how to request activity recognition updates from Location
+ Services.
</p>
<h2 id="RequestUpdates">Request Activity Recognition Updates</h2>
<p>
diff --git a/docs/html/training/location/index.jd b/docs/html/training/location/index.jd
index 5ebbb84..e03eac6 100644
--- a/docs/html/training/location/index.jd
+++ b/docs/html/training/location/index.jd
@@ -85,4 +85,12 @@
Learn how to recognize the user's current activity, such as walking, bicycling,
or driving a car, and how to use this information to modify your app's location strategy.
</dd>
+ <dt>
+ <b><a href="location-testing.html">Testing Using Mock Locations</a></b>
+ </dt>
+ <dd>
+ Learn how to test a location-aware app by injecting mock locations into Location
+ Services. In mock mode, Location Services sends out mock locations that you inject instead
+ of sensor-based locations.
+ </dd>
</dl>
diff --git a/docs/html/training/location/location-testing.jd b/docs/html/training/location/location-testing.jd
new file mode 100644
index 0000000..e36bac1
--- /dev/null
+++ b/docs/html/training/location/location-testing.jd
@@ -0,0 +1,371 @@
+page.title=Testing Using Mock Locations
+
+trainingnavtop=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#TurnOnMockMode">Turn On Mock Mode</a></li>
+ <li><a href="#SendMockLocations">Send Mock Locations</a></li>
+ <li><a href="RunProvider">Run the Mock Location Provider App</a></li>
+ <li><a href="#TestingTips">Testing Tips</a>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="receive-location-updates.html">Receiving Location Updates</a></li>
+ <li><a href="geofencing.html">Creating and Monitoring Geofences</a></li>
+ <li><a href="{@docRoot}guide/components/services.html">Services</a></li>
+ <li><a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a>
+</ul>
+
+<h2>Example Test App</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/LocationProvider.zip" class="button"
+ >Download the sample</a>
+ <p class="filename">LocationProvider.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+ To test a location-aware app that uses Location Services, you don't need to move your device
+ from place to place to generate location data. Instead, you can put Location Services into mock
+ mode. In this mode, you can send mock {@link android.location.Location} objects to
+ Location Services, which then sends them to location clients. In mock mode, Location Services
+ also uses mock {@link android.location.Location} objects to trigger geofences.
+</p>
+<p>
+ Using mock locations has several advantages:
+</p>
+<ul>
+ <li>
+ Mock locations allow you to create specific mock data, instead of trying to approximate
+ data by moving an actual device.
+ </li>
+ <li>
+ Since mock locations come from Location Services, they test every part of your
+ location-handling code. In addition, since you can send the mock data from outside your
+ production app, you don't have to disable or remove test code before you publish.
+ </li>
+ <li>
+ Since you don't have to generate test locations by moving a device, you can test an app
+ using the emulator.
+ </li>
+</ul>
+<p>
+ The best way to use mock locations is to send them from a separate mock location provider app.
+ This lesson includes a provider app that you can download and use to test your own software.
+ Modify the provider app as necessary to suit your own needs. Some ideas for providing test data
+ to the app are listed in the section <a href="TestData">Managing test data</a>.
+</p>
+<p>
+ The remainder of this lesson shows you how to turn on mock mode and use a location client to
+ send mock locations to Location Services.
+</p>
+<p class="note">
+ <strong>Note:</strong> Mock locations have no effect on the activity recognition algorithm used
+ by Location Services. To learn more about activity recognition, see the lesson
+ <a href="activity-recognition.html">Recognizing the User's Current Activity</a>.
+</p>
+<!--
+ Create a Test App
+ -->
+<h2 id="TurnOnMockMode">Turn On Mock Mode</h2>
+<p>
+ To send mock locations to Location Services in mock mode, a test app must request the permission
+ {@link android.Manifest.permission#ACCESS_MOCK_LOCATION}. In addition, you must enable mock
+ locations on the test device using the option <b>Enable mock locations</b>. To learn how to
+ enable mock locations on the device, see
+ <a href="{@docRoot}tools/device.html#setting-up">Setting up a Device for Development</a>.
+</p>
+<p>
+ To turn on mock mode in Location Services, start by connecting a location client to Location
+ Services, as described in the lesson
+ <a href="retrieve-current.html">Retrieving the Current Location</a>.
+ Next, call the method
+<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockMode(boolean)">LocationClient.setMockMode(true)</a></code>.
+ Once you call this method, Location Services turns off its internal location providers and only
+ sends out the mock locations you provide it. The following snippet shows you how to call
+<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockMode(boolean)">LocationClient.setMockMode(true)</a></code>:
+</p>
+<pre>
+ // Define a LocationClient object
+ public LocationClient mLocationClient;
+ ...
+ // Connect to Location Services
+ mLocationClient.connect();
+ ...
+ // When the location client is connected, set mock mode
+ mLocationClinet.setMockMode(true);
+</pre>
+<p>
+ Once you have connected the location client to Location Services, you must keep it connected
+ until you finish sending out mock locations. Once you call
+<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#disconnect()">LocationClient.disconnect()</a></code>,
+ Location Services returns to using its internal location providers. To turn off mock mode while
+ the location client is connected, call
+<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockMode(boolean)">LocationClient.setMockMode(false)</a></code>.
+</p>
+<h2 id="SendMockLocations">Send Mock Locations</h2>
+<p>
+ Once you have set mock mode, you can create mock {@link android.location.Location} objects and
+ send them to Location Services. In turn, Location Services sends these mock
+ {@link android.location.Location} objects to connected location clients. Location Services also
+ uses the mock {@link android.location.Location} objects to control geofence triggering.
+</p>
+<p>
+ To create a new mock {@link android.location.Location}, create a new
+ {@link android.location.Location} object using your test data. Always set the provider
+ value to {@code flp}, which is the code that Location Services puts into the
+ {@link android.location.Location} objects it sends out. The following snippet shows you how
+ to create a new mock {@link android.location.Location}:
+</p>
+<pre>
+ private static final String PROVIDER = "flp";
+ private static final double LAT = 37.377166;
+ private static final double LNG = -122.086966;
+ private static final float ACCURACY = 3.0f;
+ ...
+ /*
+ * From input arguments, create a single Location with provider set to
+ * "flp"
+ */
+ public Location createLocation(double lat, double lng, float accuracy) {
+ // Create a new Location
+ Location newLocation = new Location(PROVIDER);
+ newLocation.setLatitude(lat);
+ newLocation.setLongitude(lng);
+ newLocation.setAccuracy(accuracy);
+ return newLocation;
+ }
+ ...
+ // Example of creating a new Location from test data
+ Location testLocation = createLocation(LAT, LNG, ACCURACY);
+</pre>
+<p>
+ In mock mode, to send a mock location to Location Services call the method
+<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockLocation(android.location.Location)">LocationClient.setMockLocation()</a></code>.
+ For example:
+</p>
+<pre>
+ mLocationClient.setMockLocation(testLocation);
+</pre>
+<p>
+ Location Services sets this mock location as the current location, and this location is sent
+ out as the next location update. If this new mock location moves across a geofence boundary,
+ Location Services triggers the geofence.
+</p>
+<!--
+ Run the Mock Location Provider
+ -->
+<h2 id="RunProvider">Run the Mock Location Provider App</h2>
+<p>
+ This section contains a brief overview of the mock location provider sample app
+ (available for download above) and gives you directions for testing an app using the sample app.
+</p>
+<h3>Overview</h3>
+<p>
+ The mock location provider app included with this lesson sends mock
+ {@link android.location.Location} objects to Location Services from a background thread running
+ in a started {@link android.app.Service}. By using a started service, the provider app is able
+ to keep running even if the app's main {@link android.app.Activity} is destroyed because of
+ a configuration change or other system event. By using a background thread, the service is able
+ to perform a long-running test without blocking the UI thread.
+</p>
+<p>
+ The {@link android.app.Activity} that starts when you run the provider app allows you to
+ send test parameters to the {@link android.app.Service} and control the type of test you want.
+ You have the following options:
+</p>
+<dl>
+ <dt>
+ Pause before test
+ </dt>
+ <dd>
+ The number of seconds to wait before the provider app starts sending test data to Location
+ Services. This interval allows you to switch from the provider app to the app under test
+ before the testing actually starts.
+ </dd>
+ <dt>
+ Send interval
+ </dt>
+ <dd>
+ The number of seconds that the provider app waits before it sends another mock location to
+ Location Services. See the section <a href="#TestingTips">Testing Tips</a> to learn more
+ about setting the send interval.
+ </dd>
+ <dt>
+ Run once
+ </dt>
+ <dd>
+ Switch from normal mode to mock mode, run through the test data once, switch back to
+ normal mode, and then kill the {@link android.app.Service}.
+ </dd>
+ <dt>
+ Run continuously
+ </dt>
+ <dd>
+ Switch from normal mode to mock mode, then run through the test data indefinitely. The
+ background thread and the started {@link android.app.Service} continue to run, even if the
+ main {@link android.app.Activity} is destroyed.
+ </dd>
+ <dt>
+ Stop test
+ </dt>
+ <dd>
+ If a continuous test is in progress, stop it; otherwise, return a warning message. The
+ started {@link android.app.Service} switches from mock mode to normal mode and then
+ stops itself. This also stops the background thread.
+ </dd>
+</dl>
+<p>
+ Besides the options, the provider app has two status displays:
+</p>
+<dl>
+ <dt>
+ App status
+ </dt>
+ <dd>
+ Displays messages related to the lifecycle of the provider app.
+ </dd>
+ <dt>
+ Connection status
+ </dt>
+ <dd>
+ Displays messages related to the state of the location client connection.
+ </dd>
+</dl>
+<p>
+ While the started {@link android.app.Service} is running, it also posts notifications with the
+ testing status. These notifications allow you to see status updates even if the app is not in
+ the foreground. When you click on a notification, the main {@link android.app.Activity} of the
+ provider app returns to the foreground.
+</p>
+<h3>Test using the mock location provider app</h3>
+<p>
+ To test mock location data coming from the mock location provider app:
+</p>
+<ol>
+ <li>
+ Install the mock location provider app on a device that has Google Play services installed.
+ Location Services is part of Google Play services.
+ </li>
+ <li>
+ On the device, enable mock locations. To learn how to do this, see the topic
+ <a href="{@docRoot}tools/device.html#setting-up">Setting up a Device for Development</a>.
+ </li>
+ <li>
+ Start the provider app from the Launcher, then choose the options you want from the main
+ screen.
+ </li>
+ <li>
+ Unless you've removed the pause interval feature, the mock location provider app
+ pauses for a few seconds, and then starts sending mock location data to Location
+ Services.
+ </li>
+ <li>
+ Run the app you want to test. While the mock location provider app is running, the app
+ you're testing receives mock locations instead of real locations.
+ </li>
+ <li>
+ If the provider app is in the midst of a continuous test, you can switch back to real
+ locations by clicking <b>Stop test</b>. This forces the started {@link android.app.Service}
+ to turn off mock mode and then stop itself. When the service stops itself, the background
+ thread is also destroyed.
+ </li>
+
+</ol>
+<h2 id="TestingTips">Testing Tips</h2>
+<p>
+ The following sections contain tips for creating mock location data and using the data with a
+ mock location provider app.
+</p>
+<h3>Choosing a send interval</h3>
+<p>
+ Each location provider that contributes to the fused location sent out by Location Services has
+ its own minimum update cycle. For example, the GPS provider can't send a new location more often
+ than once per second, and the Wi-Fi provider can't send a new location more often than once
+ every five seconds. These cycle times are handled automatically for real locations, but you
+ should account for them when you send mock locations. For example, you shouldn't send a new mock
+ location more than once per second. If you're testing indoor locations, which rely heavily on
+ the Wi-Fi provider, then you should consider using a send interval of five seconds.
+</p>
+<h3>Simulating speed</h3>
+<p>
+ To simulate the speed of an actual device, shorten or lengthen the distance between two
+ successive locations. For example, changing the location by 88 feet every second simulates
+ car travel, because this change works out to 60 miles an hour. In comparison, changing the
+ location by 1.5 feet every second simulates brisk walking, because this change works out to
+ 3 miles per hour.
+</p>
+<h3>Calculating location data</h3>
+<p>
+ By searching the web, you can find a variety of small programs that calculate a new set of
+ latitude and longitude coordinates from a starting location and a distance, as well as
+ references to formulas for calculating the distance between two points based on their latitude
+ and longitude. In addition, the {@link android.location.Location} class offers two methods for
+ calculating the distance between points:
+</p>
+<dl>
+ <dt>
+ {@link android.location.Location#distanceBetween distanceBetween()}
+ </dt>
+ <dd>
+ A static method that calculates the distance between two points specified by latitude and
+ longitude.
+ </dd>
+ <dt>
+ {@link android.location.Location#distanceTo distanceTo()}
+ </dt>
+ <dd>
+ For a given {@link android.location.Location}, returns the distance to another
+ {@link android.location.Location}.
+ </dd>
+</dl>
+<h3>Geofence testing</h3>
+<p>
+ When you test an app that uses geofence detection, use test data that reflects different modes
+ of travel, including walking, cycling, driving, and traveling by train. For a slow mode of
+ travel, make small changes in position between points. Conversely, for a fast mode of travel,
+ make a large change in position between points.
+</p>
+<h3 id="TestData">Managing test data</h3>
+<p>
+ The mock location provider app included with this lesson contains test latitude, longitude,
+ and accuracy values in the form of constants. You may want to consider other ways of organizing
+ data as well:
+</p>
+<dl>
+ <dt>
+ XML
+ </dt>
+ <dd>
+ Store location data in XML files that are including in the provider app. By separating the
+ data from the code, you facilitate changes to the data.
+ </dd>
+ <dt>
+ Server download
+ </dt>
+ <dd>
+ Store location data on a server and then have the provider app download it. Since the data
+ is completely separate from the app, you can change the data without having to rebuild the
+ app. You can also change the data on the server and have the changes reflected immediately
+ in the mock locations you're testing.
+ </dd>
+ <dt>
+ Recorded data
+ </dt>
+ <dd>
+ Instead of making up test data, write a utility app that records location data as you move
+ the device. Use the recorded data as your test data, or use the data to guide you in
+ developing test data. For example, record locations as you walk with a device, and then
+ create mock locations that have an appropriate change in latitude and longitude over
+ time.
+ </dd>
+</dl>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index ebf553cc..0c4f9df 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -631,6 +631,10 @@
Recognizing the User's Current Activity
</a>
</li>
+ <li><a href="<?cs var:toroot ?>training/location/location-testing.html">
+ Testing Using Mock Locations
+ </a>
+ </li>
</ul>
</li>
</ul>
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index e3adc59..23606a1 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -565,24 +565,10 @@
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap");
try {
- boolean decodeGenericStream = true;
if (is instanceof AssetManager.AssetInputStream) {
final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
bm = nativeDecodeAsset(asset, outPadding, opts);
- // Do not follow the normal case.
- decodeGenericStream = false;
- } else if (is instanceof FileInputStream) {
- try {
- FileDescriptor fd = ((FileInputStream) is).getFD();
- // decodeFileDescriptor will take care of throwing the IAE and
- // calling setDensityFromOptions.
- return decodeFileDescriptor(fd, outPadding, opts);
- } catch (IOException e) {
- // Fall through to nativeDecodeStream.
- }
- }
-
- if (decodeGenericStream) {
+ } else {
byte [] tempStorage = null;
if (opts != null) tempStorage = opts.inTempStorage;
if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index e8d6f16..b910a24 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -21,6 +21,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.view.Surface;
/**
* Captures frames from an image stream as an OpenGL ES texture.
@@ -80,8 +81,12 @@
}
/**
- * Exception thrown when a surface couldn't be created or resized
+ * Exception thrown when a SurfaceTexture couldn't be created or resized.
+ *
+ * @deprecated No longer thrown. {@link Surface.OutOfResourcesException} is used instead.
*/
+ @SuppressWarnings("serial")
+ @Deprecated
public static class OutOfResourcesException extends Exception {
public OutOfResourcesException() {
}
@@ -94,6 +99,8 @@
* Construct a new SurfaceTexture to stream images to a given OpenGL texture.
*
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
+ *
+ * @throws OutOfResourcesException If the SurfaceTexture cannot be created.
*/
public SurfaceTexture(int texName) {
init(texName, false);
@@ -113,6 +120,8 @@
*
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
* @param singleBufferMode whether the SurfaceTexture will be in single buffered mode.
+ *
+ * @throws throws OutOfResourcesException If the SurfaceTexture cannot be created.
*/
public SurfaceTexture(int texName, boolean singleBufferMode) {
init(texName, singleBufferMode);
@@ -140,9 +149,9 @@
* android.view.Surface#lockCanvas} is called. For OpenGL ES, the EGLSurface should be
* destroyed (via eglDestroySurface), made not-current (via eglMakeCurrent), and then recreated
* (via eglCreateWindowSurface) to ensure that the new default size has taken effect.
- *
+ *
* The width and height parameters must be no greater than the minimum of
- * GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see
+ * GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see
* {@link javax.microedition.khronos.opengles.GL10#glGetIntegerv glGetIntegerv}).
* An error due to invalid dimensions might not be reported until
* updateTexImage() is called.
@@ -267,6 +276,7 @@
nativeRelease();
}
+ @Override
protected void finalize() throws Throwable {
try {
nativeFinalize();
@@ -305,7 +315,7 @@
}
}
- private void init(int texName, boolean singleBufferMode) {
+ private void init(int texName, boolean singleBufferMode) throws Surface.OutOfResourcesException {
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(looper);
@@ -317,7 +327,8 @@
nativeInit(texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
}
- private native void nativeInit(int texName, boolean singleBufferMode, Object weakSelf);
+ private native void nativeInit(int texName, boolean singleBufferMode, Object weakSelf)
+ throws Surface.OutOfResourcesException;
private native void nativeFinalize();
private native void nativeGetTransformMatrix(float[] mtx);
private native long nativeGetTimestamp();
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index ca72c25..dca934f 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -269,9 +269,12 @@
mType = t;
mUsage = usage;
- mSize = mType.getCount() * mType.getElement().getBytesSize();
if (t != null) {
+ // TODO: A3D doesn't have Type info during creation, so we can't
+ // calculate the size ahead of time. We can possibly add a method
+ // to update the size in the future if it seems reasonable.
+ mSize = mType.getCount() * mType.getElement().getBytesSize();
updateCacheInfo(t);
}
try {
diff --git a/include/android_runtime/Log.h b/include/android_runtime/Log.h
new file mode 100644
index 0000000..aa6d202
--- /dev/null
+++ b/include/android_runtime/Log.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _RUNTIME_ANDROID_LOG_H
+#define _RUNTIME_ANDROID_LOG_H
+
+// This relies on JNIHelp.h
+
+/* Logging macros.
+ *
+ * Logs an exception. If the exception is omitted or NULL, logs the current exception
+ * from the JNI environment, if any.
+ */
+#define LOG_EX(env, priority, tag, ...) \
+ jniLogException(env, ANDROID_##priority, tag, ##__VA_ARGS__)
+#define LOGV_EX(env, ...) LOG_EX(env, LOG_VERBOSE, LOG_TAG, ##__VA_ARGS__)
+#define LOGD_EX(env, ...) LOG_EX(env, LOG_DEBUG, LOG_TAG, ##__VA_ARGS__)
+#define LOGI_EX(env, ...) LOG_EX(env, LOG_INFO, LOG_TAG, ##__VA_ARGS__)
+#define LOGW_EX(env, ...) LOG_EX(env, LOG_WARN, LOG_TAG, ##__VA_ARGS__)
+#define LOGE_EX(env, ...) LOG_EX(env, LOG_ERROR, LOG_TAG, ##__VA_ARGS__)
+
+#endif // _RUNTIME_ANDROID_LOG_H
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
index b84f3b0..ec5f95c 100644
--- a/libs/androidfw/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -46,31 +46,41 @@
/*
* Zip file constants.
*/
-#define kEOCDSignature 0x06054b50
-#define kEOCDLen 22
-#define kEOCDNumEntries 8 // offset to #of entries in file
-#define kEOCDSize 12 // size of the central directory
-#define kEOCDFileOffset 16 // offset to central directory
+#define kEOCDSignature 0x06054b50
+#define kEOCDLen 22
+#define kEOCDDiskNumber 4 // number of the current disk
+#define kEOCDDiskNumberForCD 6 // disk number with the Central Directory
+#define kEOCDNumEntries 8 // offset to #of entries in file
+#define kEOCDTotalNumEntries 10 // offset to total #of entries in spanned archives
+#define kEOCDSize 12 // size of the central directory
+#define kEOCDFileOffset 16 // offset to central directory
+#define kEOCDCommentSize 20 // offset to the length of the file comment
-#define kMaxCommentLen 65535 // longest possible in ushort
-#define kMaxEOCDSearch (kMaxCommentLen + kEOCDLen)
+#define kMaxCommentLen 65535 // longest possible in ushort
+#define kMaxEOCDSearch (kMaxCommentLen + kEOCDLen)
-#define kLFHSignature 0x04034b50
-#define kLFHLen 30 // excluding variable-len fields
-#define kLFHNameLen 26 // offset to filename length
-#define kLFHExtraLen 28 // offset to extra length
+#define kLFHSignature 0x04034b50
+#define kLFHLen 30 // excluding variable-len fields
+#define kLFHGPBFlags 6 // offset to GPB flags
+#define kLFHNameLen 26 // offset to filename length
+#define kLFHExtraLen 28 // offset to extra length
-#define kCDESignature 0x02014b50
-#define kCDELen 46 // excluding variable-len fields
-#define kCDEMethod 10 // offset to compression method
-#define kCDEModWhen 12 // offset to modification timestamp
-#define kCDECRC 16 // offset to entry CRC
-#define kCDECompLen 20 // offset to compressed length
-#define kCDEUncompLen 24 // offset to uncompressed length
-#define kCDENameLen 28 // offset to filename length
-#define kCDEExtraLen 30 // offset to extra length
-#define kCDECommentLen 32 // offset to comment length
-#define kCDELocalOffset 42 // offset to local hdr
+#define kCDESignature 0x02014b50
+#define kCDELen 46 // excluding variable-len fields
+#define kCDEGPBFlags 8 // offset to GPB flags
+#define kCDEMethod 10 // offset to compression method
+#define kCDEModWhen 12 // offset to modification timestamp
+#define kCDECRC 16 // offset to entry CRC
+#define kCDECompLen 20 // offset to compressed length
+#define kCDEUncompLen 24 // offset to uncompressed length
+#define kCDENameLen 28 // offset to filename length
+#define kCDEExtraLen 30 // offset to extra length
+#define kCDECommentLen 32 // offset to comment length
+#define kCDELocalOffset 42 // offset to local hdr
+
+/* General Purpose Bit Flag */
+#define kGPFEncryptedFlag (1 << 0)
+#define kGPFUnsupportedMask (kGPFEncryptedFlag)
/*
* The values we return for ZipEntryRO use 0 as an invalid value, so we
@@ -170,6 +180,11 @@
if (readAmount > (ssize_t) mFileLength)
readAmount = mFileLength;
+ if (readAmount < kEOCDSize) {
+ ALOGW("File too short to be a zip file");
+ return false;
+ }
+
unsigned char* scanBuf = (unsigned char*) malloc(readAmount);
if (scanBuf == NULL) {
ALOGW("couldn't allocate scanBuf: %s", strerror(errno));
@@ -193,17 +208,11 @@
return false;
}
- {
- unsigned int header = get4LE(scanBuf);
- if (header == kEOCDSignature) {
- ALOGI("Found Zip archive, but it looks empty\n");
- free(scanBuf);
- return false;
- } else if (header != kLFHSignature) {
- ALOGV("Not a Zip archive (found 0x%08x)\n", header);
- free(scanBuf);
- return false;
- }
+ unsigned int header = get4LE(scanBuf);
+ if (header != kLFHSignature) {
+ ALOGV("Not a Zip archive (found 0x%08x)\n", header);
+ free(scanBuf);
+ return false;
}
/*
@@ -261,24 +270,38 @@
* Grab the CD offset and size, and the number of entries in the
* archive. After that, we can release our EOCD hunt buffer.
*/
+ unsigned int diskNumber = get2LE(eocdPtr + kEOCDDiskNumber);
+ unsigned int diskWithCentralDir = get2LE(eocdPtr + kEOCDDiskNumberForCD);
unsigned int numEntries = get2LE(eocdPtr + kEOCDNumEntries);
- unsigned int dirSize = get4LE(eocdPtr + kEOCDSize);
- unsigned int dirOffset = get4LE(eocdPtr + kEOCDFileOffset);
+ unsigned int totalNumEntries = get2LE(eocdPtr + kEOCDTotalNumEntries);
+ unsigned int centralDirSize = get4LE(eocdPtr + kEOCDSize);
+ unsigned int centralDirOffset = get4LE(eocdPtr + kEOCDFileOffset);
+ unsigned int commentSize = get2LE(eocdPtr + kEOCDCommentSize);
free(scanBuf);
// Verify that they look reasonable.
- if ((long long) dirOffset + (long long) dirSize > (long long) eocdOffset) {
+ if ((long long) centralDirOffset + (long long) centralDirSize > (long long) eocdOffset) {
ALOGW("bad offsets (dir %ld, size %u, eocd %ld)\n",
- (long) dirOffset, dirSize, (long) eocdOffset);
+ (long) centralDirOffset, centralDirSize, (long) eocdOffset);
return false;
}
if (numEntries == 0) {
ALOGW("empty archive?\n");
return false;
+ } else if (numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDir != 0) {
+ ALOGW("spanned archives not supported");
+ return false;
+ }
+
+ // Check to see if comment is a sane size
+ if ((commentSize > (mFileLength - kEOCDLen))
+ || (eocdOffset > (mFileLength - kEOCDLen) - commentSize)) {
+ ALOGW("comment size runs off end of file");
+ return false;
}
ALOGV("+++ numEntries=%d dirSize=%d dirOffset=%d\n",
- numEntries, dirSize, dirOffset);
+ numEntries, centralDirSize, centralDirOffset);
mDirectoryMap = new FileMap();
if (mDirectoryMap == NULL) {
@@ -286,14 +309,14 @@
return false;
}
- if (!mDirectoryMap->create(mFileName, mFd, dirOffset, dirSize, true)) {
+ if (!mDirectoryMap->create(mFileName, mFd, centralDirOffset, centralDirSize, true)) {
ALOGW("Unable to map '%s' (" ZD " to " ZD "): %s\n", mFileName,
- (ZD_TYPE) dirOffset, (ZD_TYPE) (dirOffset + dirSize), strerror(errno));
+ (ZD_TYPE) centralDirOffset, (ZD_TYPE) (centralDirOffset + centralDirSize), strerror(errno));
return false;
}
mNumEntries = numEntries;
- mDirectoryOffset = dirOffset;
+ mDirectoryOffset = centralDirOffset;
return true;
}
@@ -352,17 +375,30 @@
goto bail;
}
- unsigned int fileNameLen, extraLen, commentLen, hash;
+ unsigned int gpbf = get2LE(ptr + kCDEGPBFlags);
+ if ((gpbf & kGPFUnsupportedMask) != 0) {
+ ALOGW("Invalid General Purpose Bit Flag: %d", gpbf);
+ goto bail;
+ }
- fileNameLen = get2LE(ptr + kCDENameLen);
- extraLen = get2LE(ptr + kCDEExtraLen);
- commentLen = get2LE(ptr + kCDECommentLen);
+ unsigned int nameLen = get2LE(ptr + kCDENameLen);
+ unsigned int extraLen = get2LE(ptr + kCDEExtraLen);
+ unsigned int commentLen = get2LE(ptr + kCDECommentLen);
+
+ const char *name = (const char *) ptr + kCDELen;
+
+ /* Check name for NULL characters */
+ if (memchr(name, 0, nameLen) != NULL) {
+ ALOGW("Filename contains NUL byte");
+ goto bail;
+ }
/* add the CDE filename to the hash table */
- hash = computeHash((const char*)ptr + kCDELen, fileNameLen);
- addToHash((const char*)ptr + kCDELen, fileNameLen, hash);
+ unsigned int hash = computeHash(name, nameLen);
+ addToHash(name, nameLen, hash);
- ptr += kCDELen + fileNameLen + extraLen + commentLen;
+ /* We don't care about the comment or extra data. */
+ ptr += kCDELen + nameLen + extraLen + commentLen;
if ((size_t)(ptr - cdPtr) > cdLength) {
ALOGW("bad CD advance (%d vs " ZD ") at entry %d\n",
(int) (ptr - cdPtr), (ZD_TYPE) cdLength, i);
@@ -475,8 +511,10 @@
bool ret = false;
const int ent = entryToIndex(entry);
- if (ent < 0)
+ if (ent < 0) {
+ ALOGW("cannot find entry");
return false;
+ }
HashEntry hashEntry = mHashTable[ent];
@@ -585,6 +623,12 @@
}
#endif /* HAVE_PREAD */
+ unsigned int gpbf = get2LE(lfhBuf + kLFHGPBFlags);
+ if ((gpbf & kGPFUnsupportedMask) != 0) {
+ ALOGW("Invalid General Purpose Bit Flag: %d", gpbf);
+ return false;
+ }
+
off64_t dataOffset = localHdrOffset + kLFHLen
+ get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen);
if (dataOffset >= cdOffset) {
@@ -593,14 +637,15 @@
}
/* check lengths */
- if ((off64_t)(dataOffset + compLen) > cdOffset) {
+ if ((dataOffset >= cdOffset) || (compLen > (cdOffset - dataOffset))) {
ALOGW("bad compressed length in zip (%ld + " ZD " > %ld)\n",
(long) dataOffset, (ZD_TYPE) compLen, (long) cdOffset);
return false;
}
if (method == kCompressStored &&
- (off64_t)(dataOffset + uncompLen) > cdOffset)
+ ((dataOffset >= cdOffset) ||
+ (uncompLen > (cdOffset - dataOffset))))
{
ALOGE("ERROR: bad uncompressed length in zip (%ld + " ZD " > %ld)\n",
(long) dataOffset, (ZD_TYPE) uncompLen, (long) cdOffset);
@@ -645,14 +690,24 @@
*/
FileMap* newMap;
+ int method;
+ size_t uncompLen;
size_t compLen;
off64_t offset;
- if (!getEntryInfo(entry, NULL, NULL, &compLen, &offset, NULL, NULL))
+ if (!getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL)) {
return NULL;
+ }
+
+ size_t actualLen;
+ if (method == kCompressStored) {
+ actualLen = uncompLen;
+ } else {
+ actualLen = compLen;
+ }
newMap = new FileMap();
- if (!newMap->create(mFileName, mFd, offset, compLen, true)) {
+ if (!newMap->create(mFileName, mFd, offset, actualLen, true)) {
newMap->release();
return NULL;
}
@@ -671,17 +726,21 @@
const size_t kSequentialMin = 32768;
bool result = false;
int ent = entryToIndex(entry);
- if (ent < 0)
- return -1;
+ if (ent < 0) {
+ return false;
+ }
int method;
size_t uncompLen, compLen;
off64_t offset;
const unsigned char* ptr;
+ FileMap *file;
- getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
+ if (!getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL)) {
+ goto bail;
+ }
- FileMap* file = createEntryFileMap(entry);
+ file = createEntryFileMap(entry);
if (file == NULL) {
goto bail;
}
@@ -731,17 +790,21 @@
{
bool result = false;
int ent = entryToIndex(entry);
- if (ent < 0)
- return -1;
+ if (ent < 0) {
+ return false;
+ }
int method;
size_t uncompLen, compLen;
off64_t offset;
const unsigned char* ptr;
+ FileMap *file;
- getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
+ if (!getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL)) {
+ goto bail;
+ }
- FileMap* file = createEntryFileMap(entry);
+ file = createEntryFileMap(entry);
if (file == NULL) {
goto bail;
}
@@ -761,8 +824,9 @@
ALOGI("+++ successful write\n");
}
} else {
- if (!inflateBuffer(fd, ptr, uncompLen, compLen))
+ if (!inflateBuffer(fd, ptr, uncompLen, compLen)) {
goto unmap;
+ }
}
result = true;
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 7ce15c5..c0b77c7 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -66,23 +66,23 @@
virtual ~DrawBatch() { mOps.clear(); }
- virtual void add(DrawOp* op, bool opaqueOverBounds) {
+ virtual void add(DrawOp* op, const DeferredDisplayState* state, bool opaqueOverBounds) {
// NOTE: ignore empty bounds special case, since we don't merge across those ops
- mBounds.unionWith(op->state.mBounds);
+ mBounds.unionWith(state->mBounds);
mAllOpsOpaque &= opaqueOverBounds;
- mOps.add(op);
+ mOps.add(OpStatePair(op, state));
}
- bool intersects(Rect& rect) {
+ bool intersects(const Rect& rect) {
if (!rect.intersects(mBounds)) return false;
for (unsigned int i = 0; i < mOps.size(); i++) {
- if (rect.intersects(mOps[i]->state.mBounds)) {
+ if (rect.intersects(mOps[i].state->mBounds)) {
#if DEBUG_DEFER
- DEFER_LOGD("op intersects with op %p with bounds %f %f %f %f:", mOps[i],
- mOps[i]->state.mBounds.left, mOps[i]->state.mBounds.top,
- mOps[i]->state.mBounds.right, mOps[i]->state.mBounds.bottom);
- mOps[i]->output(2);
+ DEFER_LOGD("op intersects with op %p with bounds %f %f %f %f:", mOps[i].op,
+ mOps[i].state->mBounds.left, mOps[i].state->mBounds.top,
+ mOps[i].state->mBounds.right, mOps[i].state->mBounds.bottom);
+ mOps[i].op->output(2);
#endif
return true;
}
@@ -97,9 +97,9 @@
status_t status = DrawGlInfo::kStatusDone;
DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
for (unsigned int i = 0; i < mOps.size(); i++) {
- DrawOp* op = mOps[i];
-
- renderer.restoreDisplayState(op->state);
+ DrawOp* op = mOps[i].op;
+ const DeferredDisplayState* state = mOps[i].state;
+ renderer.restoreDisplayState(*state);
#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
renderer.eventMark(op->name());
@@ -108,7 +108,7 @@
status |= op->applyDraw(renderer, dirty);
#if DEBUG_MERGE_BEHAVIOR
- Rect& bounds = mOps[i]->state.mBounds;
+ const Rect& bounds = state->mBounds;
int batchColor = 0x1f000000;
if (getBatchId() & 0x1) batchColor |= 0x0000ff;
if (getBatchId() & 0x2) batchColor |= 0x00ff00;
@@ -127,7 +127,7 @@
Region uncovered(android::Rect(bounds.left, bounds.top, bounds.right, bounds.bottom));
for (unsigned int i = 0; i < mOps.size(); i++) {
- Rect &r = mOps[i]->state.mBounds;
+ const Rect &r = mOps[i].state->mBounds;
uncovered.subtractSelf(android::Rect(r.left, r.top, r.right, r.bottom));
}
return uncovered.isEmpty();
@@ -138,7 +138,7 @@
inline int count() const { return mOps.size(); }
protected:
- Vector<DrawOp*> mOps;
+ Vector<OpStatePair> mOps;
Rect mBounds; // union of bounds of contained ops
private:
bool mAllOpsOpaque;
@@ -184,19 +184,19 @@
* False positives can lead to information from the paints of subsequent merged operations being
* dropped, so we make simplifying qualifications on the ops that can merge, per op type.
*/
- bool canMergeWith(DrawOp* op) {
+ bool canMergeWith(const DrawOp* op, const DeferredDisplayState* state) {
bool isTextBatch = getBatchId() == DeferredDisplayList::kOpBatch_Text ||
getBatchId() == DeferredDisplayList::kOpBatch_ColorText;
// Overlapping other operations is only allowed for text without shadow. For other ops,
// multiDraw isn't guaranteed to overdraw correctly
- if (!isTextBatch || op->state.mDrawModifiers.mHasShadow) {
- if (intersects(op->state.mBounds)) return false;
+ if (!isTextBatch || state->mDrawModifiers.mHasShadow) {
+ if (intersects(state->mBounds)) return false;
}
- const DeferredDisplayState& lhs = op->state;
- const DeferredDisplayState& rhs = mOps[0]->state;
+ const DeferredDisplayState* lhs = state;
+ const DeferredDisplayState* rhs = mOps[0].state;
- if (NEQ_FALPHA(lhs.mAlpha, rhs.mAlpha)) return false;
+ if (NEQ_FALPHA(lhs->mAlpha, rhs->mAlpha)) return false;
/* Clipping compatibility check
*
@@ -204,9 +204,9 @@
* clip for that side.
*/
const int currentFlags = mClipSideFlags;
- const int newFlags = op->state.mClipSideFlags;
+ const int newFlags = state->mClipSideFlags;
if (currentFlags != kClipSide_None || newFlags != kClipSide_None) {
- const Rect& opBounds = op->state.mBounds;
+ const Rect& opBounds = state->mBounds;
float boundsDelta = mBounds.left - opBounds.left;
if (!checkSide(currentFlags, newFlags, kClipSide_Left, boundsDelta)) return false;
boundsDelta = mBounds.top - opBounds.top;
@@ -220,9 +220,9 @@
}
// if paints are equal, then modifiers + paint attribs don't need to be compared
- if (op->mPaint == mOps[0]->mPaint) return true;
+ if (op->mPaint == mOps[0].op->mPaint) return true;
- if (op->getPaintAlpha() != mOps[0]->getPaintAlpha()) return false;
+ if (op->getPaintAlpha() != mOps[0].op->getPaintAlpha()) return false;
/* Draw Modifiers compatibility check
*
@@ -236,8 +236,8 @@
*
* These ignore cases prevent us from simply memcmp'ing the drawModifiers
*/
- const DrawModifiers& lhsMod = lhs.mDrawModifiers;
- const DrawModifiers& rhsMod = rhs.mDrawModifiers;
+ const DrawModifiers& lhsMod = lhs->mDrawModifiers;
+ const DrawModifiers& rhsMod = rhs->mDrawModifiers;
if (lhsMod.mShader != rhsMod.mShader) return false;
if (lhsMod.mColorFilter != rhsMod.mColorFilter) return false;
@@ -249,15 +249,15 @@
return true;
}
- virtual void add(DrawOp* op, bool opaqueOverBounds) {
- DrawBatch::add(op, opaqueOverBounds);
+ virtual void add(DrawOp* op, const DeferredDisplayState* state, bool opaqueOverBounds) {
+ DrawBatch::add(op, state, opaqueOverBounds);
- const int newClipSideFlags = op->state.mClipSideFlags;
+ const int newClipSideFlags = state->mClipSideFlags;
mClipSideFlags |= newClipSideFlags;
- if (newClipSideFlags & kClipSide_Left) mClipRect.left = op->state.mClip.left;
- if (newClipSideFlags & kClipSide_Top) mClipRect.top = op->state.mClip.top;
- if (newClipSideFlags & kClipSide_Right) mClipRect.right = op->state.mClip.right;
- if (newClipSideFlags & kClipSide_Bottom) mClipRect.bottom = op->state.mClip.bottom;
+ if (newClipSideFlags & kClipSide_Left) mClipRect.left = state->mClip.left;
+ if (newClipSideFlags & kClipSide_Top) mClipRect.top = state->mClip.top;
+ if (newClipSideFlags & kClipSide_Right) mClipRect.right = state->mClip.right;
+ if (newClipSideFlags & kClipSide_Bottom) mClipRect.bottom = state->mClip.bottom;
}
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
@@ -271,7 +271,7 @@
// clipping in the merged case is done ahead of time since all ops share the clip (if any)
renderer.setupMergedMultiDraw(mClipSideFlags ? &mClipRect : NULL);
- DrawOp* op = mOps[0];
+ DrawOp* op = mOps[0].op;
DisplayListLogBuffer& buffer = DisplayListLogBuffer::getInstance();
buffer.writeCommand(0, "multiDraw");
buffer.writeCommand(1, op->name());
@@ -297,11 +297,11 @@
class StateOpBatch : public Batch {
public:
// creates a single operation batch
- StateOpBatch(StateOp* op) : mOp(op) {}
+ StateOpBatch(const StateOp* op, const DeferredDisplayState* state) : mOp(op), mState(state) {}
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
DEFER_LOGD("replaying state op batch %p", this);
- renderer.restoreDisplayState(mOp->state);
+ renderer.restoreDisplayState(*mState);
// use invalid save count because it won't be used at flush time - RestoreToCountOp is the
// only one to use it, and we don't use that class at flush time, instead calling
@@ -313,16 +313,18 @@
private:
const StateOp* mOp;
+ const DeferredDisplayState* mState;
};
class RestoreToCountBatch : public Batch {
public:
- RestoreToCountBatch(StateOp* op, int restoreCount) : mOp(op), mRestoreCount(restoreCount) {}
+ RestoreToCountBatch(const StateOp* op, const DeferredDisplayState* state, int restoreCount) :
+ mOp(op), mState(state), mRestoreCount(restoreCount) {}
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
DEFER_LOGD("batch %p restoring to count %d", this, mRestoreCount);
- renderer.restoreDisplayState(mOp->state);
+ renderer.restoreDisplayState(*mState);
renderer.restoreToCount(mRestoreCount);
return DrawGlInfo::kStatusDone;
}
@@ -330,6 +332,8 @@
private:
// we use the state storage for the RestoreToCountOp, but don't replay the op itself
const StateOp* mOp;
+ const DeferredDisplayState* mState;
+
/*
* The count used here represents the flush() time saveCount. This is as opposed to the
* DisplayList record time, or defer() time values (which are RestoreToCountOp's mCount, and
@@ -480,12 +484,27 @@
}
void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) {
- if (renderer.storeDisplayState(op->state, getDrawOpDeferFlags())) {
+ /* 1: op calculates local bounds */
+ DeferredDisplayState* const state = createState();
+ if (op->getLocalBounds(renderer.getDrawModifiers(), state->mBounds)) {
+ if (state->mBounds.isEmpty()) {
+ // valid empty bounds, don't bother deferring
+ tryRecycleState(state);
+ return;
+ }
+ } else {
+ state->mBounds.setEmpty();
+ }
+
+ /* 2: renderer calculates global bounds + stores state */
+ if (renderer.storeDisplayState(*state, getDrawOpDeferFlags())) {
+ tryRecycleState(state);
return; // quick rejected
}
+ /* 3: ask op for defer info, given renderer state */
DeferInfo deferInfo;
- op->onDefer(renderer, deferInfo);
+ op->onDefer(renderer, deferInfo, *state);
// complex clip has a complex set of expectations on the renderer state - for now, avoid taking
// the merge path in those cases
@@ -493,8 +512,8 @@
deferInfo.opaqueOverBounds &= !recordingComplexClip() && mSaveStack.isEmpty();
if (CC_LIKELY(mAvoidOverdraw) && mBatches.size() &&
- op->state.mClipSideFlags != kClipSide_ConservativeFull &&
- deferInfo.opaqueOverBounds && op->state.mBounds.contains(mBounds)) {
+ state->mClipSideFlags != kClipSide_ConservativeFull &&
+ deferInfo.opaqueOverBounds && state->mBounds.contains(mBounds)) {
// avoid overdraw by resetting drawing state + discarding drawing ops
discardDrawingBatches(mBatches.size() - 1);
resetBatchingState();
@@ -503,7 +522,7 @@
if (CC_UNLIKELY(renderer.getCaches().drawReorderDisabled)) {
// TODO: elegant way to reuse batches?
DrawBatch* b = new DrawBatch(deferInfo);
- b->add(op, deferInfo.opaqueOverBounds);
+ b->add(op, state, deferInfo.opaqueOverBounds);
mBatches.add(b);
return;
}
@@ -515,10 +534,10 @@
// (eventually, should be similar shader)
int insertBatchIndex = mBatches.size();
if (!mBatches.isEmpty()) {
- if (op->state.mBounds.isEmpty()) {
+ if (state->mBounds.isEmpty()) {
// don't know the bounds for op, so add to last batch and start from scratch on next op
DrawBatch* b = new DrawBatch(deferInfo);
- b->add(op, deferInfo.opaqueOverBounds);
+ b->add(op, state, deferInfo.opaqueOverBounds);
mBatches.add(b);
resetBatchingState();
#if DEBUG_DEFER
@@ -531,7 +550,7 @@
if (deferInfo.mergeable) {
// Try to merge with any existing batch with same mergeId.
if (mMergingBatches[deferInfo.batchId].get(deferInfo.mergeId, targetBatch)) {
- if (!((MergingDrawBatch*) targetBatch)->canMergeWith(op)) {
+ if (!((MergingDrawBatch*) targetBatch)->canMergeWith(op, state)) {
targetBatch = NULL;
}
}
@@ -554,14 +573,14 @@
if (!targetBatch) break; // found insert position, quit
}
- if (overBatch->intersects(op->state.mBounds)) {
+ if (overBatch->intersects(state->mBounds)) {
// NOTE: it may be possible to optimize for special cases where two operations
// of the same batch/paint could swap order, such as with a non-mergeable
// (clipped) and a mergeable text operation
targetBatch = NULL;
#if DEBUG_DEFER
- DEFER_LOGD("op couldn't join batch %d, was intersected by batch %d",
- targetIndex, i);
+ DEFER_LOGD("op couldn't join batch %p, was intersected by batch %d",
+ targetBatch, i);
op->output(2);
#endif
break;
@@ -586,14 +605,15 @@
mBatches.insertAt(targetBatch, insertBatchIndex);
}
- targetBatch->add(op, deferInfo.opaqueOverBounds);
+ targetBatch->add(op, state, deferInfo.opaqueOverBounds);
}
void DeferredDisplayList::storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* op) {
DEFER_LOGD("%p adding state op barrier at pos %d", this, mBatches.size());
- renderer.storeDisplayState(op->state, getStateOpDeferFlags());
- mBatches.add(new StateOpBatch(op));
+ DeferredDisplayState* state = createState();
+ renderer.storeDisplayState(*state, getStateOpDeferFlags());
+ mBatches.add(new StateOpBatch(op, state));
resetBatchingState();
}
@@ -604,8 +624,9 @@
// store displayState for the restore operation, as it may be associated with a saveLayer that
// doesn't have kClip_SaveFlag set
- renderer.storeDisplayState(op->state, getStateOpDeferFlags());
- mBatches.add(new RestoreToCountBatch(op, newSaveCount));
+ DeferredDisplayState* state = createState();
+ renderer.storeDisplayState(*state, getStateOpDeferFlags());
+ mBatches.add(new RestoreToCountBatch(op, state, newSaveCount));
resetBatchingState();
}
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 1ef0152..3dcbd0b 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -18,11 +18,13 @@
#define ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H
#include <utils/Errors.h>
+#include <utils/LinearAllocator.h>
#include <utils/Vector.h>
+#include <utils/TinyHashMap.h>
#include "Matrix.h"
+#include "OpenGLRenderer.h"
#include "Rect.h"
-#include "utils/TinyHashMap.h"
class SkBitmap;
@@ -34,6 +36,8 @@
class SaveOp;
class SaveLayerOp;
class StateOp;
+
+class DeferredDisplayState;
class OpenGLRenderer;
class Batch;
@@ -42,6 +46,38 @@
typedef const void* mergeid_t;
+class DeferredDisplayState {
+public:
+ /** static void* operator new(size_t size); PURPOSELY OMITTED **/
+ static void* operator new(size_t size, LinearAllocator& allocator) {
+ return allocator.alloc(size);
+ }
+
+ // global op bounds, mapped by mMatrix to be in screen space coordinates, clipped
+ Rect mBounds;
+
+ // the below are set and used by the OpenGLRenderer at record and deferred playback
+ bool mClipValid;
+ Rect mClip;
+ int mClipSideFlags; // specifies which sides of the bounds are clipped, unclipped if cleared
+ bool mClipped;
+ mat4 mMatrix;
+ DrawModifiers mDrawModifiers;
+ float mAlpha;
+};
+
+class OpStatePair {
+public:
+ OpStatePair()
+ : op(NULL), state(NULL) {}
+ OpStatePair(DrawOp* newOp, const DeferredDisplayState* newState)
+ : op(newOp), state(newState) {}
+ OpStatePair(const OpStatePair& other)
+ : op(other.op), state(other.state) {}
+ DrawOp* op;
+ const DeferredDisplayState* state;
+};
+
class DeferredDisplayList {
public:
DeferredDisplayList(const Rect& bounds, bool avoidOverdraw = true) :
@@ -84,6 +120,14 @@
void addDrawOp(OpenGLRenderer& renderer, DrawOp* op);
private:
+ DeferredDisplayState* createState() {
+ return new (mAllocator) DeferredDisplayState();
+ }
+
+ void tryRecycleState(DeferredDisplayState* state) {
+ mAllocator.rewindIfLastAlloc(state, sizeof(DeferredDisplayState));
+ }
+
/**
* Resets the batching back-pointers, creating a barrier in the operation stream so that no ops
* added in the future will be inserted into a batch that already exist.
@@ -131,6 +175,8 @@
* collide, which avoids the need to resolve mergeid collisions.
*/
TinyHashMap<mergeid_t, DrawBatch*> mMergingBatches[kOpBatch_Count];
+
+ LinearAllocator mAllocator;
};
/**
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 0d7b37d..bb6526e 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -369,11 +369,10 @@
}
}
- bool clipToBoundsNeeded = mClipToBounds;
+ bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
if (mAlpha < 1) {
if (mCaching) {
ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha);
- clipToBoundsNeeded = false; // clipping done by layer
} else if (!mHasOverlappingRendering) {
ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha);
} else {
@@ -422,11 +421,10 @@
renderer.concatMatrix(mTransformMatrix);
}
}
- bool clipToBoundsNeeded = mClipToBounds;
+ bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
if (mAlpha < 1) {
if (mCaching) {
renderer.setOverrideLayerAlpha(mAlpha);
- clipToBoundsNeeded = false; // clipping done by layer
} else if (!mHasOverlappingRendering) {
renderer.scaleAlpha(mAlpha);
} else {
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 194be9e..1cd5f1c 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -26,6 +26,7 @@
#include <private/hwui/DrawGlInfo.h>
+#include <utils/LinearAllocator.h>
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
@@ -35,8 +36,6 @@
#include <androidfw/ResourceTypes.h>
-#include "utils/LinearAllocator.h"
-
#include "Debug.h"
#define TRANSLATION 0x0001
@@ -114,7 +113,6 @@
void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
-
void defer(DeferStateStruct& deferStruct, const int level);
void replay(ReplayStateStruct& replayStruct, const int level);
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 42e11d0..a17942e 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -82,15 +82,6 @@
// NOTE: it would be nice to declare constants and overriding the implementation in each op to
// point at the constants, but that seems to require a .cpp file
virtual const char* name() = 0;
-
- /**
- * Stores the relevant canvas state of the object between deferral and replay (if the canvas
- * state supports being stored) See OpenGLRenderer::simpleClipAndState()
- *
- * TODO: don't reserve space for StateOps that won't be deferred
- */
- DeferredDisplayState state;
-
};
class StateOp : public DisplayListOp {
@@ -129,14 +120,6 @@
return;
}
- if (getLocalBounds(state.mBounds)) {
- // valid empty bounds, don't bother deferring
- if (state.mBounds.isEmpty()) return;
- } else {
- // empty bounds signify bounds can't be calculated
- state.mBounds.setEmpty();
- }
-
deferStruct.mDeferredList.addDrawOp(deferStruct.mRenderer, this);
}
@@ -159,11 +142,11 @@
* reducing which operations are tagged as mergeable.
*/
virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
- const Vector<DrawOp*>& ops, const Rect& bounds) {
+ const Vector<OpStatePair>& ops, const Rect& bounds) {
status_t status = DrawGlInfo::kStatusDone;
for (unsigned int i = 0; i < ops.size(); i++) {
- renderer.restoreDisplayState(ops[i]->state, true);
- status |= ops[i]->applyDraw(renderer, dirty);
+ renderer.restoreDisplayState(*(ops[i].state), true);
+ status |= ops[i].op->applyDraw(renderer, dirty);
}
return status;
}
@@ -178,20 +161,23 @@
*
* if a subclass can set deferInfo.mergeable to true, it should implement multiDraw()
*/
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {}
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {}
/**
* Query the conservative, local bounds (unmapped) bounds of the op.
*
* returns true if bounds exist
*/
- virtual bool getLocalBounds(Rect& localBounds) { return false; }
+ virtual bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
+ return false;
+ }
// TODO: better refine localbounds usage
void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
bool getQuickRejected() { return mQuickRejected; }
- inline int getPaintAlpha() {
+ inline int getPaintAlpha() const {
return OpenGLRenderer::getAlphaDirect(mPaint);
}
@@ -208,7 +194,7 @@
// Helper method for determining op opaqueness. Assumes op fills its bounds in local
// coordinates, and that paint's alpha is used
- inline bool isOpaqueOverBounds() {
+ inline bool isOpaqueOverBounds(const DeferredDisplayState& state) {
// ensure that local bounds cover mapped bounds
if (!state.mMatrix.isSimple()) return false;
@@ -251,12 +237,13 @@
// default empty constructor for bounds, to be overridden in child constructor body
DrawBoundedOp(SkPaint* paint): DrawOp(paint) { }
- bool getLocalBounds(Rect& localBounds) {
+ bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
localBounds.set(mLocalBounds);
- if (state.mDrawModifiers.mHasShadow) {
+ if (drawModifiers.mHasShadow) {
+ // TODO: inspect paint's looper directly
Rect shadow(mLocalBounds);
- shadow.translate(state.mDrawModifiers.mShadowDx, state.mDrawModifiers.mShadowDy);
- shadow.outset(state.mDrawModifiers.mShadowRadius);
+ shadow.translate(drawModifiers.mShadowDx, drawModifiers.mShadowDy);
+ shadow.outset(drawModifiers.mShadowRadius);
localBounds.unionWith(shadow);
}
return true;
@@ -777,8 +764,10 @@
* the current layer, if any.
*/
virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
- const Vector<DrawOp*>& ops, const Rect& bounds) {
- renderer.restoreDisplayState(state, true); // restore all but the clip
+ const Vector<OpStatePair>& ops, const Rect& bounds) {
+ const DeferredDisplayState& firstState = *(ops[0].state);
+ renderer.restoreDisplayState(firstState, true); // restore all but the clip
+
TextureVertex vertices[6 * ops.size()];
TextureVertex* vertex = &vertices[0];
@@ -788,14 +777,15 @@
// TODO: manually handle rect clip for bitmaps by adjusting texCoords per op,
// and allowing them to be merged in getBatchId()
for (unsigned int i = 0; i < ops.size(); i++) {
- const Rect& opBounds = ops[i]->state.mBounds;
+ const DeferredDisplayState& state = *(ops[i].state);
+ const Rect& opBounds = state.mBounds;
// When we reach multiDraw(), the matrix can be either
// pureTranslate or simple (translate and/or scale).
// If the matrix is not pureTranslate, then we have a scale
- if (!ops[i]->state.mMatrix.isPureTranslate()) transformed = true;
+ if (state.mMatrix.isPureTranslate()) transformed = true;
Rect texCoords(0, 0, 1, 1);
- ((DrawBitmapOp*) ops[i])->mUvMapper.map(texCoords);
+ ((DrawBitmapOp*) ops[i].op)->mUvMapper.map(texCoords);
SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, top);
SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
@@ -806,8 +796,7 @@
SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, bottom);
if (hasLayer) {
- const Rect& dirty = ops[i]->state.mBounds;
- renderer.dirtyLayer(dirty.left, dirty.top, dirty.right, dirty.bottom);
+ renderer.dirtyLayer(opBounds.left, opBounds.top, opBounds.right, opBounds.bottom);
}
}
@@ -821,7 +810,8 @@
virtual const char* name() { return "DrawBitmap"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
deferInfo.mergeId = getAtlasEntry() ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
@@ -861,7 +851,8 @@
virtual const char* name() { return "DrawBitmapMatrix"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
}
@@ -890,7 +881,8 @@
virtual const char* name() { return "DrawBitmapRect"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
}
@@ -915,7 +907,8 @@
virtual const char* name() { return "DrawBitmapData"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
}
};
@@ -939,7 +932,8 @@
virtual const char* name() { return "DrawBitmapMesh"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
}
@@ -989,15 +983,16 @@
* is also responsible for dirtying the current layer, if any.
*/
virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
- const Vector<DrawOp*>& ops, const Rect& bounds) {
- renderer.restoreDisplayState(state, true);
+ const Vector<OpStatePair>& ops, const Rect& bounds) {
+ const DeferredDisplayState& firstState = *(ops[0].state);
+ renderer.restoreDisplayState(firstState, true); // restore all but the clip
// Batches will usually contain a small number of items so it's
// worth performing a first iteration to count the exact number
// of vertices we need in the new mesh
uint32_t totalVertices = 0;
for (unsigned int i = 0; i < ops.size(); i++) {
- totalVertices += ((DrawPatchOp*) ops[i])->getMesh(renderer)->verticesCount;
+ totalVertices += ((DrawPatchOp*) ops[i].op)->getMesh(renderer)->verticesCount;
}
const bool hasLayer = renderer.hasLayer();
@@ -1012,7 +1007,8 @@
// enforces ops drawn by this function to have a pure translate or
// identity matrix
for (unsigned int i = 0; i < ops.size(); i++) {
- DrawPatchOp* patchOp = (DrawPatchOp*) ops[i];
+ DrawPatchOp* patchOp = (DrawPatchOp*) ops[i].op;
+ const DeferredDisplayState* state = ops[i].state;
const Patch* opMesh = patchOp->getMesh(renderer);
uint32_t vertexCount = opMesh->verticesCount;
if (vertexCount == 0) continue;
@@ -1020,9 +1016,9 @@
// We use the bounds to know where to translate our vertices
// Using patchOp->state.mBounds wouldn't work because these
// bounds are clipped
- const float tx = (int) floorf(patchOp->state.mMatrix.getTranslateX() +
+ const float tx = (int) floorf(state->mMatrix.getTranslateX() +
patchOp->mLocalBounds.left + 0.5f);
- const float ty = (int) floorf(patchOp->state.mMatrix.getTranslateY() +
+ const float ty = (int) floorf(state->mMatrix.getTranslateY() +
patchOp->mLocalBounds.top + 0.5f);
// Copy & transform all the vertices for the current operation
@@ -1074,12 +1070,13 @@
virtual const char* name() { return "DrawPatch"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Patch;
deferInfo.mergeId = getAtlasEntry() ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
deferInfo.mergeable = state.mMatrix.isPureTranslate() &&
OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
- deferInfo.opaqueOverBounds = isOpaqueOverBounds() && mBitmap->isOpaque();
+ deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && mBitmap->isOpaque();
}
private:
@@ -1119,7 +1116,7 @@
DrawStrokableOp(float left, float top, float right, float bottom, SkPaint* paint)
: DrawBoundedOp(left, top, right, bottom, paint) {};
- bool getLocalBounds(Rect& localBounds) {
+ bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
localBounds.set(mLocalBounds);
if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
localBounds.outset(strokeWidthOutset());
@@ -1127,7 +1124,8 @@
return true;
}
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
if (mPaint->getPathEffect()) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
} else {
@@ -1152,9 +1150,10 @@
OP_LOG("Draw Rect "RECT_STRING, RECT_ARGS(mLocalBounds));
}
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
- DrawStrokableOp::onDefer(renderer, deferInfo);
- deferInfo.opaqueOverBounds = isOpaqueOverBounds() &&
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
+ DrawStrokableOp::onDefer(renderer, deferInfo, state);
+ deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) &&
mPaint->getStyle() == SkPaint::kFill_Style;
}
@@ -1177,7 +1176,8 @@
virtual const char* name() { return "DrawRects"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Vertices;
}
@@ -1289,7 +1289,8 @@
return renderer.drawPath(mPath, getPaint(renderer));
}
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
SkPaint* paint = getPaint(renderer);
renderer.getCaches().pathCache.precache(mPath, paint);
@@ -1324,7 +1325,8 @@
virtual const char* name() { return "DrawLines"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = mPaint->isAntiAlias() ?
DeferredDisplayList::kOpBatch_AlphaVertices :
DeferredDisplayList::kOpBatch_Vertices;
@@ -1360,7 +1362,8 @@
OP_LOG("Draw some text, %d bytes", mBytesCount);
}
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
SkPaint* paint = getPaint(renderer);
FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
fontRenderer.precache(paint, mText, mCount, mat4::identity());
@@ -1425,7 +1428,8 @@
memset(&mPrecacheTransform.data[0], 0xff, 16 * sizeof(float));
}
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
SkPaint* paint = getPaint(renderer);
FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
const mat4& transform = renderer.findBestFontTransform(state.mMatrix);
@@ -1448,19 +1452,20 @@
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
Rect bounds;
- getLocalBounds(bounds);
+ getLocalBounds(renderer.getDrawModifiers(), bounds);
return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
mPositions, getPaint(renderer), mTotalAdvance, bounds);
}
virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
- const Vector<DrawOp*>& ops, const Rect& bounds) {
+ const Vector<OpStatePair>& ops, const Rect& bounds) {
status_t status = DrawGlInfo::kStatusDone;
for (unsigned int i = 0; i < ops.size(); i++) {
+ const DeferredDisplayState& state = *(ops[i].state);
DrawOpMode drawOpMode = (i == ops.size() - 1) ? kDrawOpMode_Flush : kDrawOpMode_Defer;
- renderer.restoreDisplayState(ops[i]->state, true); // restore all but the clip
+ renderer.restoreDisplayState(state, true); // restore all but the clip
- DrawTextOp& op = *((DrawTextOp*)ops[i]);
+ DrawTextOp& op = *((DrawTextOp*)ops[i].op);
// quickReject() will not occure in drawText() so we can use mLocalBounds
// directly, we do not need to account for shadow by calling getLocalBounds()
status |= renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 90dcf93..8866029 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -505,17 +505,12 @@
void DisplayListRenderer::addDrawOp(DrawOp* op) {
Rect localBounds;
- if (mDrawModifiers.mHasShadow) {
- op->state.mDrawModifiers = mDrawModifiers;
- }
- if (op->getLocalBounds(localBounds)) {
+ if (op->getLocalBounds(mDrawModifiers, localBounds)) {
bool rejected = quickRejectNoScissor(localBounds.left, localBounds.top,
localBounds.right, localBounds.bottom);
op->setQuickRejected(rejected);
}
- if (mDrawModifiers.mHasShadow) {
- op->state.mDrawModifiers.reset();
- }
+
mHasDrawOps = true;
addOpInternal(op);
}
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index e8456af..7e99a5f 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -732,7 +732,7 @@
if (mRs == 0) {
mRs = new RSC::RS();
- if (!mRs->init(RSC::RS_INIT_LOW_LATENCY & RSC::RS_INIT_SYNCHRONOUS)) {
+ if (!mRs->init(RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
ALOGE("blur RS failed to init");
}
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 238d9a4..2066f69 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -471,12 +471,14 @@
info.height = getSnapshot()->height;
getSnapshot()->transform->copyTo(&info.transform[0]);
+ bool dirtyClip = mDirtyClip;
// setup GL state for functor
if (mDirtyClip) {
- setScissorFromClip();
setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
}
- mCaches.enableScissor();
+ if (mCaches.enableScissor() || dirtyClip) {
+ setScissorFromClip();
+ }
interrupt();
// call functor immediately after GL state setup
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 54f6d76..f74df97 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -98,24 +98,11 @@
kClipSide_ConservativeFull = 0x1F
};
-struct DeferredDisplayState {
- // global op bounds, mapped by mMatrix to be in screen space coordinates, clipped
- Rect mBounds;
-
- // the below are set and used by the OpenGLRenderer at record and deferred playback
- bool mClipValid;
- Rect mClip;
- int mClipSideFlags; // specifies which sides of the bounds are clipped, unclipped if cleared
- bool mClipped;
- mat4 mMatrix;
- DrawModifiers mDrawModifiers;
- float mAlpha;
-};
-
///////////////////////////////////////////////////////////////////////////////
// Renderer
///////////////////////////////////////////////////////////////////////////////
+class DeferredDisplayState;
class DisplayList;
class TextSetupFunctor;
class VertexBuffer;
@@ -423,7 +410,7 @@
return getXfermode(paint->getXfermode());
}
- static inline int getAlphaDirect(SkPaint* paint) {
+ static inline int getAlphaDirect(const SkPaint* paint) {
if (!paint) return 255;
return paint->getAlpha();
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 14b812e..ccb4304 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -152,17 +152,18 @@
/**
* Broadcast intent action when the configured location providers
- * change. If you're interacting with the
- * {@link android.provider.Settings.Secure#LOCATION_MODE} API,
- * use {@link #MODE_CHANGED_ACTION} instead.
+ * change. For use with {@link #isProviderEnabled(String)}. If you're interacting with the
+ * {@link android.provider.Settings.Secure#LOCATION_MODE} API, use {@link #MODE_CHANGED_ACTION}
+ * instead.
*/
public static final String PROVIDERS_CHANGED_ACTION =
"android.location.PROVIDERS_CHANGED";
/**
* Broadcast intent action when {@link android.provider.Settings.Secure#LOCATION_MODE} changes.
- * If you're interacting with provider-based APIs such as {@link #getProviders(boolean)}, you
- * use {@link #PROVIDERS_CHANGED_ACTION} instead.
+ * For use with the {@link android.provider.Settings.Secure#LOCATION_MODE} API.
+ * If you're interacting with {@link #isProviderEnabled(String)}, use
+ * {@link #PROVIDERS_CHANGED_ACTION} instead.
*
* In the future, there may be mode changes that do not result in
* {@link #PROVIDERS_CHANGED_ACTION} broadcasts.
@@ -1098,8 +1099,13 @@
* <p>If the user has enabled this provider in the Settings menu, true
* is returned otherwise false is returned
*
+ * <p>Callers should instead use
+ * {@link android.provider.Settings.Secure#LOCATION_MODE}
+ * unless they depend on provider-specific APIs such as
+ * {@link #requestLocationUpdates(String, long, float, LocationListener)}.
+ *
* @param provider the name of the provider
- * @return true if the provider is enabled
+ * @return true if the provider exists and is enabled
*
* @throws IllegalArgumentException if provider is null
* @throws SecurityException if no suitable permission is present
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 1dcf0e9..4542643 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -323,6 +323,12 @@
public static final int FLAG_FIXED_VOLUME = 1 << 5;
/**
+ * Indicates the volume set/adjust call is for Bluetooth absolute volume
+ * @hide
+ */
+ public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
+
+ /**
* Ringer mode that will be silent and will not vibrate. (This overrides the
* vibrate setting.)
*
@@ -551,10 +557,10 @@
IAudioService service = getService();
try {
if (mUseMasterVolume) {
- service.adjustMasterVolume(direction, flags, mContext.getBasePackageName());
+ service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
} else {
service.adjustStreamVolume(streamType, direction, flags,
- mContext.getBasePackageName());
+ mContext.getOpPackageName());
}
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustStreamVolume", e);
@@ -582,9 +588,9 @@
IAudioService service = getService();
try {
if (mUseMasterVolume) {
- service.adjustMasterVolume(direction, flags, mContext.getBasePackageName());
+ service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
} else {
- service.adjustVolume(direction, flags, mContext.getBasePackageName());
+ service.adjustVolume(direction, flags, mContext.getOpPackageName());
}
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustVolume", e);
@@ -612,10 +618,10 @@
IAudioService service = getService();
try {
if (mUseMasterVolume) {
- service.adjustMasterVolume(direction, flags, mContext.getBasePackageName());
+ service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
} else {
service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags,
- mContext.getBasePackageName());
+ mContext.getOpPackageName());
}
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustSuggestedStreamVolume", e);
@@ -634,7 +640,7 @@
public void adjustMasterVolume(int steps, int flags) {
IAudioService service = getService();
try {
- service.adjustMasterVolume(steps, flags, mContext.getBasePackageName());
+ service.adjustMasterVolume(steps, flags, mContext.getOpPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustMasterVolume", e);
}
@@ -786,9 +792,9 @@
IAudioService service = getService();
try {
if (mUseMasterVolume) {
- service.setMasterVolume(index, flags, mContext.getBasePackageName());
+ service.setMasterVolume(index, flags, mContext.getOpPackageName());
} else {
- service.setStreamVolume(streamType, index, flags, mContext.getBasePackageName());
+ service.setStreamVolume(streamType, index, flags, mContext.getOpPackageName());
}
} catch (RemoteException e) {
Log.e(TAG, "Dead object in setStreamVolume", e);
@@ -854,7 +860,7 @@
public void setMasterVolume(int index, int flags) {
IAudioService service = getService();
try {
- service.setMasterVolume(index, flags, mContext.getBasePackageName());
+ service.setMasterVolume(index, flags, mContext.getOpPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Dead object in setMasterVolume", e);
}
@@ -1532,16 +1538,6 @@
/**
* @hide
- * Checks whether speech recognition is active
- * @return true if a recording with source {@link MediaRecorder.AudioSource#VOICE_RECOGNITION}
- * is underway.
- */
- public boolean isSpeechRecognitionActive() {
- return AudioSystem.isSourceActive(MediaRecorder.AudioSource.VOICE_RECOGNITION);
- }
-
- /**
- * @hide
* Checks whether the current audio focus is exclusive.
* @return true if the top of the audio focus stack requested focus
* with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
@@ -1569,7 +1565,7 @@
IAudioService service = getService();
try {
service.adjustLocalOrRemoteStreamVolume(streamType, direction,
- mContext.getBasePackageName());
+ mContext.getOpPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustLocalOrRemoteStreamVolume", e);
}
@@ -1996,7 +1992,7 @@
try {
status = service.requestAudioFocus(streamType, durationHint, mICallBack,
mAudioFocusDispatcher, getIdForAudioFocusListener(l),
- mContext.getBasePackageName() /* package name */);
+ mContext.getOpPackageName() /* package name */);
} catch (RemoteException e) {
Log.e(TAG, "Can't call requestAudioFocus() on AudioService due to "+e);
}
@@ -2018,7 +2014,7 @@
try {
service.requestAudioFocus(streamType, durationHint, mICallBack, null,
MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
- mContext.getBasePackageName());
+ mContext.getOpPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService due to "+e);
}
@@ -2407,20 +2403,6 @@
}
}
- /**
- * @hide
- * Notifies AudioService of the volume set on the A2DP device as a callback, so AudioService
- * is able to update the UI.
- */
- public void avrcpUpdateVolume(int oldVolume, int volume) {
- IAudioService service = getService();
- try {
- service.avrcpUpdateVolume(oldVolume, volume);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in avrcpUpdateVolume", e);
- }
- }
-
/**
* {@hide}
*/
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index d20f5b9..f49ef2e 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -252,7 +252,8 @@
//--------------
// audio source
if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) ||
- (audioSource > MediaRecorder.getAudioSourceMax()) ) {
+ ((audioSource > MediaRecorder.getAudioSourceMax()) &&
+ (audioSource != MediaRecorder.AudioSource.HOTWORD)) ) {
throw new IllegalArgumentException("Invalid audio source.");
}
mRecordSource = audioSource;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index b72551a..07f0858 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -843,6 +843,13 @@
boolean adjustVolume = true;
int step;
+ // skip a2dp absolute volume control request when the device
+ // is not an a2dp device
+ if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
+ (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+ return;
+ }
+
if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
callingPackage) != AppOpsManager.MODE_ALLOWED) {
return;
@@ -892,15 +899,18 @@
int oldIndex = mStreamStates[streamType].getIndex(device);
if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
+
// Check if volume update should be send to AVRCP
- synchronized (mA2dpAvrcpLock) {
- if (mA2dp != null && mAvrcpAbsVolSupported) {
- mA2dp.adjustAvrcpAbsoluteVolume(direction);
- return;
- // No need to send volume update, because we will update the volume with a
- // callback from Avrcp.
+ if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+ (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+ (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+ synchronized (mA2dpAvrcpLock) {
+ if (mA2dp != null && mAvrcpAbsVolSupported) {
+ mA2dp.adjustAvrcpAbsoluteVolume(direction);
+ }
}
}
+
if ((direction == AudioManager.ADJUST_RAISE) &&
!checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
@@ -985,6 +995,13 @@
final int device = getDeviceForStream(streamType);
int oldIndex;
+ // skip a2dp absolute volume control request when the device
+ // is not an a2dp device
+ if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
+ (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+ return;
+ }
+
if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
callingPackage) != AppOpsManager.MODE_ALLOWED) {
return;
@@ -998,12 +1015,13 @@
index = rescaleIndex(index * 10, streamType, streamTypeAlias);
- synchronized (mA2dpAvrcpLock) {
- if (mA2dp != null && mAvrcpAbsVolSupported) {
- mA2dp.setAvrcpAbsoluteVolume(index);
- return;
- // No need to send volume update, because we will update the volume with a
- // callback from Avrcp.
+ if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+ (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+ (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+ synchronized (mA2dpAvrcpLock) {
+ if (mA2dp != null && mAvrcpAbsVolSupported) {
+ mA2dp.setAvrcpAbsoluteVolume(index);
+ }
}
}
@@ -2835,7 +2853,12 @@
int index;
if (isMuted()) {
index = 0;
- } else {
+ } else if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC &&
+ (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+ mAvrcpAbsVolSupported) {
+ index = (mIndexMax + 5)/10;
+ }
+ else {
index = (getIndex(device) + 5)/10;
}
AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
@@ -3650,6 +3673,9 @@
private void makeA2dpDeviceAvailable(String address) {
// enable A2DP before notifying A2DP connection to avoid unecessary processing in
// audio policy manager
+ VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+ sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
setBluetoothA2dpOnInt(true);
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_AVAILABLE,
@@ -3666,6 +3692,9 @@
// must be called synchronized on mConnectedDevices
private void makeA2dpDeviceUnavailableNow(String address) {
+ synchronized (mA2dpAvrcpLock) {
+ mAvrcpAbsVolSupported = false;
+ }
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
address);
@@ -3706,19 +3735,6 @@
address = "";
}
- // Disable absolute volume, if device is disconnected
- synchronized (mA2dpAvrcpLock) {
- if (state == BluetoothProfile.STATE_DISCONNECTED && mAvrcpAbsVolSupported) {
- mAvrcpAbsVolSupported = false;
- sendMsg(mAudioHandler,
- MSG_SET_DEVICE_VOLUME,
- SENDMSG_QUEUE,
- getDeviceForStream(AudioSystem.STREAM_MUSIC),
- 0,
- mStreamStates[AudioSystem.STREAM_MUSIC],
- 0);
- }
- }
synchronized (mConnectedDevices) {
boolean isConnected =
(mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
@@ -3773,27 +3789,12 @@
// address is not used for now, but may be used when multiple a2dp devices are supported
synchronized (mA2dpAvrcpLock) {
mAvrcpAbsVolSupported = support;
- if (support) {
- VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
- int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
- streamState.setIndex(streamState.getMaxIndex(), device);
- sendMsg(mAudioHandler,
- MSG_SET_DEVICE_VOLUME,
- SENDMSG_QUEUE,
- device,
- 0,
- streamState,
- 0);
- }
+ VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+ sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
}
}
- public void avrcpUpdateVolume(int oldVolume, int volume) {
- mStreamStates[AudioSystem.STREAM_MUSIC].
- setIndex(volume, getDeviceForStream(AudioSystem.STREAM_MUSIC));
- sendVolumeUpdate(AudioSystem.STREAM_MUSIC, oldVolume, volume, AudioManager.FLAG_SHOW_UI);
- }
-
private boolean handleDeviceConnection(boolean connected, int device, String params) {
synchronized (mConnectedDevices) {
boolean isConnected = (mConnectedDevices.containsKey(device) &&
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 788257d..78a37c5 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -746,31 +746,28 @@
* If you need such features, consider implementing them at application level.
*
* @param timestamp a reference to a non-null AudioTimestamp instance allocated
- * and owned by caller, or null.
- * @return that same instance if timestamp parameter is non-null and a timestamp is available,
- * or a reference to a new AudioTimestamp instance which is now owned by caller
- * if timestamp parameter is null and a timestamp is available,
- * or null if no timestamp is available. In either successful case,
+ * and owned by caller.
+ * @return true if a timestamp is available, or false if no timestamp is available.
+ * If a timestamp if available,
* the AudioTimestamp instance is filled in with a position in frame units, together
* with the estimated time when that frame was presented or is committed to
* be presented.
* In the case that no timestamp is available, any supplied instance is left unaltered.
*/
- public AudioTimestamp getTimestamp(AudioTimestamp timestamp)
+ public boolean getTimestamp(AudioTimestamp timestamp)
{
+ if (timestamp == null) {
+ throw new IllegalArgumentException();
+ }
// It's unfortunate, but we have to either create garbage every time or use synchronized
long[] longArray = new long[2];
int ret = native_get_timestamp(longArray);
- if (ret == SUCCESS) {
- if (timestamp == null) {
- timestamp = new AudioTimestamp();
- }
- timestamp.framePosition = longArray[0];
- timestamp.nanoTime = longArray[1];
- } else {
- timestamp = null;
+ if (ret != SUCCESS) {
+ return false;
}
- return timestamp;
+ timestamp.framePosition = longArray[0];
+ timestamp.nanoTime = longArray[1];
+ return true;
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fe060f8..e08ecbf 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -100,8 +100,6 @@
oneway void avrcpSupportsAbsoluteVolume(String address, boolean support);
- oneway void avrcpUpdateVolume(int oldVolume, int volume);
-
void setSpeakerphoneOn(boolean on);
boolean isSpeakerphoneOn();
diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl
index dd729b4..48079f2 100644
--- a/media/java/android/media/IRemoteControlClient.aidl
+++ b/media/java/android/media/IRemoteControlClient.aidl
@@ -17,6 +17,7 @@
import android.graphics.Bitmap;
import android.media.IRemoteControlDisplay;
+import android.media.Rating;
/**
* @hide
@@ -49,5 +50,5 @@
void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h);
void setWantsSyncForDisplay(IRemoteControlDisplay rcd, boolean wantsSync);
void seekTo(int clientGeneration, long timeMs);
- void updateMetadata(int clientGeneration, int key, long value);
+ void updateMetadata(int clientGeneration, int key, in Rating value);
}
\ No newline at end of file
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 9f442f5..a346e17 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -16,20 +16,19 @@
package android.media;
-import android.graphics.ImageFormat;
import java.nio.ByteBuffer;
import java.lang.AutoCloseable;
/**
* <p>A single complete image buffer to use with a media source such as a
* {@link MediaCodec} or a
- * {@link android.hardware.camera2.CameraDevice}.</p>
+ * {@link android.hardware.camera2.CameraDevice CameraDevice}.</p>
*
* <p>This class allows for efficient direct application access to the pixel
* data of the Image through one or more
* {@link java.nio.ByteBuffer ByteBuffers}. Each buffer is encapsulated in a
* {@link Plane} that describes the layout of the pixel data in that plane. Due
- * to this direct access, and unlike the {@link android.graphics.Bitmap} class,
+ * to this direct access, and unlike the {@link android.graphics.Bitmap Bitmap} class,
* Images are not directly usable as as UI resources.</p>
*
* <p>Since Images are often directly produced or consumed by hardware
@@ -40,19 +39,28 @@
* from various media sources, not closing old Image objects will prevent the
* availability of new Images once
* {@link ImageReader#getMaxImages the maximum outstanding image count} is
- * reached.</p>
+ * reached. When this happens, the function acquiring new Images will typically
+ * throw an {@link IllegalStateException}.</p>
*
* @see ImageReader
*/
-public interface Image extends AutoCloseable {
+public abstract class Image implements AutoCloseable {
+ /**
+ * @hide
+ */
+ protected Image() {
+ }
+
/**
* Get the format for this image. This format determines the number of
* ByteBuffers needed to represent the image, and the general layout of the
* pixel data in each in ByteBuffer.
*
+ * <p>
* The format is one of the values from
- * {@link android.graphics.ImageFormat}. The mapping between the formats and
- * the planes is as follows:
+ * {@link android.graphics.ImageFormat ImageFormat}. The mapping between the
+ * formats and the planes is as follows:
+ * </p>
*
* <table>
* <tr>
@@ -61,13 +69,14 @@
* <th>Layout details</th>
* </tr>
* <tr>
- * <td>{@link android.graphics.ImageFormat#JPEG}</td>
+ * <td>{@link android.graphics.ImageFormat#JPEG JPEG}</td>
* <td>1</td>
* <td>Compressed data, so row and pixel strides are 0. To uncompress, use
- * {@link android.graphics.BitmapFactory#decodeByteArray}.</td>
+ * {@link android.graphics.BitmapFactory#decodeByteArray BitmapFactory#decodeByteArray}.
+ * </td>
* </tr>
* <tr>
- * <td>{@link android.graphics.ImageFormat#YUV_420_888}</td>
+ * <td>{@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}</td>
* <td>3</td>
* <td>A luminance plane followed by the Cb and Cr chroma planes.
* The chroma planes have half the width and height of the luminance
@@ -75,53 +84,60 @@
* Each plane has its own row stride and pixel stride.</td>
* </tr>
* <tr>
- * <td>{@link android.graphics.ImageFormat#RAW_SENSOR}</td>
+ * <td>{@link android.graphics.ImageFormat#RAW_SENSOR RAW_SENSOR}</td>
* <td>1</td>
* <td>A single plane of raw sensor image data, with 16 bits per color
* sample. The details of the layout need to be queried from the source of
* the raw sensor data, such as
- * {@link android.hardware.camera2.CameraDevice}.
+ * {@link android.hardware.camera2.CameraDevice CameraDevice}.
* </td>
* </tr>
* </table>
*
* @see android.graphics.ImageFormat
*/
- public int getFormat();
+ public abstract int getFormat();
/**
* The width of the image in pixels. For formats where some color channels
* are subsampled, this is the width of the largest-resolution plane.
*/
- public int getWidth();
+ public abstract int getWidth();
/**
* The height of the image in pixels. For formats where some color channels
* are subsampled, this is the height of the largest-resolution plane.
*/
- public int getHeight();
+ public abstract int getHeight();
/**
- * Get the timestamp associated with this frame. The timestamp is measured
- * in nanoseconds, and is monotonically increasing. However, the zero point
- * and whether the timestamp can be compared against other sources of time
- * or images depend on the source of this image.
+ * Get the timestamp associated with this frame.
+ * <p>
+ * The timestamp is measured in nanoseconds, and is monotonically
+ * increasing. However, the zero point and whether the timestamp can be
+ * compared against other sources of time or images depend on the source of
+ * this image.
+ * </p>
*/
- public long getTimestamp();
+ public abstract long getTimestamp();
/**
* Get the array of pixel planes for this Image. The number of planes is
* determined by the format of the Image.
*/
- public Plane[] getPlanes();
+ public abstract Plane[] getPlanes();
/**
- * Free up this frame for reuse. After calling this method, calling any
- * methods on this Image will result in an IllegalStateException, and
- * attempting to read from ByteBuffers returned by an earlier
- * {@code Plane#getBuffer} call will have undefined behavior.
+ * Free up this frame for reuse.
+ * <p>
+ * After calling this method, calling any methods on this {@code Image} will
+ * result in an {@link IllegalStateException}, and attempting to read from
+ * {@link ByteBuffer ByteBuffers} returned by an earlier
+ * {@link Plane#getBuffer} call will have undefined behavior.
+ * </p>
*/
- public void close();
+ @Override
+ public abstract void close();
/**
* <p>A single color plane of image data.</p>
@@ -134,29 +150,41 @@
*
* @see #getFormat
*/
- public interface Plane {
+ public static abstract class Plane {
/**
- * <p>The row stride for this color plane, in bytes.
+ * @hide
+ */
+ protected Plane() {
+ }
+
+ /**
+ * <p>The row stride for this color plane, in bytes.</p>
*
* <p>This is the distance between the start of two consecutive rows of
- * pixels in the image.</p>
+ * pixels in the image. The row stride is always greater than 0.</p>
*/
- public int getRowStride();
+ public abstract int getRowStride();
/**
* <p>The distance between adjacent pixel samples, in bytes.</p>
*
* <p>This is the distance between two consecutive pixel values in a row
* of pixels. It may be larger than the size of a single pixel to
- * account for interleaved image data or padded formats.</p>
+ * account for interleaved image data or padded formats.
+ * The pixel stride is always greater than 0.</p>
*/
- public int getPixelStride();
+ public abstract int getPixelStride();
/**
- * <p>Get a set of direct {@link java.nio.ByteBuffer byte buffers}
+ * <p>Get a direct {@link java.nio.ByteBuffer ByteBuffer}
* containing the frame data.</p>
*
+ * <p>In particular, the buffer returned will always have
+ * {@link java.nio.ByteBuffer#isDirect isDirect} return {@code true}, so
+ * the underlying data could be mapped as a pointer in JNI without doing
+ * any copies with {@code GetDirectBufferAddress}.</p>
+ *
* @return the byte buffer containing the image data for this plane.
*/
- public ByteBuffer getBuffer();
+ public abstract ByteBuffer getBuffer();
}
}
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index b14a899..aee8362 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -40,41 +40,67 @@
* <p>The image data is encapsulated in {@link Image} objects, and multiple such
* objects can be accessed at the same time, up to the number specified by the
* {@code maxImages} constructor parameter. New images sent to an ImageReader
- * through its Surface are queued until accessed through the
- * {@link #getNextImage} call. Due to memory limits, an image source will
+ * through its {@link Surface} are queued until accessed through the {@link #acquireLatestImage}
+ * or {@link #acquireNextImage} call. Due to memory limits, an image source will
* eventually stall or drop Images in trying to render to the Surface if the
* ImageReader does not obtain and release Images at a rate equal to the
* production rate.</p>
*/
-public final class ImageReader implements AutoCloseable {
+public class ImageReader implements AutoCloseable {
+
+ /**
+ * Returned by nativeImageSetup when acquiring the image was successful.
+ */
+ private static final int ACQUIRE_SUCCESS = 0;
+ /**
+ * Returned by nativeImageSetup when we couldn't acquire the buffer,
+ * because there were no buffers available to acquire.
+ */
+ private static final int ACQUIRE_NO_BUFS = 1;
+ /**
+ * Returned by nativeImageSetup when we couldn't acquire the buffer
+ * because the consumer has already acquired {@maxImages} and cannot
+ * acquire more than that.
+ */
+ private static final int ACQUIRE_MAX_IMAGES = 2;
/**
* <p>Create a new reader for images of the desired size and format.</p>
*
- * <p>The maxImages parameter determines the maximum number of {@link Image}
- * objects that can be be acquired from the ImageReader
+ * <p>The {@code maxImages} parameter determines the maximum number of {@link Image}
+ * objects that can be be acquired from the {@code ImageReader}
* simultaneously. Requesting more buffers will use up more memory, so it is
* important to use only the minimum number necessary for the use case.</p>
*
* <p>The valid sizes and formats depend on the source of the image
* data.</p>
*
- * @param width the width in pixels of the Images that this reader will
- * produce.
- * @param height the height in pixels of the Images that this reader will
- * produce.
- * @param format the format of the Image that this reader will produce. This
- * must be one of the {@link android.graphics.ImageFormat} or
- * {@link android.graphics.PixelFormat} constants.
- * @param maxImages the maximum number of images the user will want to
- * access simultaneously. This should be as small as possible to limit
- * memory use. Once maxImages Images are obtained by the user, one of them
- * has to be released before a new Image will become available for access
- * through getNextImage(). Must be greater than 0.
+ * @param width
+ * The width in pixels of the Images that this reader will produce.
+ * @param height
+ * The height in pixels of the Images that this reader will produce.
+ * @param format
+ * The format of the Image that this reader will produce. This
+ * must be one of the {@link android.graphics.ImageFormat} or
+ * {@link android.graphics.PixelFormat} constants.
+ * @param maxImages
+ * The maximum number of images the user will want to
+ * access simultaneously. This should be as small as possible to limit
+ * memory use. Once maxImages Images are obtained by the user, one of them
+ * has to be released before a new Image will become available for access
+ * through {@link #acquireLatestImage()} or {@link #acquireNextImage()}.
+ * Must be greater than 0.
*
* @see Image
*/
- public ImageReader(int width, int height, int format, int maxImages) {
+ public static ImageReader newInstance(int width, int height, int format, int maxImages) {
+ return new ImageReader(width, height, format, maxImages);
+ }
+
+ /**
+ * @hide
+ */
+ protected ImageReader(int width, int height, int format, int maxImages) {
mWidth = width;
mHeight = height;
mFormat = format;
@@ -96,33 +122,79 @@
mSurface = nativeGetSurface();
}
+ /**
+ * The width of each {@link Image}, in pixels.
+ *
+ * <p>ImageReader guarantees that all Images acquired from ImageReader (for example, with
+ * {@link #acquireNextImage}) will have the same dimensions as specified in
+ * {@link #newInstance}.</p>
+ *
+ * @return the width of an Image
+ */
public int getWidth() {
return mWidth;
}
+ /**
+ * The height of each {@link Image}, in pixels.
+ *
+ * <p>ImageReader guarantees that all Images acquired from ImageReader (for example, with
+ * {@link #acquireNextImage}) will have the same dimensions as specified in
+ * {@link #newInstance}.</p>
+ *
+ * @return the height of an Image
+ */
public int getHeight() {
return mHeight;
}
+ /**
+ * The {@link ImageFormat image format} of each Image.
+ *
+ * <p>ImageReader guarantees that all {@link Image Images} acquired from ImageReader
+ * (for example, with {@link #acquireNextImage}) will have the same format as specified in
+ * {@link #newInstance}.</p>
+ *
+ * @return the format of an Image
+ *
+ * @see ImageFormat
+ */
public int getImageFormat() {
return mFormat;
}
+ /**
+ * Maximum number of images that can be acquired from the ImageReader by any time (for example,
+ * with {@link #acquireNextImage}).
+ *
+ * <p>An image is considered acquired after it's returned by a function from ImageReader, and
+ * until the Image is {@link Image#close closed} to release the image back to the ImageReader.
+ * </p>
+ *
+ * <p>Attempting to acquire more than {@code maxImages} concurrently will result in the
+ * acquire function throwing a {@link IllegalStateException}. Furthermore,
+ * while the max number of images have been acquired by the ImageReader user, the producer
+ * enqueueing additional images may stall until at least one image has been released. </p>
+ *
+ * @return Maximum number of images for this ImageReader.
+ *
+ * @see Image#close
+ */
public int getMaxImages() {
return mMaxImages;
}
/**
- * <p>Get a Surface that can be used to produce Images for this
- * ImageReader.</p>
+ * <p>Get a {@link Surface} that can be used to produce {@link Image Images} for this
+ * {@code ImageReader}.</p>
*
- * <p>Until valid image data is rendered into this Surface, the
- * {@link #getNextImage} method will return {@code null}. Only one source
+ * <p>Until valid image data is rendered into this {@link Surface}, the
+ * {@link #acquireNextImage} method will return {@code null}. Only one source
* can be producing data into this Surface at the same time, although the
- * same Surface can be reused with a different API once the first source is
- * disconnected from the Surface.</p>
+ * same {@link Surface} can be reused with a different API once the first source is
+ * disconnected from the {@link Surface}.</p>
*
- * @return A Surface to use for a drawing target for various APIs.
+ * @return A {@link Surface} to use for a drawing target for various APIs.
*/
public Surface getSurface() {
return mSurface;
@@ -130,41 +202,154 @@
/**
* <p>
- * Get the next Image from the ImageReader's queue. Returns {@code null} if
- * no new image is available.
+ * Acquire the latest {@link Image} from the ImageReader's queue, dropping older
+ * {@link Image images}. Returns {@code null} if no new image is available.
* </p>
* <p>
- * This operation will fail by throwing an
- * {@link Surface.OutOfResourcesException OutOfResourcesException} if too
- * many images have been acquired with {@link #getNextImage}. In particular
- * a sequence of {@link #getNextImage} calls greater than {@link #getMaxImages}
- * without calling {@link Image#close} or {@link #releaseImage} in-between
- * will exhaust the underlying queue. At such a time,
- * {@link Surface.OutOfResourcesException OutOfResourcesException} will be
- * thrown until more images are released with {@link Image#close} or
- * {@link #releaseImage}.
+ * This operation will acquire all the images possible from the ImageReader,
+ * but {@link #close} all images that aren't the latest. This function is
+ * recommended to use over {@link #acquireNextImage} for most use-cases, as it's
+ * more suited for real-time processing.
+ * </p>
+ * <p>
+ * Note that {@link #getMaxImages maxImages} should be at least 2 for
+ * {@link #acquireLatestImage} to be any different than {@link #acquireNextImage} -
+ * discarding all-but-the-newest {@link Image} requires temporarily acquiring two
+ * {@link Image Images} at once. Or more generally, calling {@link #acquireLatestImage}
+ * with less than two images of margin, that is
+ * {@code (maxImages - currentAcquiredImages < 2)} will not discard as expected.
+ * </p>
+ * <p>
+ * This operation will fail by throwing an {@link IllegalStateException} if
+ * {@code maxImages} have been acquired with {@link #acquireLatestImage} or
+ * {@link #acquireNextImage}. In particular a sequence of {@link #acquireLatestImage}
+ * calls greater than {@link #getMaxImages} without calling {@link Image#close} in-between
+ * will exhaust the underlying queue. At such a time, {@link IllegalStateException}
+ * will be thrown until more images are
+ * released with {@link Image#close}.
* </p>
*
- * @return a new frame of image data, or {@code null} if no image data is
- * available.
- * @throws Surface.OutOfResourcesException if too many images are currently
- * acquired
+ * @return latest frame of image data, or {@code null} if no image data is available.
+ * @throws IllegalStateException if too many images are currently acquired
*/
- public Image getNextImage() {
- SurfaceImage si = new SurfaceImage();
- if (nativeImageSetup(si)) {
- // create SurfacePlane objects
- si.createSurfacePlanes();
- si.setImageValid(true);
- return si;
+ public Image acquireLatestImage() {
+ Image image = acquireNextImage();
+ if (image == null) {
+ return null;
}
- return null;
+ try {
+ for (;;) {
+ Image next = acquireNextImageNoThrowISE();
+ if (next == null) {
+ Image result = image;
+ image = null;
+ return result;
+ }
+ image.close();
+ image = next;
+ }
+ } finally {
+ if (image != null) {
+ image.close();
+ }
+ }
+ }
+
+ /**
+ * Don't throw IllegalStateException if there are too many images acquired.
+ *
+ * @return Image if acquiring succeeded, or null otherwise.
+ *
+ * @hide
+ */
+ public Image acquireNextImageNoThrowISE() {
+ SurfaceImage si = new SurfaceImage();
+ return acquireNextSurfaceImage(si) == ACQUIRE_SUCCESS ? si : null;
+ }
+
+ /**
+ * Attempts to acquire the next image from the underlying native implementation.
+ *
+ * <p>
+ * Note that unexpected failures will throw at the JNI level.
+ * </p>
+ *
+ * @param si A blank SurfaceImage.
+ * @return One of the {@code ACQUIRE_*} codes that determine success or failure.
+ *
+ * @see #ACQUIRE_MAX_IMAGES
+ * @see #ACQUIRE_NO_BUFS
+ * @see #ACQUIRE_SUCCESS
+ */
+ private int acquireNextSurfaceImage(SurfaceImage si) {
+
+ int status = nativeImageSetup(si);
+
+ switch (status) {
+ case ACQUIRE_SUCCESS:
+ si.createSurfacePlanes();
+ si.setImageValid(true);
+ case ACQUIRE_NO_BUFS:
+ case ACQUIRE_MAX_IMAGES:
+ break;
+ default:
+ throw new AssertionError("Unknown nativeImageSetup return code " + status);
+ }
+
+ return status;
+ }
+
+ /**
+ * <p>
+ * Acquire the next Image from the ImageReader's queue. Returns {@code null} if
+ * no new image is available.
+ * </p>
+ *
+ * <p><i>Warning:</i> Consider using {@link #acquireLatestImage()} instead, as it will
+ * automatically release older images, and allow slower-running processing routines to catch
+ * up to the newest frame. Usage of {@link #acquireNextImage} is recommended for
+ * batch/background processing. Incorrectly using this function can cause images to appear
+ * with an ever-increasing delay, followed by a complete stall where no new images seem to
+ * appear.
+ * </p>
+ *
+ * <p>
+ * This operation will fail by throwing an {@link IllegalStateException} if
+ * {@code maxImages} have been acquired with {@link #acquireNextImage} or
+ * {@link #acquireLatestImage}. In particular a sequence of {@link #acquireNextImage} or
+ * {@link #acquireLatestImage} calls greater than {@link #getMaxImages maxImages} without
+ * calling {@link Image#close} in-between will exhaust the underlying queue. At such a time,
+ * {@link IllegalStateException} will be thrown until more images are released with
+ * {@link Image#close}.
+ * </p>
+ *
+ * @return a new frame of image data, or {@code null} if no image data is available.
+ * @throws IllegalStateException if {@code maxImages} images are currently acquired
+ * @see #acquireLatestImage
+ */
+ public Image acquireNextImage() {
+ SurfaceImage si = new SurfaceImage();
+ int status = acquireNextSurfaceImage(si);
+
+ switch (status) {
+ case ACQUIRE_SUCCESS:
+ return si;
+ case ACQUIRE_NO_BUFS:
+ return null;
+ case ACQUIRE_MAX_IMAGES:
+ throw new IllegalStateException(
+ String.format(
+ "maxImages (%d) has already been acquired, " +
+ "call #close before acquiring more.", mMaxImages));
+ default:
+ throw new AssertionError("Unknown nativeImageSetup return code " + status);
+ }
}
/**
* <p>Return the frame to the ImageReader for reuse.</p>
*/
- public void releaseImage(Image i) {
+ private void releaseImage(Image i) {
if (! (i instanceof SurfaceImage) ) {
throw new IllegalArgumentException(
"This image was not produced by an ImageReader");
@@ -183,13 +368,16 @@
/**
* Register a listener to be invoked when a new image becomes available
* from the ImageReader.
- * @param listener the listener that will be run
- * @param handler The handler on which the listener should be invoked, or null
- * if the listener should be invoked on the calling thread's looper.
*
- * @throws IllegalArgumentException if no handler specified and the calling thread has no looper
+ * @param listener
+ * The listener that will be run.
+ * @param handler
+ * The handler on which the listener should be invoked, or null
+ * if the listener should be invoked on the calling thread's looper.
+ * @throws IllegalArgumentException
+ * If no handler specified and the calling thread has no looper.
*/
- public void setImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
+ public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
mImageListener = listener;
Looper looper;
@@ -206,12 +394,16 @@
/**
* Callback interface for being notified that a new image is available.
+ *
+ * <p>
* The onImageAvailable is called per image basis, that is, callback fires for every new frame
* available from ImageReader.
+ * </p>
*/
public interface OnImageAvailableListener {
/**
* Callback that is called when a new image is available from ImageReader.
+ *
* @param reader the ImageReader the callback is associated with.
* @see ImageReader
* @see Image
@@ -220,12 +412,17 @@
}
/**
- * Free up all the resources associated with this ImageReader. After
- * Calling this method, this ImageReader can not be used. calling
- * any methods on this ImageReader and Images previously provided by {@link #getNextImage}
- * will result in an IllegalStateException, and attempting to read from
- * ByteBuffers returned by an earlier {@code Plane#getBuffer} call will
+ * Free up all the resources associated with this ImageReader.
+ *
+ * <p>
+ * After calling this method, this ImageReader can not be used. Calling
+ * any methods on this ImageReader and Images previously provided by
+ * {@link #acquireNextImage} or {@link #acquireLatestImage}
+ * will result in an {@link IllegalStateException}, and attempting to read from
+ * {@link ByteBuffer ByteBuffers} returned by an earlier
+ * {@link Image.Plane#getBuffer Plane#getBuffer} call will
* have undefined behavior.
+ * </p>
*/
@Override
public void close() {
@@ -242,11 +439,14 @@
}
/**
- * Only a subset of the formats defined in {@link android.graphics.ImageFormat} and
- * {@link android.graphics.PixelFormat} are supported by ImageReader. When reading RGB
- * data from a surface, the formats defined in {@link android.graphics.PixelFormat}
- * can be used, when reading YUV, JPEG or raw sensor data ( for example, from camera
- * or video decoder), formats from {@link android.graphics.ImageFormat} are used.
+ * Only a subset of the formats defined in
+ * {@link android.graphics.ImageFormat ImageFormat} and
+ * {@link android.graphics.PixelFormat PixelFormat} are supported by
+ * ImageReader. When reading RGB data from a surface, the formats defined in
+ * {@link android.graphics.PixelFormat PixelFormat} can be used, when
+ * reading YUV, JPEG or raw sensor data (for example, from camera or video
+ * decoder), formats from {@link android.graphics.ImageFormat ImageFormat}
+ * are used.
*/
private int getNumPlanesFromFormat() {
switch (mFormat) {
@@ -308,7 +508,7 @@
*/
private long mNativeContext;
- private class SurfaceImage implements android.media.Image {
+ private class SurfaceImage extends android.media.Image {
public SurfaceImage() {
mIsImageValid = false;
}
@@ -404,7 +604,7 @@
mPlanes[i] = nativeCreatePlane(i);
}
}
- private class SurfacePlane implements android.media.Image.Plane {
+ private class SurfacePlane extends android.media.Image.Plane {
// SurfacePlane instance is created by native code when a new SurfaceImage is created
private SurfacePlane(int index, int rowStride, int pixelStride) {
mIndex = index;
@@ -479,9 +679,17 @@
private synchronized native void nativeClose();
private synchronized native void nativeReleaseImage(Image i);
private synchronized native Surface nativeGetSurface();
- private synchronized native boolean nativeImageSetup(Image i);
- /*
+ /**
+ * @return A return code {@code ACQUIRE_*}
+ *
+ * @see #ACQUIRE_SUCCESS
+ * @see #ACQUIRE_NO_BUFS
+ * @see #ACQUIRE_MAX_IMAGES
+ */
+ private synchronized native int nativeImageSetup(Image i);
+
+ /**
* We use a class initializer to allow the native code to cache some
* field offsets.
*/
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index f4e867e..1250cbc 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -294,6 +294,9 @@
*/
public native final void flush();
+ /**
+ * Thrown when a crypto error occurs while queueing a secure input buffer.
+ */
public final static class CryptoException extends RuntimeException {
public CryptoException(int errorCode, String detailMessage) {
super(detailMessage);
@@ -318,6 +321,9 @@
*/
public static final int ERROR_RESOURCE_BUSY = 3;
+ /**
+ * Retrieve the error code associated with a CryptoException
+ */
public int getErrorCode() {
return mErrorCode;
}
@@ -449,6 +455,9 @@
* @param presentationTimeUs The time at which this buffer should be rendered.
* @param flags A bitmask of flags {@link #BUFFER_FLAG_SYNC_FRAME},
* {@link #BUFFER_FLAG_CODEC_CONFIG} or {@link #BUFFER_FLAG_END_OF_STREAM}.
+ * @throws CryptoException if an error occurs while attempting to decrypt the buffer.
+ * An error code associated with the exception helps identify the
+ * reason for the failure.
*/
public native final void queueSecureInputBuffer(
int index,
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index ab686e6..34dc580 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -2093,8 +2093,11 @@
if ((mCurrentRcClient != null) && (mCurrentRcClientGen == genId)) {
try {
switch (key) {
- case RemoteControlClient.MetadataEditor.LONG_KEY_RATING_BY_USER:
- mCurrentRcClient.updateMetadata(genId, key, value);
+ case RemoteControlClient.MetadataEditor.RATING_KEY_BY_USER:
+ // TODO handle rating update, placeholder code here that sends
+ // an unrated percent-based rating
+ mCurrentRcClient.updateMetadata(genId, key,
+ Rating.newUnratedRating(Rating.RATING_PERCENTAGE));
break;
default:
Log.e(TAG, "unhandled metadata key " + key + " update for RCC "
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 949a42c..16ae43d 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -44,9 +44,19 @@
* for encoders, readable in the output format of decoders</b></td></tr>
* <tr><td>{@link #KEY_FRAME_RATE}</td><td>Integer or Float</td><td><b>encoder-only</b></td></tr>
* <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>{@link #KEY_MAX_WIDTH}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution width</td></tr>
+ * <tr><td>{@link #KEY_MAX_HEIGHT}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution height</td></tr>
* <tr><td>{@link #KEY_REPEAT_PREVIOUS_FRAME_AFTER}</td><td>Long</td><td><b>video encoder in surface-mode only</b></td></tr>
* <tr><td>{@link #KEY_PUSH_BLANK_BUFFERS_ON_STOP}</td><td>Integer(1)</td><td><b>video decoder rendering to a surface only</b></td></tr>
* </table>
+ * Specify both {@link #KEY_MAX_WIDTH} and {@link #KEY_MAX_HEIGHT} to enable
+ * adaptive playback (seamless resolution change) for a video decoder that
+ * supports it ({@link MediaCodecInfo.CodecCapabilities#FEATURE_AdaptivePlayback}).
+ * The values are used as hints for the codec: they are the maximum expected
+ * resolution to prepare for. Depending on codec support, preparing for larger
+ * maximum resolution may require more memory even if that resolution is never
+ * reached. These fields have no effect for codecs that do not support adaptive
+ * playback.<br /><br />
*
* Audio formats have the following keys:
* <table>
@@ -104,6 +114,20 @@
*/
public static final String KEY_HEIGHT = "height";
+ /**
+ * A key describing the maximum expected width of the content in a video
+ * decoder format, in case there are resolution changes in the video content.
+ * The associated value is an integer
+ */
+ public static final String KEY_MAX_WIDTH = "max-width";
+
+ /**
+ * A key describing the maximum expected height of the content in a video
+ * decoder format, in case there are resolution changes in the video content.
+ * The associated value is an integer
+ */
+ public static final String KEY_MAX_HEIGHT = "max-height";
+
/** A key describing the maximum size in bytes of a buffer of data
* described by this MediaFormat.
* The associated value is an integer
@@ -197,6 +221,28 @@
*/
public static final String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
+ /**
+ * A key for boolean AUTOSELECT field. Tracks with AUTOSELECT=true are
+ * considered when automatically selecting a track without specific user
+ * choice (as defined by HLS).
+ * @hide
+ */
+ public static final String KEY_AUTOSELECT = "autoselect";
+
+ /**
+ * A key for boolean DEFAULT field. The track with DEFAULT=true is selected
+ * in the absence of a specific user choice (as defined by HLS).
+ * @hide
+ */
+ public static final String KEY_DEFAULT = "default";
+
+ /**
+ * A key for boolean FORCED field for subtitle tracks. True if it is a
+ * forced subtitle track.
+ * @hide
+ */
+ public static final String KEY_FORCED = "forced";
+
/* package private */ MediaFormat(Map<String, Object> map) {
mMap = map;
}
@@ -227,6 +273,20 @@
}
/**
+ * Returns the value of an integer key, or the default value if the
+ * key is missing or is for another type value.
+ * @hide
+ */
+ public final int getInteger(String name, int defaultValue) {
+ try {
+ return getInteger(name);
+ }
+ catch (NullPointerException e) { /* no such field */ }
+ catch (ClassCastException e) { /* field of different type */ }
+ return defaultValue;
+ }
+
+ /**
* Returns the value of a long key.
*/
public final long getLong(String name) {
diff --git a/media/java/android/media/MediaMetadataEditor.java b/media/java/android/media/MediaMetadataEditor.java
new file mode 100644
index 0000000..b601016
--- /dev/null
+++ b/media/java/android/media/MediaMetadataEditor.java
@@ -0,0 +1,462 @@
+/*
+ * 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.media;
+
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+/**
+ * An abstract class for editing and storing metadata that can be published by
+ * {@link RemoteControlClient}. See the {@link RemoteControlClient#editMetadata(boolean)}
+ * method to instantiate a {@link RemoteControlClient.MetadataEditor} object.
+ */
+public abstract class MediaMetadataEditor {
+
+ private final static String TAG = "MediaMetadataEditor";
+ /**
+ * @hide
+ */
+ protected MediaMetadataEditor() {
+ }
+
+ // Public keys for metadata used by RemoteControlClient and RemoteController.
+ // Note that these keys are defined here, and not in MediaMetadataRetriever
+ // because they are not supported by the MediaMetadataRetriever features.
+ /**
+ * The metadata key for the content artwork / album art.
+ */
+ public final static int BITMAP_KEY_ARTWORK =
+ RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK;
+
+ /**
+ * The metadata key for the content's average rating, not the user's rating.
+ * The value associated with this key is a {@link Rating} instance.
+ * @see #RATING_KEY_BY_USER
+ */
+ public final static int RATING_KEY_BY_OTHERS = 101;
+
+ /**
+ * The metadata key for the content's user rating.
+ * The value associated with this key is a {@link Rating} instance.
+ * This key can be flagged as "editable" (with {@link #addEditableKey(int)}) to enable
+ * receiving user rating values through the
+ * {@link android.media.RemoteControlClient.OnMetadataUpdateListener} interface.
+ */
+ public final static int RATING_KEY_BY_USER = 0x10000001;
+
+ /**
+ * @hide
+ * Editable key mask
+ */
+ public final static int KEY_EDITABLE_MASK = 0x1FFFFFFF;
+
+
+ /**
+ * Applies all of the metadata changes that have been set since the MediaMetadataEditor instance
+ * was created or since {@link #clear()} was called.
+ */
+ public abstract void apply();
+
+
+ /**
+ * @hide
+ * Mask of editable keys.
+ */
+ protected long mEditableKeys;
+
+ /**
+ * @hide
+ */
+ protected boolean mMetadataChanged = false;
+
+ /**
+ * @hide
+ */
+ protected boolean mApplied = false;
+
+ /**
+ * @hide
+ */
+ protected boolean mArtworkChanged = false;
+
+ /**
+ * @hide
+ */
+ protected Bitmap mEditorArtwork;
+
+ /**
+ * @hide
+ */
+ protected Bundle mEditorMetadata;
+
+
+ /**
+ * Clears all the pending metadata changes set since the MediaMetadataEditor instance was
+ * created or since this method was last called.
+ * Note that clearing the metadata doesn't reset the editable keys
+ * (use {@link #removeEditableKeys()} instead).
+ */
+ public synchronized void clear() {
+ if (mApplied) {
+ Log.e(TAG, "Can't clear a previously applied MediaMetadataEditor");
+ return;
+ }
+ mEditorMetadata.clear();
+ mEditorArtwork = null;
+ }
+
+ /**
+ * Flags the given key as being editable.
+ * This should only be used by metadata publishers, such as {@link RemoteControlClient},
+ * which will declare the metadata field as eligible to be updated, with new values
+ * received through the {@link RemoteControlClient.OnMetadataUpdateListener} interface.
+ * @param key the type of metadata that can be edited. The supported key is
+ * {@link #RATING_KEY_BY_USER}.
+ */
+ public synchronized void addEditableKey(int key) {
+ if (mApplied) {
+ Log.e(TAG, "Can't change editable keys of a previously applied MetadataEditor");
+ return;
+ }
+ // only one editable key at the moment, so we're not wasting memory on an array
+ // of editable keys to check the validity of the key, just hardcode the supported key.
+ if (key == RATING_KEY_BY_USER) {
+ mEditableKeys |= (KEY_EDITABLE_MASK & key);
+ mMetadataChanged = true;
+ } else {
+ Log.e(TAG, "Metadata key " + key + " cannot be edited");
+ }
+ }
+
+ /**
+ * Causes all metadata fields to be read-only.
+ */
+ public synchronized void removeEditableKeys() {
+ if (mApplied) {
+ Log.e(TAG, "Can't remove all editable keys of a previously applied MetadataEditor");
+ return;
+ }
+ if (mEditableKeys != 0) {
+ mEditableKeys = 0;
+ mMetadataChanged = true;
+ }
+ }
+
+ /**
+ * Retrieves the keys flagged as editable.
+ * @return null if there are no editable keys, or an array containing the keys.
+ */
+ public synchronized int[] getEditableKeys() {
+ // only one editable key supported here
+ if (mEditableKeys == RATING_KEY_BY_USER) {
+ int[] keys = { RATING_KEY_BY_USER };
+ return keys;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Adds textual information.
+ * Note that none of the information added after {@link #apply()} has been called,
+ * will be available to consumers of metadata stored by the MediaMetadataEditor.
+ * @param key The identifier of a the metadata field to set. Valid values are
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
+ * @param value The text for the given key, or {@code null} to signify there is no valid
+ * information for the field.
+ * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+ * calls together.
+ */
+ public synchronized MediaMetadataEditor putString(int key, String value)
+ throws IllegalArgumentException {
+ if (mApplied) {
+ Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+ return this;
+ }
+ if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_STRING) {
+ throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
+ }
+ mEditorMetadata.putString(String.valueOf(key), value);
+ mMetadataChanged = true;
+ return this;
+ }
+
+ /**
+ * Adds numerical information.
+ * Note that none of the information added after {@link #apply()} has been called
+ * will be available to consumers of metadata stored by the MediaMetadataEditor.
+ * @param key the identifier of a the metadata field to set. Valid values are
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
+ * expressed in milliseconds),
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
+ * @param value The long value for the given key
+ * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+ * calls together.
+ * @throws IllegalArgumentException
+ */
+ public synchronized MediaMetadataEditor putLong(int key, long value)
+ throws IllegalArgumentException {
+ if (mApplied) {
+ Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+ return this;
+ }
+ if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_LONG) {
+ throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
+ }
+ mEditorMetadata.putLong(String.valueOf(key), value);
+ mMetadataChanged = true;
+ return this;
+ }
+
+ /**
+ * Adds image.
+ * @param key the identifier of the bitmap to set. The only valid value is
+ * {@link #BITMAP_KEY_ARTWORK}
+ * @param bitmap The bitmap for the artwork, or null if there isn't any.
+ * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+ * calls together.
+ * @throws IllegalArgumentException
+ * @see android.graphics.Bitmap
+ */
+ public synchronized MediaMetadataEditor putBitmap(int key, Bitmap bitmap)
+ throws IllegalArgumentException {
+ if (mApplied) {
+ Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+ return this;
+ }
+ if (key != BITMAP_KEY_ARTWORK) {
+ throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
+ }
+ mEditorArtwork = bitmap;
+ mArtworkChanged = true;
+ return this;
+ }
+
+ /**
+ * Adds information stored as an instance.
+ * Note that none of the information added after {@link #apply()} has been called
+ * will be available to consumers of metadata stored by the MediaMetadataEditor.
+ * @param key the identifier of a the metadata field to set. Valid keys for a:
+ * <ul>
+ * <li>{@link Bitmap} object are {@link #BITMAP_KEY_ARTWORK},</li>
+ * <li>{@link String} object are the same as for {@link #putString(int, String)}</li>
+ * <li>{@link Long} object are the same as for {@link #putLong(int, long)}</li>
+ * <li>{@link Rating} object are {@link #RATING_KEY_BY_OTHERS}
+ * and {@link #RATING_KEY_BY_USER}.</li>
+ * </ul>
+ * @param obj the metadata to add.
+ * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+ * calls together.
+ * @throws IllegalArgumentException
+ */
+ public synchronized MediaMetadataEditor putObject(int key, Object value)
+ throws IllegalArgumentException {
+ if (mApplied) {
+ Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+ return this;
+ }
+ switch(METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID)) {
+ case METADATA_TYPE_LONG:
+ if (value instanceof Long) {
+ return putLong(key, ((Long)value).longValue());
+ } else {
+ throw(new IllegalArgumentException("Not a non-null Long for key "+ key));
+ }
+ case METADATA_TYPE_STRING:
+ if ((value == null) || (value instanceof String)) {
+ return putString(key, (String) value);
+ } else {
+ throw(new IllegalArgumentException("Not a String for key "+ key));
+ }
+ case METADATA_TYPE_RATING:
+ mEditorMetadata.putParcelable(String.valueOf(key), (Parcelable)value);
+ mMetadataChanged = true;
+ break;
+ case METADATA_TYPE_BITMAP:
+ if ((value == null) || (value instanceof Bitmap)) {
+ return putBitmap(key, (Bitmap) value);
+ } else {
+ throw(new IllegalArgumentException("Not a Bitmap for key "+ key));
+ }
+ default:
+ throw(new IllegalArgumentException("Invalid key "+ key));
+ }
+ return this;
+ }
+
+
+ /**
+ * Returns the long value for the key.
+ * @param key one of the keys supported in {@link #putLong(int, long)}
+ * @param defaultValue the value returned if the key is not present
+ * @return the long value for the key, or the supplied default value if the key is not present
+ * @throws IllegalArgumentException
+ */
+ public synchronized long getLong(int key, long defaultValue)
+ throws IllegalArgumentException {
+ if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_LONG) {
+ throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
+ }
+ return mEditorMetadata.getLong(String.valueOf(key), defaultValue);
+ }
+
+ /**
+ * Returns the {@link String} value for the key.
+ * @param key one of the keys supported in {@link #putString(int, String)}
+ * @param defaultValue the value returned if the key is not present
+ * @return the {@link String} value for the key, or the supplied default value if the key is
+ * not present
+ * @throws IllegalArgumentException
+ */
+ public synchronized String getString(int key, String defaultValue)
+ throws IllegalArgumentException {
+ if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_STRING) {
+ throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
+ }
+ return mEditorMetadata.getString(String.valueOf(key), defaultValue);
+ }
+
+ /**
+ * Returns the {@link Bitmap} value for the key.
+ * @param key the {@link #BITMAP_KEY_ARTWORK} key
+ * @param defaultValue the value returned if the key is not present
+ * @return the {@link Bitmap} value for the key, or the supplied default value if the key is
+ * not present
+ * @throws IllegalArgumentException
+ */
+ public synchronized Bitmap getBitmap(int key, Bitmap defaultValue)
+ throws IllegalArgumentException {
+ if (key != BITMAP_KEY_ARTWORK) {
+ throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
+ }
+ return (mEditorArtwork != null ? mEditorArtwork : defaultValue);
+ }
+
+ /**
+ * Returns an object representation of the value for the key
+ * @param key one of the keys supported in {@link #putObject(int, Object)}
+ * @param defaultValue the value returned if the key is not present
+ * @return the object for the key, as a {@link Long}, {@link Bitmap}, {@link String}, or
+ * {@link Rating} depending on the key value, or the supplied default value if the key is
+ * not present
+ * @throws IllegalArgumentException
+ */
+ public synchronized Object getObject(int key, Object defaultValue)
+ throws IllegalArgumentException {
+ switch (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID)) {
+ case METADATA_TYPE_LONG:
+ if (mEditorMetadata.containsKey(String.valueOf(key))) {
+ return mEditorMetadata.getLong(String.valueOf(key));
+ } else {
+ return defaultValue;
+ }
+ case METADATA_TYPE_STRING:
+ if (mEditorMetadata.containsKey(String.valueOf(key))) {
+ return mEditorMetadata.getString(String.valueOf(key));
+ } else {
+ return defaultValue;
+ }
+ case METADATA_TYPE_RATING:
+ if (mEditorMetadata.containsKey(String.valueOf(key))) {
+ return mEditorMetadata.getParcelable(String.valueOf(key));
+ } else {
+ return defaultValue;
+ }
+ case METADATA_TYPE_BITMAP:
+ // only one key for Bitmap supported, value is not stored in mEditorMetadata Bundle
+ if (key == BITMAP_KEY_ARTWORK) {
+ return (mEditorArtwork != null ? mEditorArtwork : defaultValue);
+ } // else: fall through to invalid key handling
+ default:
+ throw(new IllegalArgumentException("Invalid key "+ key));
+ }
+ }
+
+
+ /**
+ * @hide
+ */
+ protected static final int METADATA_TYPE_INVALID = -1;
+ /**
+ * @hide
+ */
+ protected static final int METADATA_TYPE_LONG = 0;
+
+ /**
+ * @hide
+ */
+ protected static final int METADATA_TYPE_STRING = 1;
+
+ /**
+ * @hide
+ */
+ protected static final int METADATA_TYPE_BITMAP = 2;
+
+ /**
+ * @hide
+ */
+ protected static final int METADATA_TYPE_RATING = 3;
+
+ /**
+ * @hide
+ */
+ protected static final SparseIntArray METADATA_KEYS_TYPE;
+
+ static {
+ METADATA_KEYS_TYPE = new SparseIntArray(17);
+ // NOTE: if adding to the list below, make sure you increment the array initialization size
+ // keys with long values
+ METADATA_KEYS_TYPE.put(
+ MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER, METADATA_TYPE_LONG);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_TYPE_LONG);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_TYPE_LONG);
+ // keys with String values
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(
+ MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(
+ MediaMetadataRetriever.METADATA_KEY_COMPILATION, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_TYPE_STRING);
+ // keys with Bitmap values
+ METADATA_KEYS_TYPE.put(BITMAP_KEY_ARTWORK, METADATA_TYPE_BITMAP);
+ // keys with Rating values
+ METADATA_KEYS_TYPE.put(RATING_KEY_BY_OTHERS, METADATA_TYPE_RATING);
+ METADATA_KEYS_TYPE.put(RATING_KEY_BY_USER, METADATA_TYPE_RATING);
+ }
+}
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index 774964e..65a9308 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -92,6 +92,7 @@
Object[] values);
private static native void nativeSetOrientationHint(int nativeObject,
int degrees);
+ private static native void nativeSetLocation(int nativeObject, int latitude, int longitude);
private static native void nativeWriteSampleData(int nativeObject,
int trackIndex, ByteBuffer byteBuf,
int offset, int size, long presentationTimeUs, int flags);
@@ -165,6 +166,41 @@
}
/**
+ * Set and store the geodata (latitude and longitude) in the output file.
+ * This method should be called before {@link #start}. The geodata is stored
+ * in udta box if the output format is
+ * {@link OutputFormat#MUXER_OUTPUT_MPEG_4}, and is ignored for other output
+ * formats. The geodata is stored according to ISO-6709 standard.
+ *
+ * @param latitude Latitude in degrees. Its value must be in the range [-90,
+ * 90].
+ * @param longitude Longitude in degrees. Its value must be in the range
+ * [-180, 180].
+ * @throws IllegalArgumentException If the given latitude or longitude is out
+ * of range.
+ * @throws IllegalStateException If this method is called after {@link #start}.
+ */
+ public void setLocation(float latitude, float longitude) {
+ int latitudex10000 = (int) (latitude * 10000 + 0.5);
+ int longitudex10000 = (int) (longitude * 10000 + 0.5);
+
+ if (latitudex10000 > 900000 || latitudex10000 < -900000) {
+ String msg = "Latitude: " + latitude + " out of range.";
+ throw new IllegalArgumentException(msg);
+ }
+ if (longitudex10000 > 1800000 || longitudex10000 < -1800000) {
+ String msg = "Longitude: " + longitude + " out of range";
+ throw new IllegalArgumentException(msg);
+ }
+
+ if (mState == MUXER_STATE_INITIALIZED && mNativeObject != 0) {
+ nativeSetLocation(mNativeObject, latitudex10000, longitudex10000);
+ } else {
+ throw new IllegalStateException("Can't set location due to wrong state.");
+ }
+ }
+
+ /**
* Starts the muxer.
* <p>Make sure this is called after {@link #addTrack} and before
* {@link #writeSampleData}.</p>
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index ce1896a..7acf8af 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1578,7 +1578,8 @@
* unknown or could not be determined, null is returned.
*/
public MediaFormat getFormat() {
- if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
+ if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT
+ || mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
return mFormat;
}
return null;
@@ -1602,6 +1603,12 @@
if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
mFormat = MediaFormat.createSubtitleFormat(
MEDIA_MIMETYPE_TEXT_SUBRIP, language);
+ } else if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
+ mFormat = MediaFormat.createSubtitleFormat(
+ MEDIA_MIMETYPE_TEXT_VTT, language);
+ mFormat.setInteger(MediaFormat.KEY_AUTOSELECT, in.readInt());
+ mFormat.setInteger(MediaFormat.KEY_DEFAULT, in.readInt());
+ mFormat.setInteger(MediaFormat.KEY_FORCED, in.readInt());
} else {
mFormat = new MediaFormat();
mFormat.setString(MediaFormat.KEY_LANGUAGE, language);
@@ -1629,6 +1636,12 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mTrackType);
dest.writeString(getLanguage());
+
+ if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
+ dest.writeInt(mFormat.getInteger(MediaFormat.KEY_AUTOSELECT));
+ dest.writeInt(mFormat.getInteger(MediaFormat.KEY_DEFAULT));
+ dest.writeInt(mFormat.getInteger(MediaFormat.KEY_FORCED));
+ }
}
/**
@@ -1693,6 +1706,12 @@
*/
public static final String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+ /**
+ * MIME type for WebVTT subtitle data.
+ * @hide
+ */
+ public static final String MEDIA_MIMETYPE_TEXT_VTT = "text/vtt";
+
/*
* A helper function to check if the mime type is supported by media framework.
*/
@@ -1800,8 +1819,6 @@
scanner.close();
mOutOfBandSubtitleTracks.add(track);
track.onData(contents, true /* eos */, ~0 /* runID: keep forever */);
- // update default track selection
- mSubtitleController.selectDefaultTrack();
return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
}
@@ -1829,9 +1846,8 @@
if (i < mInbandSubtitleTracks.length) {
inbandTracks[i] = mInbandSubtitleTracks[i];
} else {
- MediaFormat format = MediaFormat.createSubtitleFormat(
- "text/vtt", tracks[i].getLanguage());
- SubtitleTrack track = mSubtitleController.addTrack(format);
+ SubtitleTrack track = mSubtitleController.addTrack(
+ tracks[i].getFormat());
inbandTracks[i] = track;
}
}
@@ -2214,9 +2230,12 @@
break;
case MEDIA_INFO_METADATA_UPDATE:
scanInternalSubtitleTracks();
- break;
+ // fall through
+
case MEDIA_INFO_EXTERNAL_METADATA_UPDATE:
msg.arg1 = MEDIA_INFO_METADATA_UPDATE;
+ // update default track selection
+ mSubtitleController.selectDefaultTrack();
break;
}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 1d2b889..8dcbd6b 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -200,6 +200,19 @@
* </p>
*/
public static final int REMOTE_SUBMIX = 8;
+
+ /**
+ * Audio source for preemptible, low-priority software hotword detection
+ * It presents the same gain and pre processing tuning as {@link #VOICE_RECOGNITION}.
+ * <p>
+ * An application should use this audio source when it wishes to do
+ * always-on software hotword detection, while gracefully giving in to any other application
+ * that might want to read from the microphone.
+ * </p>
+ * This is a hidden audio source.
+ * @hide
+ */
+ protected static final int HOTWORD = 1999;
}
/**
diff --git a/core/java/android/hardware/camera2/CameraMetadata.aidl b/media/java/android/media/Rating.aidl
similarity index 88%
copy from core/java/android/hardware/camera2/CameraMetadata.aidl
copy to media/java/android/media/Rating.aidl
index 71dd471..1dc336a 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.aidl
+++ b/media/java/android/media/Rating.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.media;
-/** @hide */
-parcelable CameraMetadata;
+parcelable Rating;
diff --git a/media/java/android/media/Rating.java b/media/java/android/media/Rating.java
new file mode 100644
index 0000000..48443ff
--- /dev/null
+++ b/media/java/android/media/Rating.java
@@ -0,0 +1,274 @@
+/*
+ * 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.media;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * A class to encapsulate rating information used as content metadata.
+ * A rating is defined by its rating style (see {@link #RATING_HEART},
+ * {@link #RATING_THUMB_UP_DOWN}, {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
+ * {@link #RATING_5_STARS} or {@link #RATING_PERCENTAGE}) and the actual rating value (which may
+ * be defined as "unrated"), both of which are defined when the rating instance is constructed
+ * through one of the factory methods.
+ */
+public final class Rating implements Parcelable {
+
+ private final static String TAG = "Rating";
+
+ /**
+ * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to
+ * indicate the content referred to is a favorite (or not).
+ */
+ public final static int RATING_HEART = 1;
+
+ /**
+ * A rating style for "thumb up" vs "thumb down".
+ */
+ public final static int RATING_THUMB_UP_DOWN = 2;
+
+ /**
+ * A rating style with 0 to 3 stars.
+ */
+ public final static int RATING_3_STARS = 3;
+
+ /**
+ * A rating style with 0 to 4 stars.
+ */
+ public final static int RATING_4_STARS = 4;
+
+ /**
+ * A rating style with 0 to 5 stars.
+ */
+ public final static int RATING_5_STARS = 5;
+
+ /**
+ * A rating style expressed as a percentage.
+ */
+ public final static int RATING_PERCENTAGE = 6;
+
+ private final static float RATING_NOT_RATED = -1.0f;
+
+ private final int mRatingStyle;
+
+ private final float mRatingValue;
+
+ private Rating(int ratingStyle, float rating) {
+ mRatingStyle = ratingStyle;
+ mRatingValue = rating;
+ }
+
+ @Override
+ public int describeContents() {
+ return mRatingStyle;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mRatingStyle);
+ dest.writeFloat(mRatingValue);
+ }
+
+ public static final Parcelable.Creator<Rating> CREATOR
+ = new Parcelable.Creator<Rating>() {
+ /**
+ * Rebuilds a Rating previously stored with writeToParcel().
+ * @param p Parcel object to read the Rating from
+ * @return a new Rating created from the data in the parcel
+ */
+ public Rating createFromParcel(Parcel p) {
+ return new Rating(p.readInt(), p.readFloat());
+ }
+ public Rating[] newArray(int size) {
+ return new Rating[size];
+ }
+ };
+
+ /**
+ * Return a Rating instance with no rating.
+ * Create and return a new Rating instance with no rating known for the given
+ * rating style.
+ * @param ratingStyle one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
+ * {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
+ * or {@link #RATING_PERCENTAGE}.
+ * @return null if an invalid rating style is passed, a new Rating instance otherwise.
+ */
+ public static Rating newUnratedRating(int ratingStyle) {
+ switch(ratingStyle) {
+ case RATING_HEART:
+ case RATING_THUMB_UP_DOWN:
+ case RATING_3_STARS:
+ case RATING_4_STARS:
+ case RATING_5_STARS:
+ case RATING_PERCENTAGE:
+ return new Rating(ratingStyle, RATING_NOT_RATED);
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Return a Rating instance with a heart-based rating.
+ * Create and return a new Rating instance with a rating style of {@link #RATING_HEART},
+ * and a heart-based rating.
+ * @param hasHeart true for a "heart selected" rating, false for "heart unselected".
+ * @return a new Rating instance.
+ */
+ public static Rating newHeartRating(boolean hasHeart) {
+ return new Rating(RATING_HEART, hasHeart ? 1.0f : 0.0f);
+ }
+
+ /**
+ * Return a Rating instance with a thumb-based rating.
+ * Create and return a new Rating instance with a {@link #RATING_THUMB_UP_DOWN}
+ * rating style, and a "thumb up" or "thumb down" rating.
+ * @param thumbIsUp true for a "thumb up" rating, false for "thumb down".
+ * @return a new Rating instance.
+ */
+ public static Rating newThumbRating(boolean thumbIsUp) {
+ return new Rating(RATING_THUMB_UP_DOWN, thumbIsUp ? 1.0f : 0.0f);
+ }
+
+ /**
+ * Return a Rating instance with a star-based rating.
+ * Create and return a new Rating instance with one of the star-base rating styles
+ * and the given integer or fractional number of stars. Non integer values can for instance
+ * be used to represent an average rating value, which might not be an integer number of stars.
+ * @param starRatingStyle one of {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
+ * {@link #RATING_5_STARS}.
+ * @param starRating a number ranging from 0.0f to 3.0f, 4.0f or 5.0f according to
+ * the rating style.
+ * @return null if the rating style is invalid, or the rating is out of range,
+ * a new Rating instance otherwise.
+ */
+ public static Rating newStarRating(int starRatingStyle, float starRating) {
+ float maxRating = -1.0f;
+ switch(starRatingStyle) {
+ case RATING_3_STARS:
+ maxRating = 3.0f;
+ break;
+ case RATING_4_STARS:
+ maxRating = 4.0f;
+ break;
+ case RATING_5_STARS:
+ maxRating = 5.0f;
+ break;
+ default:
+ Log.e(TAG, "Invalid rating style (" + starRatingStyle + ") for a star rating");
+ return null;
+ }
+ if ((starRating < 0.0f) || (starRating > maxRating)) {
+ Log.e(TAG, "Trying to set out of range star-based rating");
+ return null;
+ }
+ return new Rating(starRatingStyle, starRating);
+ }
+
+ /**
+ * Return a Rating instance with a percentage-based rating.
+ * Create and return a new Rating instance with a {@link #RATING_PERCENTAGE}
+ * rating style, and a rating of the given percentage.
+ * @param percent the value of the rating
+ * @return null if the rating is out of range, a new Rating instance otherwise.
+ */
+ public static Rating newPercentageRating(float percent) {
+ if ((percent < 0.0f) || (percent > 100.0f)) {
+ Log.e(TAG, "Invalid percentage-based rating value");
+ return null;
+ } else {
+ return new Rating(RATING_PERCENTAGE, percent);
+ }
+ }
+
+ /**
+ * Return whether there is a rating value available.
+ * @return true if the instance was not created with {@link #newUnratedRating(int)}.
+ */
+ public boolean isRated() {
+ return mRatingValue >= 0.0f;
+ }
+
+ /**
+ * Return the rating style.
+ * @return one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
+ * {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
+ * or {@link #RATING_PERCENTAGE}.
+ */
+ public int getRatingStyle() {
+ return mRatingStyle;
+ }
+
+ /**
+ * Return whether the rating is "heart selected".
+ * @return true if the rating is "heart selected", false if the rating is "heart unselected",
+ * if the rating style is not {@link #RATING_HEART} or if it is unrated.
+ */
+ public boolean hasHeart() {
+ if (mRatingStyle != RATING_HEART) {
+ return false;
+ } else {
+ return (mRatingValue == 1.0f);
+ }
+ }
+
+ /**
+ * Return whether the rating is "thumb up".
+ * @return true if the rating is "thumb up", false if the rating is "thumb down",
+ * if the rating style is not {@link #RATING_THUMB_UP_DOWN} or if it is unrated.
+ */
+ public boolean isThumbUp() {
+ if (mRatingStyle != RATING_THUMB_UP_DOWN) {
+ return false;
+ } else {
+ return (mRatingValue == 1.0f);
+ }
+ }
+
+ /**
+ * Return the star-based rating value.
+ * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
+ * not star-based, or if it is unrated.
+ */
+ public float getStarRating() {
+ switch (mRatingStyle) {
+ case RATING_3_STARS:
+ case RATING_4_STARS:
+ case RATING_5_STARS:
+ if (isRated()) {
+ return mRatingValue;
+ }
+ default:
+ return -1.0f;
+ }
+ }
+
+ /**
+ * Return the percentage-based rating value.
+ * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
+ * not percentage-based, or if it is unrated.
+ */
+ public float getPercentRating() {
+ if ((mRatingStyle != RATING_PERCENTAGE) || !isRated()) {
+ return -1.0f;
+ } else {
+ return mRatingValue;
+ }
+ }
+}
\ No newline at end of file
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 58f5d55..f8faf3a 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -30,6 +30,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -385,27 +386,6 @@
mEventHandler = new EventHandler(this, looper);
}
- private static final int[] METADATA_KEYS_TYPE_STRING = {
- MediaMetadataRetriever.METADATA_KEY_ALBUM,
- MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
- MediaMetadataRetriever.METADATA_KEY_TITLE,
- MediaMetadataRetriever.METADATA_KEY_ARTIST,
- MediaMetadataRetriever.METADATA_KEY_AUTHOR,
- MediaMetadataRetriever.METADATA_KEY_COMPILATION,
- MediaMetadataRetriever.METADATA_KEY_COMPOSER,
- MediaMetadataRetriever.METADATA_KEY_DATE,
- MediaMetadataRetriever.METADATA_KEY_GENRE,
- MediaMetadataRetriever.METADATA_KEY_TITLE,
- MediaMetadataRetriever.METADATA_KEY_WRITER };
- private static final int[] METADATA_KEYS_TYPE_LONG = {
- MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
- MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
- MediaMetadataRetriever.METADATA_KEY_DURATION,
- MediaMetadataRetriever.METADATA_KEY_YEAR,
- MetadataEditor.LONG_KEY_RATING_TYPE,
- MetadataEditor.LONG_KEY_RATING_BY_OTHERS,
- MetadataEditor.LONG_KEY_RATING_BY_USER};
-
/**
* Class used to modify metadata in a {@link RemoteControlClient} object.
* Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
@@ -414,28 +394,7 @@
* for the associated client. Once the metadata has been "applied", you cannot reuse this
* instance of the MetadataEditor.
*/
- public class MetadataEditor {
- /**
- * Mask of editable keys.
- */
- private long mEditableKeys;
- /**
- * @hide
- */
- protected boolean mMetadataChanged;
- /**
- * @hide
- */
- protected boolean mArtworkChanged;
- /**
- * @hide
- */
- protected Bitmap mEditorArtwork;
- /**
- * @hide
- */
- protected Bundle mEditorMetadata;
- private boolean mApplied = false;
+ public class MetadataEditor extends MediaMetadataEditor {
// only use RemoteControlClient.editMetadata() to get a MetadataEditor instance
private MetadataEditor() { }
@@ -450,73 +409,10 @@
* The metadata key for the content artwork / album art.
*/
public final static int BITMAP_KEY_ARTWORK = 100;
- /**
- * The metadata key qualifying the content rating.
- * The value associated with this key may be: {@link #RATING_HEART},
- * {@link #RATING_THUMB_UP_DOWN}, or a non-null positive integer expressing a maximum
- * number of "stars" for the rating, for which a typical value is 3 or 5.
- */
- public final static int LONG_KEY_RATING_TYPE = 101;
- /**
- * The metadata key for the content's average rating, not the user's rating.
- * The value associated with this key may be: an integer value between 0 and 100,
- * or {@link #RATING_NOT_RATED} to express that no average rating is available.
- * <p></p>
- * Note that a rating value up to 100 is not incompatible with a rating type using up
- * to 5 stars for instance, as the average may be an non-integer number of stars.
- * <p></p>
- * When the rating type is:
- * <ul>
- * <li>{@link #RATING_HEART}, a rating of 51 to 100 means "heart selected",</li>
- * <li>{@link #RATING_THUMB_UP_DOWN}, a rating of 0 to 50 means "thumb down",
- * 51 to 100 means "thumb up"</li>
- * <li>a non-null positive integer, the rating value is mapped to the number of stars, e.g.
- * with a maximum of 5 stars, a rating of 0 maps to 0 stars, 1 to 20 maps to 1 star,
- * 21 to 40 maps to 2 stars, etc.</li>
- * </ul>
- * @see #LONG_KEY_RATING_BY_USER
- */
- public final static int LONG_KEY_RATING_BY_OTHERS = 102;
-
- // editable keys
- /**
- * @hide
- * Editable key mask
- */
- public final static int KEY_EDITABLE_MASK = 0x1FFFFFFF;
- /**
- * The metadata key for the content's user rating.
- * The value associated with this key may be: an integer value between 0 and 100,
- * or {@link #RATING_NOT_RATED} to express that the user hasn't rated this content.
- * Rules for the interpretation of the rating value according to the rating style are
- * the same as for {@link #LONG_KEY_RATING_BY_OTHERS}.
- * This key can be flagged as "editable" (with {@link #addEditableKey(int)}) to enable
- * receiving user rating values through the
- * {@link android.media.RemoteControlClient.OnMetadataUpdateListener} interface.
- */
- public final static int LONG_KEY_RATING_BY_USER = 0x10000001;
-
- /**
- * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to
- * indicate the content referred to is a favorite (or not).
- * @see #LONG_KEY_RATING_TYPE
- */
- public final static long RATING_HEART = -1;
- /**
- * A rating style for "thumb up" vs "thumb down".
- * @see #LONG_KEY_RATING_TYPE
- */
- public final static long RATING_THUMB_UP_DOWN = -2;
- /**
- * A rating value indicating no rating is available.
- * @see #LONG_KEY_RATING_BY_OTHERS
- * @see #LONG_KEY_RATING_BY_USER
- */
- public final static long RATING_NOT_RATED = -101;
/**
* @hide
- * TODO(jmtrivi) have lockscreen and music move to the new key name
+ * TODO(jmtrivi) have lockscreen move to the new key name and remove
*/
public final static int METADATA_KEY_ARTWORK = BITMAP_KEY_ARTWORK;
@@ -543,15 +439,7 @@
*/
public synchronized MetadataEditor putString(int key, String value)
throws IllegalArgumentException {
- if (mApplied) {
- Log.e(TAG, "Can't edit a previously applied MetadataEditor");
- return this;
- }
- if (!validTypeForKey(key, METADATA_KEYS_TYPE_STRING)) {
- throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
- }
- mEditorMetadata.putString(String.valueOf(key), value);
- mMetadataChanged = true;
+ super.putString(key, value);
return this;
}
@@ -564,9 +452,7 @@
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
* expressed in milliseconds),
- * {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR},
- * {@link #LONG_KEY_RATING_BY_OTHERS}, {@link #LONG_KEY_RATING_BY_USER},
- * {@link #LONG_KEY_RATING_TYPE}.
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
* @param value The long value for the given key
* @return Returns a reference to the same MetadataEditor object, so you can chain put
* calls together.
@@ -574,15 +460,7 @@
*/
public synchronized MetadataEditor putLong(int key, long value)
throws IllegalArgumentException {
- if (mApplied) {
- Log.e(TAG, "Can't edit a previously applied MetadataEditor");
- return this;
- }
- if (!validTypeForKey(key, METADATA_KEYS_TYPE_LONG)) {
- throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
- }
- mEditorMetadata.putLong(String.valueOf(key), value);
- mMetadataChanged = true;
+ super.putLong(key, value);
return this;
}
@@ -596,69 +474,22 @@
* @throws IllegalArgumentException
* @see android.graphics.Bitmap
*/
+ @Override
public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap)
throws IllegalArgumentException {
- if (mApplied) {
- Log.e(TAG, "Can't edit a previously applied MetadataEditor");
- return this;
- }
- if (key != BITMAP_KEY_ARTWORK) {
- throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
- }
- mEditorArtwork = bitmap;
- mArtworkChanged = true;
+ super.putBitmap(key, bitmap);
return this;
}
/**
- * Clears all the metadata that has been set since the MetadataEditor instance was
- * created with {@link RemoteControlClient#editMetadata(boolean)}.
+ * Clears all the metadata that has been set since the MetadataEditor instance was created
+ * (with {@link RemoteControlClient#editMetadata(boolean)}).
* Note that clearing the metadata doesn't reset the editable keys
- * (use {@link #clearEditableKeys()} instead).
+ * (use {@link MediaMetadataEditor#removeEditableKeys()} instead).
*/
+ @Override
public synchronized void clear() {
- if (mApplied) {
- Log.e(TAG, "Can't clear a previously applied MetadataEditor");
- return;
- }
- mEditorMetadata.clear();
- mEditorArtwork = null;
- }
-
- /**
- * Flag the given key as being editable.
- * This will declare the metadata field as eligible to be updated, with new values
- * received through the {@link RemoteControlClient.OnMetadataUpdateListener} interface.
- * @param key the type of metadata that can be edited. The supported key is
- * {@link #LONG_KEY_RATING_BY_USER}.
- */
- public synchronized void addEditableKey(int key) {
- if (mApplied) {
- Log.e(TAG, "Can't change editable keys of a previously applied MetadataEditor");
- return;
- }
- // only one editable key at the moment, so we're not wasting memory on an array
- // of editable keys to check the validity of the key, just hardcode the supported key.
- if (key == MetadataEditor.LONG_KEY_RATING_BY_USER) {
- mEditableKeys |= (MetadataEditor.KEY_EDITABLE_MASK & key);
- mMetadataChanged = true;
- } else {
- Log.e(TAG, "Metadata key " + key + " cannot be edited");
- }
- }
-
- /**
- * Causes all metadata fields to be read-only.
- */
- public synchronized void clearEditableKeys() {
- if (mApplied) {
- Log.e(TAG, "Can't clear editable keys of a previously applied MetadataEditor");
- return;
- }
- if (mEditableKeys != 0) {
- mEditableKeys = 0;
- mMetadataChanged = true;
- }
+ super.clear();
}
/**
@@ -881,30 +712,17 @@
/**
* Interface definition for a callback to be invoked when one of the metadata values has
* been updated.
+ * Implement this interface to receive metadata updates after registering your listener
+ * through {@link RemoteControlClient#setMetadataUpdateListener(OnMetadataUpdateListener)}.
*/
public interface OnMetadataUpdateListener {
/**
* Called on the implementer to notify that the metadata field for the given key has
- * been updated to the new value of type <code>long</long>.
- * @param key the identifier of the updated metadata field of type <code>long</long>.
- * @param newValue the new <code>long</long> value for the key
+ * been updated to the new value.
+ * @param key the identifier of the updated metadata field.
+ * @param newValue the Object storing the new value for the key.
*/
- void onMetadataUpdateLong(int key, long newValue);
- /**
- * Called on the implementer to notify that the metadata field for the given key has
- * been updated to the new <code>String</long>.
- * @param key the identifier of the updated metadata field of type <code>String</long>.
- * @param newValue the new <code>String</long> value for the key
- */
- void onMetadataUpdateString(int key, String newValue);
- /**
- * Called on the implementer to notify that the metadata field for the given key has
- * been updated to the new {@link android.graphics.Bitmap}.
- * @param key the identifier of the updated metadata field of type
- * {@link android.graphics.Bitmap}.
- * @param newValue the new {@link android.graphics.Bitmap} for the key
- */
- void onMetadataUpdateBitmap(int key, Bitmap newValue);
+ public abstract void onMetadataUpdate(int key, Object newValue);
}
/**
@@ -1338,12 +1156,11 @@
}
}
- public void updateMetadata(int generationId, int key, long value) {
+ public void updateMetadata(int generationId, int key, Rating value) {
// only post messages, we can't block here
if (mEventHandler != null) {
mEventHandler.sendMessage(mEventHandler.obtainMessage(
- MSG_UPDATE_METADATA_LONG, generationId /* arg1 */, key /* arg2*/,
- new Long(value)));
+ MSG_UPDATE_METADATA, generationId /* arg1 */, key /* arg2*/, value));
}
}
};
@@ -1389,7 +1206,7 @@
private final static int MSG_SEEK_TO = 10;
private final static int MSG_POSITION_DRIFT_CHECK = 11;
private final static int MSG_DISPLAY_WANTS_POS_SYNC = 12;
- private final static int MSG_UPDATE_METADATA_LONG = 13;
+ private final static int MSG_UPDATE_METADATA = 13;
private class EventHandler extends Handler {
public EventHandler(RemoteControlClient rcc, Looper looper) {
@@ -1443,8 +1260,8 @@
case MSG_DISPLAY_WANTS_POS_SYNC:
onDisplayWantsSync((IRemoteControlDisplay)msg.obj, msg.arg1 == 1);
break;
- case MSG_UPDATE_METADATA_LONG:
- onUpdateMetadata(msg.arg1, msg.arg2, ((Long)msg.obj).longValue());
+ case MSG_UPDATE_METADATA:
+ onUpdateMetadata(msg.arg1, msg.arg2, msg.obj);
break;
default:
Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
@@ -1725,10 +1542,10 @@
}
}
- private void onUpdateMetadata(int generationId, int key, long value) {
+ private void onUpdateMetadata(int generationId, int key, Object value) {
synchronized (mCacheLock) {
if ((mCurrentClientGenId == generationId) && (mMetadataUpdateListener != null)) {
- mMetadataUpdateListener.onMetadataUpdateLong(key, value);
+ mMetadataUpdateListener.onMetadataUpdate(key, value);
}
}
}
@@ -1771,24 +1588,6 @@
return bitmap;
}
- /**
- * Fast routine to go through an array of allowed keys and return whether the key is part
- * of that array
- * @param key the key value
- * @param validKeys the array of valid keys for a given type
- * @return true if the key is part of the array, false otherwise
- */
- private static boolean validTypeForKey(int key, int[] validKeys) {
- try {
- for (int i = 0 ; ; i++) {
- if (key == validKeys[i]) {
- return true;
- }
- }
- } catch (ArrayIndexOutOfBoundsException e) {
- return false;
- }
- }
/**
* Returns whether, for the given playback state, the playback position is expected to
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 52c0c2d..12f7bd9 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -120,6 +120,14 @@
.fromString("58b4b260-8e06-11e0-aa8e-0002a5d5c51b");
/**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * UUID for Loudness Enhancer
+ */
+ public static final UUID EFFECT_TYPE_LOUDNESS_ENHANCER = UUID
+ .fromString("fe3199be-aed0-413f-87bb-11260eb63cf1");
+
+ /**
* Null effect UUID. Used when the UUID for effect type of
* @hide
*/
diff --git a/media/java/android/media/audiofx/LoudnessEnhancer.java b/media/java/android/media/audiofx/LoudnessEnhancer.java
new file mode 100644
index 0000000..eb2fb75
--- /dev/null
+++ b/media/java/android/media/audiofx/LoudnessEnhancer.java
@@ -0,0 +1,291 @@
+/*
+ * 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.media.audiofx;
+
+import android.media.AudioTrack;
+import android.media.MediaPlayer;
+import android.media.audiofx.AudioEffect;
+import android.util.Log;
+
+import java.util.StringTokenizer;
+
+
+/**
+ * LoudnessEnhancer is an audio effect for increasing audio loudness.
+ * The processing is parametrized by a target gain value, which determines the maximum amount
+ * by which an audio signal will be amplified; signals amplified outside of the sample
+ * range supported by the platform are compressed.
+ * An application creates a LoudnessEnhancer object to instantiate and control a
+ * this audio effect in the audio framework.
+ * To attach the LoudnessEnhancer to a particular AudioTrack or MediaPlayer,
+ * specify the audio session ID of this AudioTrack or MediaPlayer when constructing the effect
+ * (see {@link AudioTrack#getAudioSessionId()} and {@link MediaPlayer#getAudioSessionId()}).
+ */
+
+public class LoudnessEnhancer extends AudioEffect {
+
+ private final static String TAG = "LoudnessEnhancer";
+
+ // These parameter constants must be synchronized with those in
+ // /system/media/audio_effects/include/audio_effects/effect_loudnessenhancer.h
+ /**
+ * The maximum gain applied applied to the signal to process.
+ * It is expressed in millibels (100mB = 1dB) where 0mB corresponds to no amplification.
+ */
+ public static final int PARAM_TARGET_GAIN_MB = 0;
+
+ /**
+ * Registered listener for parameter changes.
+ */
+ private OnParameterChangeListener mParamListener = null;
+
+ /**
+ * Listener used internally to to receive raw parameter change events
+ * from AudioEffect super class
+ */
+ private BaseParameterListener mBaseParamListener = null;
+
+ /**
+ * Lock for access to mParamListener
+ */
+ private final Object mParamListenerLock = new Object();
+
+ /**
+ * @hide
+ * Class constructor.
+ * @param audioSession system-wide unique audio session identifier. The LoudnessEnhancer
+ * will be attached to the MediaPlayer or AudioTrack in the same audio session.
+ *
+ * @throws java.lang.IllegalStateException
+ * @throws java.lang.IllegalArgumentException
+ * @throws java.lang.UnsupportedOperationException
+ * @throws java.lang.RuntimeException
+ */
+ public LoudnessEnhancer(int audioSession)
+ throws IllegalStateException, IllegalArgumentException,
+ UnsupportedOperationException, RuntimeException {
+ super(EFFECT_TYPE_LOUDNESS_ENHANCER, EFFECT_TYPE_NULL, 0, audioSession);
+
+ if (audioSession == 0) {
+ Log.w(TAG, "WARNING: attaching a LoudnessEnhancer to global output mix is deprecated!");
+ }
+ }
+
+ /**
+ * @hide
+ * Class constructor for the LoudnessEnhancer audio effect.
+ * @param priority the priority level requested by the application for controlling the
+ * LoudnessEnhancer engine. As the same engine can be shared by several applications,
+ * this parameter indicates how much the requesting application needs control of effect
+ * parameters. The normal priority is 0, above normal is a positive number, below normal a
+ * negative number.
+ * @param audioSession system-wide unique audio session identifier. The LoudnessEnhancer
+ * will be attached to the MediaPlayer or AudioTrack in the same audio session.
+ *
+ * @throws java.lang.IllegalStateException
+ * @throws java.lang.IllegalArgumentException
+ * @throws java.lang.UnsupportedOperationException
+ * @throws java.lang.RuntimeException
+ */
+ public LoudnessEnhancer(int priority, int audioSession)
+ throws IllegalStateException, IllegalArgumentException,
+ UnsupportedOperationException, RuntimeException {
+ super(EFFECT_TYPE_LOUDNESS_ENHANCER, EFFECT_TYPE_NULL, priority, audioSession);
+
+ if (audioSession == 0) {
+ Log.w(TAG, "WARNING: attaching a LoudnessEnhancer to global output mix is deprecated!");
+ }
+ }
+
+ /**
+ * Set the target gain for the audio effect.
+ * The target gain is the maximum value by which a sample value will be amplified when the
+ * effect is enabled.
+ * @param gainmB the effect target gain expressed in mB. 0mB corresponds to no amplification.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setTargetGain(int gainmB)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ checkStatus(setParameter(PARAM_TARGET_GAIN_MB, gainmB));
+ }
+
+ /**
+ * Return the target gain.
+ * @return the effect target gain expressed in mB.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public float getTargetGain()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ int[] value = new int[1];
+ checkStatus(getParameter(PARAM_TARGET_GAIN_MB, value));
+ return value[0];
+ }
+
+ /**
+ * @hide
+ * The OnParameterChangeListener interface defines a method called by the LoudnessEnhancer
+ * when a parameter value has changed.
+ */
+ public interface OnParameterChangeListener {
+ /**
+ * Method called when a parameter value has changed. The method is called only if the
+ * parameter was changed by another application having the control of the same
+ * LoudnessEnhancer engine.
+ * @param effect the LoudnessEnhancer on which the interface is registered.
+ * @param param ID of the modified parameter. See {@link #PARAM_GENERIC_PARAM1} ...
+ * @param value the new parameter value.
+ */
+ void onParameterChange(LoudnessEnhancer effect, int param, int value);
+ }
+
+ /**
+ * Listener used internally to receive unformatted parameter change events from AudioEffect
+ * super class.
+ */
+ private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+ private BaseParameterListener() {
+
+ }
+ public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+ // only notify when the parameter was successfully change
+ if (status != AudioEffect.SUCCESS) {
+ return;
+ }
+ OnParameterChangeListener l = null;
+ synchronized (mParamListenerLock) {
+ if (mParamListener != null) {
+ l = mParamListener;
+ }
+ }
+ if (l != null) {
+ int p = -1;
+ int v = Integer.MIN_VALUE;
+
+ if (param.length == 4) {
+ p = byteArrayToInt(param, 0);
+ }
+ if (value.length == 4) {
+ v = byteArrayToInt(value, 0);
+ }
+ if (p != -1 && v != Integer.MIN_VALUE) {
+ l.onParameterChange(LoudnessEnhancer.this, p, v);
+ }
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Registers an OnParameterChangeListener interface.
+ * @param listener OnParameterChangeListener interface registered
+ */
+ public void setParameterListener(OnParameterChangeListener listener) {
+ synchronized (mParamListenerLock) {
+ if (mParamListener == null) {
+ mBaseParamListener = new BaseParameterListener();
+ super.setParameterListener(mBaseParamListener);
+ }
+ mParamListener = listener;
+ }
+ }
+
+ /**
+ * @hide
+ * The Settings class regroups the LoudnessEnhancer parameters. It is used in
+ * conjunction with the getProperties() and setProperties() methods to backup and restore
+ * all parameters in a single call.
+ */
+ public static class Settings {
+ public int targetGainmB;
+
+ public Settings() {
+ }
+
+ /**
+ * Settings class constructor from a key=value; pairs formatted string. The string is
+ * typically returned by Settings.toString() method.
+ * @throws IllegalArgumentException if the string is not correctly formatted.
+ */
+ public Settings(String settings) {
+ StringTokenizer st = new StringTokenizer(settings, "=;");
+ //int tokens = st.countTokens();
+ if (st.countTokens() != 3) {
+ throw new IllegalArgumentException("settings: " + settings);
+ }
+ String key = st.nextToken();
+ if (!key.equals("LoudnessEnhancer")) {
+ throw new IllegalArgumentException(
+ "invalid settings for LoudnessEnhancer: " + key);
+ }
+ try {
+ key = st.nextToken();
+ if (!key.equals("targetGainmB")) {
+ throw new IllegalArgumentException("invalid key name: " + key);
+ }
+ targetGainmB = Integer.parseInt(st.nextToken());
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException("invalid value for key: " + key);
+ }
+ }
+
+ @Override
+ public String toString() {
+ String str = new String (
+ "LoudnessEnhancer"+
+ ";targetGainmB="+Integer.toString(targetGainmB)
+ );
+ return str;
+ }
+ };
+
+
+ /**
+ * @hide
+ * Gets the LoudnessEnhancer properties. This method is useful when a snapshot of current
+ * effect settings must be saved by the application.
+ * @return a LoudnessEnhancer.Settings object containing all current parameters values
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public LoudnessEnhancer.Settings getProperties()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ Settings settings = new Settings();
+ int[] value = new int[1];
+ checkStatus(getParameter(PARAM_TARGET_GAIN_MB, value));
+ settings.targetGainmB = value[0];
+ return settings;
+ }
+
+ /**
+ * @hide
+ * Sets the LoudnessEnhancer properties. This method is useful when bass boost settings
+ * have to be applied from a previous backup.
+ * @param settings a LoudnessEnhancer.Settings object containing the properties to apply
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setProperties(LoudnessEnhancer.Settings settings)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ checkStatus(setParameter(PARAM_TARGET_GAIN_MB, settings.targetGainmB));
+ }
+}
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 92edb8a..a03dbf3 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -43,13 +43,16 @@
using namespace android;
-static const char* const OutOfResourcesException =
- "android/view/Surface$OutOfResourcesException";
-
enum {
IMAGE_READER_MAX_NUM_PLANES = 3,
};
+enum {
+ ACQUIRE_SUCCESS = 0,
+ ACQUIRE_NO_BUFFERS = 1,
+ ACQUIRE_MAX_IMAGES = 2,
+};
+
static struct {
jfieldID mNativeContext;
jmethodID postEventFromNative;
@@ -685,14 +688,14 @@
ctx->returnLockedBuffer(buffer);
}
-static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz,
+static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz,
jobject image)
{
ALOGV("%s:", __FUNCTION__);
JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
if (ctx == NULL) {
jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
- return false;
+ return -1;
}
CpuConsumer* consumer = ctx->getCpuConsumer();
@@ -700,27 +703,22 @@
if (buffer == NULL) {
ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
" maxImages buffers");
- jniThrowException(env, OutOfResourcesException,
- "Too many outstanding images, close existing images"
- " to be able to acquire more.");
- return false;
+ return ACQUIRE_MAX_IMAGES;
}
status_t res = consumer->lockNextBuffer(buffer);
if (res != NO_ERROR) {
if (res != BAD_VALUE /*no buffers*/) {
if (res == NOT_ENOUGH_DATA) {
- jniThrowException(env, OutOfResourcesException,
- "Too many outstanding images, close existing images"
- " to be able to acquire more.");
+ return ACQUIRE_MAX_IMAGES;
} else {
ALOGE("%s Fail to lockNextBuffer with error: %d ",
__FUNCTION__, res);
- jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ jniThrowExceptionFmt(env, "java/lang/AssertionError",
"Unknown error (%d) when we tried to lock buffer.",
res);
}
}
- return false;
+ return ACQUIRE_NO_BUFFERS;
}
// Check if the left-top corner of the crop rect is origin, we currently assume this point is
@@ -730,7 +728,7 @@
ALOGE("crop left: %d, top = %d", lt.x, lt.y);
jniThrowException(env, "java/lang/UnsupportedOperationException",
"crop left top corner need to at origin");
- return false;
+ return -1;
}
// Check if the producer buffer configurations match what ImageReader configured.
@@ -738,22 +736,28 @@
int outputWidth = buffer->width;
int outputHeight = buffer->height;
- // Correct with/height when crop is set.
- if (buffer->crop.getWidth() > 0) {
- outputWidth = buffer->crop.getWidth() + 1;
- }
- if (buffer->crop.getHeight() > 0) {
- outputHeight = buffer->crop.getHeight() + 1;
+ // Correct width/height when crop is set.
+ if (!buffer->crop.isEmpty()) {
+ outputWidth = buffer->crop.getWidth();
+ outputHeight = buffer->crop.getHeight();
}
int imageReaderWidth = ctx->getBufferWidth();
int imageReaderHeight = ctx->getBufferHeight();
- if (imageReaderWidth != outputWidth
- || imageReaderHeight != outputHeight) {
- // Spew warning for now, since MediaCodec decoder has a bug to setup the right crop
- // TODO: make it throw exception once the decoder bug is fixed.
- ALOGW("Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
- outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
+ if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) &&
+ (imageReaderWidth != outputWidth || imageReaderHeight > outputHeight)) {
+ /**
+ * For video decoder, the buffer height is actually the vertical stride,
+ * which is always >= actual image height. For future, decoder need provide
+ * right crop rectangle to CpuConsumer to indicate the actual image height,
+ * see bug 9563986. After this bug is fixed, we can enforce the height equal
+ * check. Right now, only make sure buffer height is no less than ImageReader
+ * height.
+ */
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ "Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
+ outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
+ return -1;
}
if (ctx->getBufferFormat() != buffer->format) {
@@ -770,14 +774,14 @@
buffer->format, ctx->getBufferFormat());
jniThrowException(env, "java/lang/UnsupportedOperationException",
msg.string());
- return false;
+ return -1;
}
// Set SurfaceImage instance member variables
Image_setBuffer(env, image, buffer);
env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
static_cast<jlong>(buffer->timestamp));
- return true;
+ return ACQUIRE_SUCCESS;
}
static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz)
@@ -848,7 +852,7 @@
{"nativeInit", "(Ljava/lang/Object;IIII)V", (void*)ImageReader_init },
{"nativeClose", "()V", (void*)ImageReader_close },
{"nativeReleaseImage", "(Landroid/media/Image;)V", (void*)ImageReader_imageRelease },
- {"nativeImageSetup", "(Landroid/media/Image;)Z", (void*)ImageReader_imageSetup },
+ {"nativeImageSetup", "(Landroid/media/Image;)I", (void*)ImageReader_imageSetup },
{"nativeGetSurface", "()Landroid/view/Surface;", (void*)ImageReader_getSurface },
};
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 666d111..bbb74d25b 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -21,6 +21,7 @@
#include "android_media_MediaDrm.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include "android_os_Parcel.h"
#include "jni.h"
#include "JNIHelp.h"
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 1704d5c..1ac45d4 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -22,6 +22,7 @@
#include "android_media_Utils.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include "jni.h"
#include "JNIHelp.h"
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index 7517e85..457b956 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -164,6 +164,18 @@
}
+static void android_media_MediaMuxer_setLocation(
+ JNIEnv *env, jclass clazz, jint nativeObject, jint latitude, jint longitude) {
+ MediaMuxer* muxer = reinterpret_cast<MediaMuxer *>(nativeObject);
+
+ status_t res = muxer->setLocation(latitude, longitude);
+ if (res != OK) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Failed to set location");
+ return;
+ }
+}
+
static void android_media_MediaMuxer_start(JNIEnv *env, jclass clazz,
jint nativeObject) {
sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
@@ -216,6 +228,9 @@
{ "nativeSetOrientationHint", "(II)V",
(void *)android_media_MediaMuxer_setOrientationHint},
+ { "nativeSetLocation", "(III)V",
+ (void *)android_media_MediaMuxer_setLocation},
+
{ "nativeStart", "(I)V", (void *)android_media_MediaMuxer_start},
{ "nativeWriteSampleData", "(IILjava/nio/ByteBuffer;IIJI)V",
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 9b66c06..d134667 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -31,6 +31,7 @@
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_view_Surface.h"
+#include "android_runtime/Log.h"
#include "utils/Errors.h" // for status_t
#include "utils/KeyedVector.h"
#include "utils/String8.h"
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 5d27966..4e3d14e 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -25,6 +25,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
using namespace android;
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index fbd5d21..77c7966 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -26,6 +26,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include "MtpDatabase.h"
#include "MtpDataPacket.h"
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 113784e..b61b66c 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -28,6 +28,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include "private/android_filesystem_config.h"
#include "MtpTypes.h"
diff --git a/media/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp
index 4982a47..d8099dd 100644
--- a/media/jni/mediaeditor/VideoEditorClasses.cpp
+++ b/media/jni/mediaeditor/VideoEditorClasses.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#define LOG_TAG "VideoEditorClasses"
#include <VideoEditorClasses.h>
#include <VideoEditorJava.h>
diff --git a/media/jni/mediaeditor/VideoEditorJava.cpp b/media/jni/mediaeditor/VideoEditorJava.cpp
index bcf9099..fde0fb5 100644
--- a/media/jni/mediaeditor/VideoEditorJava.cpp
+++ b/media/jni/mediaeditor/VideoEditorJava.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "VideoEditorJava"
+
#include <VideoEditorClasses.h>
#include <VideoEditorJava.h>
#include <VideoEditorLogging.h>
diff --git a/media/jni/mediaeditor/VideoEditorLogging.h b/media/jni/mediaeditor/VideoEditorLogging.h
index 479d8b6..1f1228a 100644
--- a/media/jni/mediaeditor/VideoEditorLogging.h
+++ b/media/jni/mediaeditor/VideoEditorLogging.h
@@ -17,6 +17,16 @@
#ifndef VIDEO_EDITOR_LOGGING_H
#define VIDEO_EDITOR_LOGGING_H
+#ifndef LOG_TAG
+#error "No LOG_TAG defined!"
+#endif
+
+/*
+ * This file is used as a proxy for cutils/log.h. Include cutils/log.h here to
+ * avoid relying on import ordering.
+ */
+#include <cutils/log.h>
+
//#define VIDEOEDIT_LOGGING_ENABLED
#define VIDEOEDIT_LOG_INDENTATION (3)
diff --git a/media/jni/mediaeditor/VideoEditorOsal.cpp b/media/jni/mediaeditor/VideoEditorOsal.cpp
index a8c08ac..c12b1f5 100644
--- a/media/jni/mediaeditor/VideoEditorOsal.cpp
+++ b/media/jni/mediaeditor/VideoEditorOsal.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "VideoEditorOsal"
+
#include <VideoEditorJava.h>
#include <VideoEditorLogging.h>
#include <VideoEditorOsal.h>
diff --git a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
index c8fb263..2f8e357 100644
--- a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "VideoEditorPropertiesMain"
+
#include <dlfcn.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
index ecdc287..64b12b7 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
@@ -49,6 +49,7 @@
addMediaPlayerStateUnitTests(suite);
addMediaScannerUnitTests(suite);
addCameraUnitTests(suite);
+ addImageReaderTests(suite);
return suite;
}
@@ -65,6 +66,10 @@
suite.addTestSuite(CameraMetadataTest.class);
}
+ private void addImageReaderTests(TestSuite suite) {
+ suite.addTestSuite(ImageReaderTest.class);
+ }
+
// Running all unit tests checking the state machine may be time-consuming.
private void addMediaMetadataRetrieverStateUnitTests(TestSuite suite) {
suite.addTestSuite(MediaMetadataRetrieverTest.class);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 624bbaa..1b7faec 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -25,6 +25,7 @@
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.utils.BinderHolder;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.os.Binder;
@@ -155,7 +156,7 @@
}
@Override
- public void onResultReceived(int frameId, CameraMetadata result) throws RemoteException {
+ public void onResultReceived(int frameId, CameraMetadataNative result) throws RemoteException {
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 2f271bb..56d73c0 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -22,6 +22,7 @@
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.utils.BinderHolder;
import android.os.RemoteException;
import android.test.AndroidTestCase;
@@ -62,13 +63,13 @@
}
@Override
- public void onResultReceived(int frameId, CameraMetadata result) throws RemoteException {
+ public void onResultReceived(int frameId, CameraMetadataNative result) throws RemoteException {
}
}
- class IsMetadataNotEmpty extends ArgumentMatcher<CameraMetadata> {
+ class IsMetadataNotEmpty extends ArgumentMatcher<CameraMetadataNative> {
public boolean matches(Object obj) {
- return !((CameraMetadata) obj).isEmpty();
+ return !((CameraMetadataNative) obj).isEmpty();
}
}
@@ -78,20 +79,17 @@
mSurface = new Surface(mSurfaceTexture);
}
- private CaptureRequest createDefaultRequest(boolean needStream) throws Exception {
- CameraMetadata metadata = new CameraMetadata();
+ private CaptureRequest.Builder createDefaultBuilder(boolean needStream) throws Exception {
+ CameraMetadataNative metadata = new CameraMetadataNative();
assertTrue(metadata.isEmpty());
- CaptureRequest request = new CaptureRequest();
- assertTrue(request.isEmpty());
-
int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
assertFalse(metadata.isEmpty());
- request.swap(metadata);
+ CaptureRequest.Builder request = new CaptureRequest.Builder(metadata);
assertFalse(request.isEmpty());
- assertTrue(metadata.isEmpty());
+ assertFalse(metadata.isEmpty());
if (needStream) {
int streamId = mCameraUser.createStream(/* ignored */10, /* ignored */20,
/* ignored */30, mSurface);
@@ -150,14 +148,13 @@
@SmallTest
public void testCreateDefaultRequest() throws Exception {
- CameraMetadata metadata = new CameraMetadata();
+ CameraMetadataNative metadata = new CameraMetadataNative();
assertTrue(metadata.isEmpty());
int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
assertFalse(metadata.isEmpty());
- metadata.close();
}
@SmallTest
@@ -208,37 +205,39 @@
@SmallTest
public void testSubmitBadRequest() throws Exception {
- CaptureRequest request = createDefaultRequest(/* needStream */false);
- int status = mCameraUser.submitRequest(request, /* streaming */false);
+ CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */false);
+ CaptureRequest request1 = builder.build();
+ int status = mCameraUser.submitRequest(request1, /* streaming */false);
assertEquals("Expected submitRequest to return BAD_VALUE " +
"since we had 0 surface targets set.", CameraBinderTestUtils.BAD_VALUE, status);
- request.addTarget(mSurface);
- status = mCameraUser.submitRequest(request, /* streaming */false);
+ builder.addTarget(mSurface);
+ CaptureRequest request2 = builder.build();
+ status = mCameraUser.submitRequest(request2, /* streaming */false);
assertEquals("Expected submitRequest to return BAD_VALUE since " +
"the target surface wasn't registered with createStream.",
CameraBinderTestUtils.BAD_VALUE, status);
-
- request.close();
}
@SmallTest
public void testSubmitGoodRequest() throws Exception {
- CaptureRequest request = createDefaultRequest(/* needStream */true);
+ CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true);
+ CaptureRequest request = builder.build();
// Submit valid request twice.
int requestId1 = submitCameraRequest(request, /* streaming */false);
int requestId2 = submitCameraRequest(request, /* streaming */false);
assertNotSame("Request IDs should be unique for multiple requests", requestId1, requestId2);
- request.close();
}
@SmallTest
public void testSubmitStreamingRequest() throws Exception {
- CaptureRequest request = createDefaultRequest(/* needStream */true);
+ CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true);
+
+ CaptureRequest request = builder.build();
// Submit valid request once (non-streaming), and another time
// (streaming)
@@ -260,12 +259,11 @@
assertEquals("Streaming request IDs should be cancellable", CameraBinderTestUtils.NO_ERROR,
status);
- request.close();
}
@SmallTest
public void testCameraInfo() throws RemoteException {
- CameraMetadata info = new CameraMetadata();
+ CameraMetadataNative info = new CameraMetadataNative();
int status = mCameraUser.getCameraInfo(/*out*/info);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
@@ -276,8 +274,8 @@
@SmallTest
public void testWaitUntilIdle() throws Exception {
- CaptureRequest request = createDefaultRequest(/* needStream */true);
- int requestIdStreaming = submitCameraRequest(request, /* streaming */true);
+ CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true);
+ int requestIdStreaming = submitCameraRequest(builder.build(), /* streaming */true);
// Test Bad case first: waitUntilIdle when there is active repeating request
int status = mCameraUser.waitUntilIdle();
@@ -294,7 +292,7 @@
@SmallTest
public void testCaptureResultCallbacks() throws Exception {
IsMetadataNotEmpty matcher = new IsMetadataNotEmpty();
- CaptureRequest request = createDefaultRequest(/* needStream */true);
+ CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
// Test both single request and streaming request.
int requestId1 = submitCameraRequest(request, /* streaming */false);
@@ -307,7 +305,6 @@
.onResultReceived(
eq(streamingId),
argThat(matcher));
- request.close();
}
@SmallTest
@@ -319,7 +316,7 @@
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
// Then set up a stream
- CaptureRequest request = createDefaultRequest(/* needStream */true);
+ CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
// Flush should still be a no-op, really
status = mCameraUser.flush();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 2d26ac7..7b2a20e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -61,6 +61,7 @@
private SurfaceHolder mSurfaceHolder = null;
private static final int NUM_STRESS_LOOP = 10;
private static final int NUM_PLAYBACk_IN_EACH_LOOP = 20;
+ private static final int SHORT_WAIT = 2 * 1000; // 2 seconds
private static final long MEDIA_STRESS_WAIT_TIME = 5000; //5 seconds
private static final String MEDIA_MEMORY_OUTPUT =
"/sdcard/mediaMemOutput.txt";
@@ -99,16 +100,17 @@
@Override
protected void setUp() throws Exception {
super.setUp();
+ //Insert a 2 second before launching the test activity. This is
+ //the workaround for the race condition of requesting the updated surface.
+ Thread.sleep(SHORT_WAIT);
+ getActivity();
//Check if the device support the camcorder
- CamcorderProfile mCamcorderProfile = CamcorderProfile.get(CAMERA_ID);
+ mCamcorderProfile = CamcorderProfile.get(CAMERA_ID);
if (mCamcorderProfile != null) {
mVideoWidth = mCamcorderProfile.videoFrameWidth;
mVideoHeight = mCamcorderProfile.videoFrameHeight;
+ Log.v(TAG, "height = " + mVideoHeight + " width= " + mVideoWidth);
}
- //Insert a 2 second before launching the test activity. This is
- //the workaround for the race condition of requesting the updated surface.
- Thread.sleep(2000);
- getActivity();
if (MediaFrameworkPerfTestRunner.mGetNativeHeapDump)
MediaTestUtil.getNativeHeapDump(this.getName() + "_before");
@@ -246,6 +248,8 @@
Thread.sleep(MEDIA_STRESS_WAIT_TIME);
mRecorder.stop();
mRecorder.release();
+ //Insert 2 seconds to make sure the camera released.
+ Thread.sleep(SHORT_WAIT);
} catch (Exception e) {
Log.v("record video failed ", e.toString());
mRecorder.release();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index ecf01d9..874e078 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -23,8 +23,9 @@
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.Rational;
import android.hardware.camera2.Size;
+import android.hardware.camera2.impl.CameraMetadataNative;
-import static android.hardware.camera2.CameraMetadata.*;
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
@@ -42,7 +43,7 @@
*/
public class CameraMetadataTest extends junit.framework.TestCase {
- CameraMetadata mMetadata;
+ CameraMetadataNative mMetadata;
Parcel mParcel;
// Sections
@@ -62,13 +63,12 @@
@Override
public void setUp() {
- mMetadata = new CameraMetadata();
+ mMetadata = new CameraMetadataNative();
mParcel = Parcel.obtain();
}
@Override
public void tearDown() throws Exception {
- mMetadata.close();
mMetadata = null;
mParcel.recycle();
@@ -82,115 +82,47 @@
}
@SmallTest
- public void testClose() throws Exception {
- mMetadata.isEmpty(); // no throw
-
- assertFalse(mMetadata.isClosed());
-
- mMetadata.close();
-
- assertTrue(mMetadata.isClosed());
-
- // OK: second close should not throw
- mMetadata.close();
-
- assertTrue(mMetadata.isClosed());
-
- // All other calls after close should throw IllegalStateException
-
- try {
- mMetadata.isEmpty();
- fail("Unreachable -- isEmpty after close should throw IllegalStateException");
- } catch (IllegalStateException e) {
- // good: we expect calling this method after close to fail
- }
-
- try {
- mMetadata.getEntryCount();
- fail("Unreachable -- getEntryCount after close should throw IllegalStateException");
- } catch (IllegalStateException e) {
- // good: we expect calling this method after close to fail
- }
-
-
- try {
- mMetadata.swap(mMetadata);
- fail("Unreachable -- swap after close should throw IllegalStateException");
- } catch (IllegalStateException e) {
- // good: we expect calling this method after close to fail
- }
-
- try {
- mMetadata.readFromParcel(mParcel);
- fail("Unreachable -- readFromParcel after close should throw IllegalStateException");
- } catch (IllegalStateException e) {
- // good: we expect calling this method after close to fail
- }
-
- try {
- mMetadata.writeToParcel(mParcel, /*flags*/0);
- fail("Unreachable -- writeToParcel after close should throw IllegalStateException");
- } catch (IllegalStateException e) {
- // good: we expect calling this method after close to fail
- }
-
- try {
- mMetadata.readValues(/*tag*/0);
- fail("Unreachable -- readValues after close should throw IllegalStateException");
- } catch (IllegalStateException e) {
- // good: we expect calling this method after close to fail
- }
-
- try {
- mMetadata.writeValues(/*tag*/0, /*source*/new byte[] { 1,2,3 });
- fail("Unreachable -- readValues after close should throw IllegalStateException");
- } catch (IllegalStateException e) {
- // good: we expect calling this method after close to fail
- }
- }
-
- @SmallTest
public void testGetTagFromKey() {
// Test success
assertEquals(ANDROID_COLOR_CORRECTION_MODE,
- CameraMetadata.getTag("android.colorCorrection.mode"));
+ CameraMetadataNative.getTag("android.colorCorrection.mode"));
assertEquals(ANDROID_COLOR_CORRECTION_TRANSFORM,
- CameraMetadata.getTag("android.colorCorrection.transform"));
+ CameraMetadataNative.getTag("android.colorCorrection.transform"));
assertEquals(ANDROID_CONTROL_AE_ANTIBANDING_MODE,
- CameraMetadata.getTag("android.control.aeAntibandingMode"));
+ CameraMetadataNative.getTag("android.control.aeAntibandingMode"));
assertEquals(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
- CameraMetadata.getTag("android.control.aeExposureCompensation"));
+ CameraMetadataNative.getTag("android.control.aeExposureCompensation"));
// Test failures
try {
- CameraMetadata.getTag(null);
+ CameraMetadataNative.getTag(null);
fail("A null key should throw NPE");
} catch(NullPointerException e) {
}
try {
- CameraMetadata.getTag("android.control");
+ CameraMetadataNative.getTag("android.control");
fail("A section name only should not be a valid key");
} catch(IllegalArgumentException e) {
}
try {
- CameraMetadata.getTag("android.control.thisTagNameIsFakeAndDoesNotExist");
+ CameraMetadataNative.getTag("android.control.thisTagNameIsFakeAndDoesNotExist");
fail("A valid section with an invalid tag name should not be a valid key");
} catch(IllegalArgumentException e) {
}
try {
- CameraMetadata.getTag("android");
+ CameraMetadataNative.getTag("android");
fail("A namespace name only should not be a valid key");
} catch(IllegalArgumentException e) {
}
try {
- CameraMetadata.getTag("this.key.is.definitely.invalid");
+ CameraMetadataNative.getTag("this.key.is.definitely.invalid");
fail("A completely fake key name should not be valid");
} catch(IllegalArgumentException e) {
}
@@ -198,14 +130,14 @@
@SmallTest
public void testGetTypeFromTag() {
- assertEquals(TYPE_BYTE, CameraMetadata.getNativeType(ANDROID_COLOR_CORRECTION_MODE));
- assertEquals(TYPE_FLOAT, CameraMetadata.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM));
- assertEquals(TYPE_BYTE, CameraMetadata.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE));
+ assertEquals(TYPE_BYTE, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_MODE));
+ assertEquals(TYPE_FLOAT, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM));
+ assertEquals(TYPE_BYTE, CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE));
assertEquals(TYPE_INT32,
- CameraMetadata.getNativeType(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION));
+ CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION));
try {
- CameraMetadata.getNativeType(0xDEADF00D);
+ CameraMetadataNative.getNativeType(0xDEADF00D);
fail("No type should exist for invalid tag 0xDEADF00D");
} catch(IllegalArgumentException e) {
}
@@ -454,7 +386,7 @@
@SmallTest
public void testReadWriteEnumWithCustomValues() {
- CameraMetadata.registerEnumValues(AeAntibandingMode.class, new int[] {
+ CameraMetadataNative.registerEnumValues(AeAntibandingMode.class, new int[] {
0,
10,
20,
@@ -475,7 +407,7 @@
Key<AeAntibandingMode[]> aeAntibandingModeKey =
new Key<AeAntibandingMode[]>("android.control.aeAvailableAntibandingModes",
AeAntibandingMode[].class);
- byte[] aeAntibandingModeValues = mMetadata.readValues(CameraMetadata
+ byte[] aeAntibandingModeValues = mMetadata.readValues(CameraMetadataNative
.getTag("android.control.aeAvailableAntibandingModes"));
byte[] expectedValues = new byte[] { 0, 10, 20, 30 };
assertArrayEquals(expectedValues, aeAntibandingModeValues);
@@ -485,7 +417,7 @@
* Stranger cases that don't use byte enums
*/
// int (n)
- CameraMetadata.registerEnumValues(AvailableFormat.class, new int[] {
+ CameraMetadataNative.registerEnumValues(AvailableFormat.class, new int[] {
0x20,
0x32315659,
0x11,
@@ -505,7 +437,7 @@
Key<AeAntibandingMode> availableFormatsKey =
new Key<AeAntibandingMode>("android.scaler.availableFormats",
AeAntibandingMode.class);
- byte[] availableFormatValues = mMetadata.readValues(CameraMetadata
+ byte[] availableFormatValues = mMetadata.readValues(CameraMetadataNative
.getTag(availableFormatsKey.getName()));
int[] expectedIntValues = new int[] {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java
new file mode 100644
index 0000000..f6cd990
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediaframeworktest.unit;
+
+import static org.mockito.Mockito.*;
+
+import android.graphics.ImageFormat;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.media.ImageReader;
+import android.media.ImageReader.OnImageAvailableListener;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class ImageReaderTest extends AndroidTestCase {
+
+ private static final String TAG = "ImageReaderTest-unit";
+
+ private static final int DEFAULT_WIDTH = 640;
+ private static final int DEFAULT_HEIGHT = 480;
+ private static final int DEFAULT_FORMAT = ImageFormat.YUV_420_888;
+ private static final int DEFAULT_MAX_IMAGES = 3;
+
+ private ImageReader mReader;
+ private Image mImage1;
+ private Image mImage2;
+ private Image mImage3;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ /**
+ * Workaround for mockito and JB-MR2 incompatibility
+ *
+ * Avoid java.lang.IllegalArgumentException: dexcache == null
+ * https://code.google.com/p/dexmaker/issues/detail?id=2
+ */
+ System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
+
+ // TODO: refactor above into one of the test runners
+
+ mReader = spy(ImageReader.newInstance(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+ DEFAULT_MAX_IMAGES));
+ mImage1 = mock(Image.class);
+ mImage2 = mock(Image.class);
+ mImage3 = mock(Image.class);
+
+ /**
+ * Ensure rest of classes are mockable
+ */
+ {
+ mock(Plane.class);
+ mock(OnImageAvailableListener.class);
+ }
+
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mReader.close();
+
+ super.tearDown();
+ }
+
+ /**
+ * Return null when there is nothing in the image queue.
+ */
+ @SmallTest
+ public void testGetLatestImageEmpty() {
+ when(mReader.acquireNextImage()).thenReturn(null);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(null);
+ assertEquals(null, mReader.acquireLatestImage());
+ }
+
+ /**
+ * Return the last image from the image queue, close up the rest.
+ */
+ @SmallTest
+ public void testGetLatestImage1() {
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(null);
+ assertEquals(mImage1, mReader.acquireLatestImage());
+ verify(mImage1, never()).close();
+ }
+
+ /**
+ * Return the last image from the image queue, close up the rest.
+ */
+ @SmallTest
+ public void testGetLatestImage2() {
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).thenReturn(null);
+ assertEquals(mImage2, mReader.acquireLatestImage());
+ verify(mImage1, atLeastOnce()).close();
+ verify(mImage2, never()).close();
+ }
+
+ /**
+ * Return the last image from the image queue, close up the rest.
+ */
+ @SmallTest
+ public void testGetLatestImage3() {
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
+ thenReturn(mImage3).
+ thenReturn(null);
+ assertEquals(mImage3, mReader.acquireLatestImage());
+ verify(mImage1, atLeastOnce()).close();
+ verify(mImage2, atLeastOnce()).close();
+ verify(mImage3, never()).close();
+ }
+
+ /**
+ * Return null if get a IllegalStateException with no images in the queue.
+ */
+ @SmallTest
+ public void testGetLatestImageTooManyBuffersAcquiredEmpty() {
+ when(mReader.acquireNextImage()).thenThrow(new IllegalStateException());
+ try {
+ mReader.acquireLatestImage();
+ fail("Expected IllegalStateException to be thrown");
+ } catch(IllegalStateException e) {
+ }
+ }
+
+ /**
+ * All images are cleaned up when we get an unexpected Error.
+ */
+ @SmallTest
+ public void testGetLatestImageExceptionalError() {
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
+ thenReturn(mImage3).
+ thenThrow(new OutOfMemoryError());
+ try {
+ mReader.acquireLatestImage();
+ fail("Impossible");
+ } catch(OutOfMemoryError e) {
+ }
+
+ verify(mImage1, atLeastOnce()).close();
+ verify(mImage2, atLeastOnce()).close();
+ verify(mImage3, atLeastOnce()).close();
+ }
+
+ /**
+ * All images are cleaned up when we get an unexpected RuntimeException.
+ */
+ @SmallTest
+ public void testGetLatestImageExceptionalRuntime() {
+
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
+ thenReturn(mImage3).
+ thenThrow(new RuntimeException());
+ try {
+ mReader.acquireLatestImage();
+ fail("Impossible");
+ } catch(RuntimeException e) {
+ }
+
+ verify(mImage1, atLeastOnce()).close();
+ verify(mImage2, atLeastOnce()).close();
+ verify(mImage3, atLeastOnce()).close();
+ }
+}
diff --git a/media/tests/SoundPoolTest/AndroidManifest.xml b/media/tests/SoundPoolTest/AndroidManifest.xml
index 126276c..8a29052 100644
--- a/media/tests/SoundPoolTest/AndroidManifest.xml
+++ b/media/tests/SoundPoolTest/AndroidManifest.xml
@@ -8,4 +8,5 @@
</intent-filter>
</activity>
</application>
+ <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8"/>
</manifest>
diff --git a/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java b/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
index 33db2dd..cc3306c 100644
--- a/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
+++ b/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
@@ -143,7 +143,7 @@
if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
sleep(50);
}
- if (DEBUG) Log.d(LOG_TAG, "End scale test");
+ if (DEBUG) Log.d(LOG_TAG, "End sounds test");
return true;
}
@@ -165,7 +165,7 @@
if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
sleep(50);
}
- if (DEBUG) Log.d(LOG_TAG, "End sounds test");
+ if (DEBUG) Log.d(LOG_TAG, "End scale test");
return true;
}
@@ -189,6 +189,7 @@
if (DEBUG) Log.d(LOG_TAG, "Change rate " + mScale[step]);
}
mSoundPool.stop(id);
+ if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
if (DEBUG) Log.d(LOG_TAG, "End rate test");
return true;
}
@@ -205,34 +206,38 @@
Log.e(LOG_TAG, "Error occurred starting note");
return false;
}
- sleep(250);
+ sleep(1000);
// play a low priority sound
- int id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME,
+ int id = mSoundPool.play(mSounds[1], DEFAULT_VOLUME, DEFAULT_VOLUME,
LOW_PRIORITY, DEFAULT_LOOP, 1.0f);
- if (id > 0) {
+ if (id != 0) {
Log.e(LOG_TAG, "Normal > Low priority test failed");
result = false;
mSoundPool.stop(id);
} else {
- Log.e(LOG_TAG, "Normal > Low priority test passed");
+ sleep(1000);
+ Log.i(LOG_TAG, "Normal > Low priority test passed");
}
- sleep(250);
// play a high priority sound
- id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME,
+ id = mSoundPool.play(mSounds[2], DEFAULT_VOLUME, DEFAULT_VOLUME,
HIGH_PRIORITY, DEFAULT_LOOP, 1.0f);
if (id == 0) {
Log.e(LOG_TAG, "High > Normal priority test failed");
result = false;
} else {
- Log.e(LOG_TAG, "High > Normal priority test passed");
+ sleep(1000);
+ Log.i(LOG_TAG, "Stopping high priority");
+ mSoundPool.stop(id);
+ sleep(1000);
+ Log.i(LOG_TAG, "High > Normal priority test passed");
}
- sleep(250);
- mSoundPool.stop(id);
// stop normal note
+ Log.i(LOG_TAG, "Stopping normal priority");
mSoundPool.stop(normalId);
+ sleep(1000);
if (DEBUG) Log.d(LOG_TAG, "End priority test");
return result;
@@ -250,17 +255,21 @@
Log.e(LOG_TAG, "Error occurred starting note");
return false;
}
- sleep(250);
+ sleep(2500);
// pause and resume sound a few times
for (int count = 0; count < 5; count++) {
+ if (DEBUG) Log.d(LOG_TAG, "Pause note " + id);
mSoundPool.pause(id);
- sleep(250);
+ sleep(1000);
+ if (DEBUG) Log.d(LOG_TAG, "Resume note " + id);
mSoundPool.resume(id);
- sleep(250);
+ sleep(1000);
}
+ if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
mSoundPool.stop(id);
+ sleep(1000);
// play 5 sounds, forces one to be stolen
int ids[] = new int[5];
@@ -272,18 +281,21 @@
Log.e(LOG_TAG, "Error occurred starting note");
return false;
}
- sleep(250);
+ sleep(1000);
}
// pause and resume sound a few times
for (int count = 0; count < 5; count++) {
+ if (DEBUG) Log.d(LOG_TAG, "autoPause");
mSoundPool.autoPause();
- sleep(250);
+ sleep(1000);
+ if (DEBUG) Log.d(LOG_TAG, "autoResume");
mSoundPool.autoResume();
- sleep(250);
+ sleep(1000);
}
for (int i = 0; i < 5; i++) {
+ if (DEBUG) Log.d(LOG_TAG, "Stop note " + ids[i]);
mSoundPool.stop(ids[i]);
}
@@ -302,9 +314,9 @@
return false;
}
- // pan from left to right
+ // pan from right to left
for (int count = 0; count < 101; count++) {
- sleep(20);
+ sleep(50);
double radians = PI_OVER_2 * count / 100.0;
float leftVolume = (float) Math.sin(radians);
float rightVolume = (float) Math.cos(radians);
diff --git a/media/tests/audiotests/Android.mk b/media/tests/audiotests/Android.mk
new file mode 100644
index 0000000..69f0bb5
--- /dev/null
+++ b/media/tests/audiotests/Android.mk
@@ -0,0 +1,21 @@
+ifeq ($(TARGET_ARCH),arm)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= shared_mem_test
+LOCAL_SRC_FILES := \
+ shared_mem_test.cpp
+LOCAL_SHARED_LIBRARIES := \
+ libc \
+ libcutils \
+ libutils \
+ libbinder \
+ libhardware_legacy \
+ libmedia
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/media/tests/audiotests/shared_mem_test.cpp b/media/tests/audiotests/shared_mem_test.cpp
new file mode 100644
index 0000000..992c900
--- /dev/null
+++ b/media/tests/audiotests/shared_mem_test.cpp
@@ -0,0 +1,216 @@
+// Copyright 2008, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//
+#define LOG_NDEBUG 0
+#define LOG_TAG "shared_mem_test"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <cutils/properties.h>
+#include <media/AudioSystem.h>
+#include <media/AudioTrack.h>
+#include <math.h>
+
+#include "shared_mem_test.h"
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+#include <binder/ProcessState.h>
+
+
+#include <utils/Log.h>
+
+#include <fcntl.h>
+
+namespace android {
+
+/************************************************************
+*
+* Constructor
+*
+************************************************************/
+AudioTrackTest::AudioTrackTest(void) {
+
+ InitSine(); // init sine table
+
+}
+
+
+/************************************************************
+*
+*
+************************************************************/
+void AudioTrackTest::Execute(void) {
+ if (Test01() == 0) {
+ ALOGD("01 passed\n");
+ } else {
+ ALOGD("01 failed\n");
+ }
+}
+
+/************************************************************
+*
+* Shared memory test
+*
+************************************************************/
+#define BUF_SZ 44100
+
+int AudioTrackTest::Test01() {
+
+ sp<MemoryDealer> heap;
+ sp<IMemory> iMem;
+ uint8_t* p;
+
+ short smpBuf[BUF_SZ];
+ long rate = 44100;
+ unsigned long phi;
+ unsigned long dPhi;
+ long amplitude;
+ long freq = 1237;
+ float f0;
+
+ f0 = pow(2., 32.) * freq / (float)rate;
+ dPhi = (unsigned long)f0;
+ amplitude = 1000;
+ phi = 0;
+ Generate(smpBuf, BUF_SZ, amplitude, phi, dPhi); // fill buffer
+
+ for (int i = 0; i < 1024; i++) {
+ heap = new MemoryDealer(1024*1024, "AudioTrack Heap Base");
+
+ iMem = heap->allocate(BUF_SZ*sizeof(short));
+
+ p = static_cast<uint8_t*>(iMem->pointer());
+ memcpy(p, smpBuf, BUF_SZ*sizeof(short));
+
+ sp<AudioTrack> track = new AudioTrack(AUDIO_STREAM_MUSIC,// stream type
+ rate,
+ AUDIO_FORMAT_PCM_16_BIT,// word length, PCM
+ AUDIO_CHANNEL_OUT_MONO,
+ iMem);
+
+ status_t status = track->initCheck();
+ if(status != NO_ERROR) {
+ track.clear();
+ ALOGD("Failed for initCheck()");
+ return -1;
+ }
+
+ // start play
+ ALOGD("start");
+ track->start();
+
+ usleep(20000);
+
+ ALOGD("stop");
+ track->stop();
+ iMem.clear();
+ heap.clear();
+ usleep(20000);
+ }
+
+ return 0;
+
+}
+
+/************************************************************
+*
+* Generate a mono buffer
+* Error is less than 3lsb
+*
+************************************************************/
+void AudioTrackTest::Generate(short *buffer, long bufferSz, long amplitude, unsigned long &phi, long dPhi)
+{
+ long pi13 = 25736; // 2^13*pi
+ // fill buffer
+ for(int i0=0; i0<bufferSz; i0++) {
+ long sample;
+ long l0, l1;
+
+ buffer[i0] = ComputeSine( amplitude, phi);
+ phi += dPhi;
+ }
+}
+
+/************************************************************
+*
+* Generate a sine
+* Error is less than 3lsb
+*
+************************************************************/
+short AudioTrackTest::ComputeSine(long amplitude, long phi)
+{
+ long pi13 = 25736; // 2^13*pi
+ long sample;
+ long l0, l1;
+
+ sample = (amplitude*sin1024[(phi>>22) & 0x3ff]) >> 15;
+ // correct with interpolation
+ l0 = (phi>>12) & 0x3ff; // 2^20 * x / (2*pi)
+ l1 = (amplitude*sin1024[((phi>>22) + 256) & 0x3ff]) >> 15; // 2^15*cosine
+ l0 = (l0 * l1) >> 10;
+ l0 = (l0 * pi13) >> 22;
+ sample = sample + l0;
+
+ return (short)sample;
+}
+
+
+/************************************************************
+*
+* init sine table
+*
+************************************************************/
+void AudioTrackTest::InitSine(void) {
+ double phi = 0;
+ double dPhi = 2 * M_PI / SIN_SZ;
+ for(int i0 = 0; i0<SIN_SZ; i0++) {
+ long d0;
+
+ d0 = 32768. * sin(phi);
+ phi += dPhi;
+ if(d0 >= 32767) d0 = 32767;
+ if(d0 <= -32768) d0 = -32768;
+ sin1024[i0] = (short)d0;
+ }
+}
+
+/************************************************************
+*
+* main in name space
+*
+************************************************************/
+int main() {
+ ProcessState::self()->startThreadPool();
+ AudioTrackTest *test;
+
+ test = new AudioTrackTest();
+ test->Execute();
+ delete test;
+
+ return 0;
+}
+
+}
+
+/************************************************************
+*
+* global main
+*
+************************************************************/
+int main(int argc, char *argv[]) {
+
+ return android::main();
+}
diff --git a/media/tests/audiotests/shared_mem_test.h b/media/tests/audiotests/shared_mem_test.h
new file mode 100644
index 0000000..f495955
--- /dev/null
+++ b/media/tests/audiotests/shared_mem_test.h
@@ -0,0 +1,27 @@
+// Copyright 2008 The Android Open Source Project
+
+#ifndef AUDIOTRACKTEST_H_
+#define AUDIOTRACKTEST_H_
+
+namespace android {
+
+class AudioTrackTest{
+ public:
+ AudioTrackTest(void);
+ ~AudioTrackTest() {};
+
+ void Execute(void);
+ int Test01();
+
+ void Generate(short *buffer, long bufferSz, long amplitude, unsigned long &phi, long dPhi);
+ void InitSine();
+ short ComputeSine(long amplitude, long phi);
+
+ #define SIN_SZ 1024
+ short sin1024[SIN_SZ]; // sine table 2*pi = 1024
+};
+
+};
+
+
+#endif /*AUDIOTRACKTEST_H_*/
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
index 294b502..0c65283 100644
--- a/obex/javax/obex/ClientOperation.java
+++ b/obex/javax/obex/ClientOperation.java
@@ -121,6 +121,13 @@
(header).mAuthResp.length);
}
+
+ if ((header).mConnectionID != null) {
+ mRequestHeader.mConnectionID = new byte[4];
+ System.arraycopy((header).mConnectionID, 0, mRequestHeader.mConnectionID, 0,
+ 4);
+
+ }
}
/**
@@ -420,7 +427,7 @@
//split the headerArray
end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketSize
- ObexHelper.BASE_PACKET_LENGTH);
- // can not split
+ // can not split
if (end == -1) {
mOperationDone = true;
abort();
@@ -521,7 +528,7 @@
return false;
}
- // send all of the output data in 0x48,
+ // send all of the output data in 0x48,
// send 0x49 with empty body
if ((mPrivateOutput != null) && (mPrivateOutput.size() > 0))
returnValue = true;
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
index a4b9759..f1b9a0d 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -256,6 +256,10 @@
public void sendResponse(int code, byte[] header) throws IOException {
int totalLength = 3;
byte[] data = null;
+ OutputStream op = mOutput;
+ if (op == null) {
+ return;
+ }
if (header != null) {
totalLength += header.length;
@@ -270,8 +274,8 @@
data[1] = (byte)0x00;
data[2] = (byte)totalLength;
}
- mOutput.write(data);
- mOutput.flush();
+ op.write(data);
+ op.flush();
}
/**
diff --git a/packages/BackupRestoreConfirmation/res/values-en-rIN/strings.xml b/packages/BackupRestoreConfirmation/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..d096d98
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-en-rIN/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="backup_confirm_title" msgid="827563724209303345">"Full backup"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"Full restoration"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"A full backup of all data to a connected desktop computer has been requested. Do you want to allow this to happen?\n\nIf you did not request the backup yourself, do not allow the operation to proceed."</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"Back up my data"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"Do not back up"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"A full restore of all data from a connected desktop computer has been requested. Do you want to allow this to happen?\n\nIf you did not request the restore yourself, do not allow the operation to proceed. This will replace any data currently on the device!"</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"Restore my data"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"Do not restore"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Please enter your current backup password below:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"Please enter your device encryption password below."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"Please enter your device encryption password below. This will also be used to encrypt the backup archive."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Please enter a password to use for encrypting the full backup data. If this is left blank, your current backup password will be used:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"If you wish to encrypt the full backup data, enter a password below:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"If the restore data is encrypted, please enter the password below:"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"Backup starting..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"Backup finished"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"Restoration starting..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"Restoration ended"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"Operation timed out"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-et-rEE/strings.xml b/packages/BackupRestoreConfirmation/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..0f5fde2
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-et-rEE/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="backup_confirm_title" msgid="827563724209303345">"Täielik varundus"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"Täielik taastamine"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"Taotleti kõikide andmete varundamist ühendatud lauaarvutist. Kas soovite seda lubada?\n\nKui te ei taotlenud varundust, siis ärge lubage toimingut jätkata."</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"Varunda mu andmed"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"Ära varunda"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"Taotletud on kõikide andmete taastamist ühendatud lauaarvutist. Kas soovite seda lubada?\n\nKui te ei taotlenud taastamist, siis ärge lubage toimingut jätkata. See asendab kõik praegu seadmes olevad andmed."</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"Taasta mu andmed"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"Ära taasta"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Sisestage allpool praegune varunduse parool:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"Sisestage allpool oma seadme krüpteerimise parool."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"Sisestage allpool oma seadme krüpteerimise parool. Seda kasutatakse ka varukoopiate arhiivi krüpteerimiseks."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Sisestage parool kõikide varundatud andmete krüpteerimise jaoks. Kui jätate selle tühjaks, siis kasutatakse teie praegust varunduse parooli:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Kui soovite kõik varundusandmed krüpteerida, siis sisestage allpool parool:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"Kui taasteandmed on krüpteeritud, siis sisestage allpool parool."</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"Algab varundamine ..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"Varundamine jõudis lõpule"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"Algab taastamine ..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"Taastamine jõudis lõpule"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"Toiming aegus"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-fr-rCA/strings.xml b/packages/BackupRestoreConfirmation/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..8a70fb5
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-fr-rCA/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="backup_confirm_title" msgid="827563724209303345">"Sauvegarde complète"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"Restauration complète"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"Vous avez demandé une sauvegarde complète de l\'ensemble des données vers un ordinateur de bureau connecté. Voulez-vous l\'autoriser?\n\nSi vous n\'avez pas demandé la sauvegarde vous-même, n\'autorisez pas la poursuite de l\'opération."</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"Sauvegarder mes données"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"Ne pas sauvegarder"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"Vous avez demandé une restauration complète de l\'ensemble des données à partir d\'un ordinateur de bureau connecté. Voulez-vous l\'autoriser?\n\nSi vous n\'avez pas demandé vous-même la restauration, n\'autorisez pas sa poursuite. Cette opération remplacera toutes les données actuellement sur l\'appareil!"</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"Restaurer mes données"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"Ne pas restaurer"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Veuillez saisir votre mot de passe de sauvegarde actuel ci-dessous :"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"Veuillez saisir le mot de passe de chiffrement de l\'appareil ci-dessous."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"Veuillez saisir le mot de passe de chiffrement de l\'appareil ci-dessous. Il permettra également de chiffrer les archives de sauvegarde."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Veuillez saisir un mot de passe à utiliser pour chiffrer les données de sauvegarde complète. Si ce champ n\'est pas renseigné, votre mot de passe de sauvegarde actuel sera utilisé :"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Si vous souhaitez chiffrer l\'ensemble des données de sauvegarde, veuillez saisir un mot de passe ci-dessous :"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"Si les données de restauration sont chiffrées, veuillez saisir le mot de passe ci-dessous :"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"Démarrage de la sauvegarde…"</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"Sauvegarde terminée."</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"Démarrage de la restauration…"</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"Restauration terminée."</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"L\'opération a expiré."</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-hi/strings.xml b/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
index dd0c645..0b29804 100644
--- a/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
@@ -16,22 +16,22 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="backup_confirm_title" msgid="827563724209303345">"पूर्ण बैकअप"</string>
+ <string name="backup_confirm_title" msgid="827563724209303345">"पूर्ण सुरक्षा"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"पूर्ण पुनर्स्थापना"</string>
- <string name="backup_confirm_text" msgid="1878021282758896593">"कनेक्ट किए गए डेस्कटॉप कंप्यूटर से सभी डेटा के संपूर्ण बैकअप का अनुरोध किया गया है. क्या आप इसकी अनुमति देना चाहते हैं?\n\nयदि आपने स्वयं बैकअप का अनुरोध नहीं किया है, तो प्रक्रिया जारी रखने की अनुमति न दें."</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"कनेक्ट किए गए डेस्कटॉप कंप्यूटर से सभी डेटा के संपूर्ण सुरक्षा का अनुरोध किया गया है. क्या आप इसकी अनुमति देना चाहते हैं?\n\nयदि आपने स्वयं बैकअप का अनुरोध नहीं किया है, तो प्रक्रिया जारी रखने की अनुमति न दें."</string>
<string name="allow_backup_button_label" msgid="4217228747769644068">"मेरे डेटा का बैकअप लें"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"बैकअप न लें"</string>
<string name="restore_confirm_text" msgid="7499866728030461776">"कनेक्ट किए गए डेस्कटॉप कंप्यूटर से सभी डेटा की पूर्ण पुनर्स्थापना का अनुरोध किया गया है. क्या आप इसकी अनुमति देना चाहते हैं?\n\nयदि आपने स्वयं पुनर्प्राप्ति का अनुरोध नहीं किया है, तो प्रक्रिया जारी रखने की अनुमति न दें. इससे वर्तमान में आपके उपकरण पर मौजूद डेटा बदल जाएगा!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"मेरा डेटा पुनर्स्थापित करें"</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"पुनर्स्थापित न करें"</string>
- <string name="current_password_text" msgid="8268189555578298067">"कृपया नीचे अपना वर्तमान बैकअप पासवर्ड डालें:"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"कृपया नीचे अपना वर्तमान सुरक्षित करने का पासवर्ड डालें:"</string>
<string name="device_encryption_restore_text" msgid="1570864916855208992">"कृपया नीचे अपना उपकरण एन्क्रिप्शन पासवर्ड डालें."</string>
- <string name="device_encryption_backup_text" msgid="5866590762672844664">"कृपया अपना उपकरण एन्क्रिप्शन पासवर्ड नीचे दर्ज करें. बैकअप संग्रहण को एन्क्रिप्ट करने के लिए भी इसका उपयोग किया जाएगा."</string>
- <string name="backup_enc_password_text" msgid="4981585714795233099">"कृपया संपूर्ण बैकअप डेटा को एन्क्रिप्ट करने में उपयोग के लिए पासवर्ड डालें. यदि यह खाली छोड़ दिया जाता है, तो आपके वर्तमान बैकअप पासवर्ड का उपयोग किया जाएगा:"</string>
- <string name="backup_enc_password_optional" msgid="1350137345907579306">"यदि आप संपूर्ण बैकअप डेटा एन्क्रिप्ट करना चाहते हैं, तो नीचे पासवर्ड डालें:"</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"कृपया अपना उपकरण सुरक्षित तरीका पासवर्ड नीचे दर्ज करें. बैकअप संग्रहण को एन्क्रिप्ट करने के लिए भी इसका उपयोग किया जाएगा."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"कृपया संपूर्ण सुरक्षित डेटा को एन्क्रिप्ट करने में उपयोग के लिए पासवर्ड डालें. यदि यह खाली छोड़ दिया जाता है, तो आपके वर्तमान बैकअप पासवर्ड का उपयोग किया जाएगा:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"यदि आप संपूर्ण सुरक्षित डेटा को एन्क्रिप्ट करना चाहते हैं, तो नीचे पासवर्ड डालें:"</string>
<string name="restore_enc_password_text" msgid="6140898525580710823">"यदि पुनर्स्थापित डेटा को एन्क्रिप्ट किया गया है, तो कृपया नीचे पासवर्ड डालें:"</string>
- <string name="toast_backup_started" msgid="550354281452756121">"बैकअप प्रारंभ हो रहा है..."</string>
- <string name="toast_backup_ended" msgid="3818080769548726424">"बैकअप पूर्ण"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"सुरक्षित करना शुरु हो रहा है..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"सुरक्षित करना पूर्ण"</string>
<string name="toast_restore_started" msgid="7881679218971277385">"पुनर्स्थापना प्रारंभ हो रही है..."</string>
<string name="toast_restore_ended" msgid="1764041639199696132">"पुनर्स्थापना समाप्त"</string>
<string name="toast_timeout" msgid="5276598587087626877">"कार्यवाही समयबाह्य हो गई"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-hy-rAM/strings.xml b/packages/BackupRestoreConfirmation/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..4db9080
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-hy-rAM/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="backup_confirm_title" msgid="827563724209303345">"Ամբողջական պահուստավորում"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"Ամբողջական վերականգնում"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"Կապակցված աշխատասեղանով համակարգչի վրա բոլոր տվյալների լրիվ պահուստավորման հարցում է արվել: Ցանկանու՞մ եք թույլատրել հարցման կատարումը:\n\nԵթե դուք ինքներդ պահուստավորման հարցում չեք արել, թույլ մի տվեք, որպեսզի գործողությունը շարունակվի:"</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"Պահուստավորել իմ տվյալները"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"Չպահուստավորել"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"Հայցվել է բոլոր տվյալների ամբողջական վերականգնում միացված աշխատանքային համակարգչից: Ցանկանու՞մ եք թույլատրել, որ դա տեղի ունենա:\n\nԵթե վերականգնումը ինքներդ չեք հայցել, թուjլ մի տվեք, որ գործողությունը շարունակվի: Դա կփոխարինի ներկայում հեռախոսի մեջ գտնվող ցանկացած տվյալ:"</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"Վերականգնել իմ տվյալները"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"Չվերականգնել"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Խնդրում ենք մուտքագրել ձեր ընթացիկ պահուստային գաղտնաբառը ներքևում`"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"Խնդրում ենք մուտքագրել ձեր սարքի կոդավորված գաղտնաբառը ներքևում:"</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"Խնդրում ենք մուտքագրել ձեր սարքի կոդավորված գաղտնաբառը ներքևում: Այն նաև կօգտագործվի պահուստային արխիվի կոդավորման համար:"</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Խնդրում ենք մուտքագրել գաղտնաբառը` ամբողջական պահուստավորվող տվյալները կոդավորելու համար: Եթե այն դատարկ թողնեք, ապա կօգտագործվի ձեր առկա պահուստավորման գաղտնաբառը`"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Եթե ցանկանում եք կոդավորել ամբողջական պահուստավորված տվյալները, մուտքագրեք գաղտնաբառ ստորև`"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"Եթե վերականգնվող տվյալները կոդավորված են, խնդրում ենք մուտքագրել գաղտնաբառը ստորև`"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"Պահուստավորումը սկսվում է..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"Պահուստավորումն ավարտվեց"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"Վերականգնումը մեկնարկեց..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"Վերականգնումն ավարտվեց"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"Գործողության ժամանակը սպառվեց"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-ka-rGE/strings.xml b/packages/BackupRestoreConfirmation/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..9c6f67e
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-ka-rGE/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="backup_confirm_title" msgid="827563724209303345">"სრული სარეზერვო კოპირება"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"სრულად აღდგენა"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"მოთხოვნილ იქნა სამაგიდო კომპიუტერთან დაკავშირებული ყველა მონაცემის სრულყოფილი სარეზერვო ასლები. \n\nთუ სარეზერვო ასლები თქვენ არ მოგითხოვიათ, არ დაუშვათ ამ ოპერაციის გაგრძელება."</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"ჩემი მონაცემების სარეზერვო კოპირება"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"სარეზერვო ასლები არ გააკეთო"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"დაკავშირებული დესკტოპ კომპიუტერიდან მოხდა ყველა მონაცემის სრული აღდგენის მოთხოვნა. გსურთ, დაუშვათ ეს?\n\nთუ თქვენ თვითონ არ მოითხოვეთ აღდგენა, არ დაუშვათ ამ ოპერაციის გაგრძელება. ის ჩაანაცვლებს მოწყობილობაზე ამჟამად არსებულ ნებისმიერ მონაცემს!"</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"ჩემი მონაცემების აღდგენა"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"არ აღადგინო"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"გთხოვთ, ქვემოთ მიუთითოთ თქვენი ამჟამინდელი სათადარიგო პაროლი:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"გთხოვთ, ქვემოთ მიუთითოთ თქვენი მოწყობილობის დაშიფვრის პაროლი."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"გთხოვთ, ქვემოთ მიუთითოთ თქვენი მოწყობილობის დაშიფვრის პაროლი. ეს ასევე გამოყენებული იქნება სათადარიგო არქივის დაშიფრვისათვის."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"გთხოვთ შეიყვანოთ ყველა სამარქაფო ასლის დაშიფრვის პაროლი. თუ ამ ველს ცარიელს დატოვებთ, გამოყენებული იქნება მიმდინარე პაროლი:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"თუ გსურთ სრული ლოკალური სარეზერვო კოპიის დაშიფრვა, შეიყვანეთ პაროლი ქვემოთ:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"თუ აღსადგენი მონაცემები დაშიფრულია, გთხოვთ, შეიყვანოთ პაროლი ქვემოთ:"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"ასლების მომზადება იწყება..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"სარეზერვო კოპირება დასრულებულია"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"აღდგენა იწყება..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"აღდგენა დასრულდა"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"ოპერაციის დროის ლიმიტი ამოიწურა"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-km-rKH/strings.xml b/packages/BackupRestoreConfirmation/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..956fdd7
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-km-rKH/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="backup_confirm_title" msgid="827563724209303345">"ការបម្រុងទុកពេញលេញ"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"ស្ដារឡើងវិញពេញលេញ"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"ការបម្រុងទុកទិន្នន័យទាំងអស់ពេញលេញទៅកុំព្យូទ័រដែលបានភ្ជាប់ត្រូវបានស្នើ។ តើអ្នកចង់ឲ្យវាកើតឡើងដែរឬទេ??\n\nបើអ្នកមិនបានស្នើការបម្រុងទុកដោយខ្លួនអ្នកផ្ទាល់ទេ កុំអនុញ្ញាតប្រតិបត្តិការនេះ។"</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"បម្រុងទុកទិន្នន័យរបស់ខ្ញុំ"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"កុំបម្រុងទុក"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"ការស្ដារទិន្នន័យទាំងអស់ពេញលេញពីកុំព្យូទ័រដែលបានតភ្ជាប់ត្រូវបានស្នើ។ តើអ្នកចង់អនុញ្ញាតដែរឬទេ?\n\n បើអ្នកមិនបានស្នើការស្ដារខ្លួនឯងទេ កុំអនុញ្ញាត។ វានឹងជំនួសទិន្នន័យណាមួយដែលមានលើឧបករណ៍!"</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"ស្ដារទិន្នន័យរបស់ខ្ញុំ"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"កុំស្ដារឡើងវិញ"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"សូមបញ្ចូលពាក្យសម្ងាត់បម្រុងទុកបច្ចុប្បន្នរបស់អ្នកខាងក្រោម៖"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"សូមបញ្ចូលពាក្យសម្ងាត់ដាក់លេខកូដឧបករណ៍របស់អ្នកខាងក្រោម។"</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"សូមបញ្ចូលពាក្យសម្ងាត់ដាក់លេខកូដឧបករណ៍របស់អ្នកខាងក្រោម។ វានឹងត្រូវបានប្រើ ដើម្បីដាក់លេខកូដប័ណ្ណសារបម្រុងទុកផងដែរ។"</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"សូមបញ្ចូលពាក្យសម្ងាត់ដើម្បីប្រើសម្រាប់ដាក់លេខកូដទិន្នន័យបម្រុងទុកពេញលេញ។ បើទុកវាទទេ ពាក្យសម្ងាត់បម្រុងទុកបច្ចុប្បន្នរបស់អ្នកនឹងត្រូវបានប្រើ៖"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"បើអ្នកចង់ដាក់លេខកូដទិន្នន័យបម្រុងទុកពេញលេញ បញ្ចូលពាក្យសម្ងាត់ខាងក្រោម៖"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"បើទិន្នន័យស្ដារត្រូវបានដាក់លេខកូដ សូមបញ្ចូលពាក្យសម្ងាត់ខាងក្រោម៖"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"កំពុងចាប់ផ្ដើមបម្រុងទុក..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"ការបម្រុងទុកបានបញ្ចប់"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"ការស្ដារកំពុងចាប់ផ្ដើម..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"ការស្តារបានបញ្ចប់"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"ប្រតិបត្តិការអស់ពេល"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-lo-rLA/strings.xml b/packages/BackupRestoreConfirmation/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..fb28502
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-lo-rLA/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="backup_confirm_title" msgid="827563724209303345">"ສຳຮອງຂໍ້ມູນເຕັມຮູບແບບ"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"ກູ້ຂໍ້ມູນເຕັມຮູບແບບ"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"ມີການຮ້ອງຂໍໃຫ້ສຳຮອງຂໍ້ມູນທັງໝົດ ໄປໃສ່ຄອມພິວເຕີຕັ້ງໂຕະທີ່ເຊື່ອມຕໍ່ຢູ່. ທ່ານຈະອະນຸມັດໃຫ້ດຳເນີນການຫຼືບໍ່?\n\nຫາກທ່ານບໍ່ໄດ້ຮ້ອງຂໍໃຫ້ສຳຮອງຂໍ້ມູນດ້ວຍຕົນເອງ, ກະລຸນາຢ່າອະນຸຍາດໃຫ້ດຳເນີນການຕໍ່ໄປ."</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"ສຳຮອງຂໍ້ມູນຂອງຂ້ອຍ"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"ບໍ່ໃຫ້ສຳຮອງຂໍ້ມູນ"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"ການກູ້ຂໍ້ມູນທັງໝົດຈາກຄອມພິວເຕີທີ່ເຊື່ອມຕໍ່ຢູ່ນັ້ນຖືກຮ້ອງຂໍແລ້ວ. ທ່ານຕ້ອງການອະນຸຍາດໃຫ້ການກະທຳນີ້ເກີດຂຶ້ນບໍ່?\n\nຫາກທ່ານບໍ່ໄດ້ເຮັດການຮ້ອງຂໍ້ການກູ້ຂໍ້ມູນດ້ວຍໂຕທ່ານເອງ, ທ່ານບໍ່ຄວນອະນຸຍາດໃຫ້ມີການດຳເນີນການໃດໆ ເນື່ອງຈາກມັນຈະໄປຂຽນທັບຂໍ້ມູນທັງໝົດທີ່ຢູ່ໃນອຸປະກອນ!"</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"ກູ້ຄືນຂໍ້ມູນຂອງຂ້ອຍ"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"ບໍ່ໃຫ້ກູ້ຄືນ"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"ກະລຸນາປ້ອນລະຫັດຜ່ານການສຳຮອງຂໍ້ມູນທີ່ທ່ານໃຊ້ຢູ່ໃສ່ດ້ານລຸ່ມ:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"ກະລຸນາປ້ອນລະຫັດຜ່ານການເຂົ້າລະຫັດອຸປະກອນຂອງທ່ານໃສ່ດ້ານລຸ່ມ."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"ກະລຸນາປ້ອນລະຫັດຜ່ານການເຂົ້າລະຫັດອຸປະກອນຂອງທ່ານໃສ່ດ້ານລຸ່ມ. ລະຫັດນີ້ຍັງຈະໃຊ້ເພື່ອເຂົ້າລະຫັດຂໍ້ມູນທີ່ສຳຮອງໄວ້."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"ກະລຸນາປ້ອນລະຫັດຜ່ານ ເພື່ອໃຊ້ໃນການເຂົ້າລະຫັດການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບ. ຖ້າປ່ອຍໃຫ້ເປົ່າຫວ່າງໄວ້, ລະຫັດຜ່ານສຳຮອງຂໍ້ມູນທີ່ທ່ານໃຊ້ຢູ່ຈະຖືກນຳໃຊ້ແທນ:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"ຫາກທ່ານຕ້ອງການທີ່ຈະເຂົ້າລະຫັດໃຫ້ກັບການສຳຮອງຂໍ້ມູນທັງໝົດ, ກະລຸນາໃສ່ລະຫັດທາງລຸ່ມນີ້:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"ຫາກຂໍ້ມູນສຳຮອງຖືກເຂົ້າລະຫັດໄວ້, ກະລຸນາໃສ່ລະຫັດຜ່ານທາງດ້ານລຸ່ມນີ້:"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"ກຳລັງເລີ່ມການສຳຮອງຂໍ້ມູນ..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"ສຳຮອງຂໍ້ມູນສຳເລັດແລ້ວ"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"ການກູ້ຂໍ້ມູນກຳລັງຈະເລີ່ມ..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"ການກູ້ຂໍ້ມູນສິ້ນສຸດແລ້ວ"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"ໝົດເວລາປະຕິບັດການ"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-mn-rMN/strings.xml b/packages/BackupRestoreConfirmation/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..b2738c0
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-mn-rMN/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="backup_confirm_title" msgid="827563724209303345">"Бүрэн нөөшлөх"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"Бүрэн сэргээх"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"Холбогдсон байгаа десктоп компьютерлүү бүх датаг бүрэн нөөшлөх хүсэлт тавигдав. Та энийг зөвшөөрөх үү?\n\nХэрэв та нөөшлөлт хийх хүсэлт хийгээгүй бол энийг зөвшөөрч болохгүй."</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"Миний датаг нөөшлөх"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"Нөөшлөхгүй"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"Холбогдсон байгаа десктоп компьютерээс бүх датаг бүрэн сэргээх хүсэлт тавигдав. Та энийг зөвшөөрөх үү?\n\nХэрэв та сэргээх хүсэлт хийгээгүй бол энийг зөвшөөрч болохгүй. Энэ нь төхөөрөмж дээр одоо байгаа дурын датаг орлуулах болно!"</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"Миний датаг сэргээх"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"Сэргээхгүй"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Одоогийн нөөшлөх нууц үгийг доор оруулна уу:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"Төхөөрөмж шифрлэх нууц үгийг доор оруулна уу."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"Төхөөрөмж шифрлэх нууц үгийг доор оруулна уу. Энэ нууц үгийг нөөшлөх архивийг шифрлэхэд бас ашиглана."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Бүрэн дата нөөшлөлтийг шифрлэхэд ашиглах нууц үгийг оруулна уу. Хэрэв та хоосон үлдээвэл таны одоогийн нөөшлөлтийн нууц үг ашиглагдах болно:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Хэрэв та бүрэн нөөшлөх датаг шифрлэх бол доор нууц үгийг оруулна уу:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"Хэрэв сэргээх дата шифрлэгдсэн бол доор нууц үгийг оруулна уу:"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"Нөөшлөж эхлэх..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"Нөөшлөлт дуусав"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"Сэргээлт эхлэж байна..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"Сэргээлт дуусав"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"Ажиллагааны хугацаа хэтрэв"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-ms-rMY/strings.xml b/packages/BackupRestoreConfirmation/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..65a9ede
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-ms-rMY/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="backup_confirm_title" msgid="827563724209303345">"Sandaran penuh"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"Pemulihan penuh"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"Sandaran lengkap bagi semua data ke komputer meja yang bersambung telah diminta. Adakah anda mahu membenarkan ini berlaku?\n\nJika anda tidak meminta sandaran ini sendiri, jangan benarkan operasi diteruskan."</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"Sandarkan data saya"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"Jangan buat sandaran"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"Pemulihan penuh semua data dari komputer meja yang bersambung telah diminta. Adakah anda mahu membenarkan ini berlaku?\n\nJika anda tidak meminta pemulihan ini sendiri, jangan benarkan operasi ini diteruskan. Ini akan menggantikan sebarang data semasa pada peranti!"</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"Pulihkan data saya"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"Jangan kembalikan"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Sila masukkan kata laluan sandaran semasa anda di bawah:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"Sila masukkan kata laluan penyulitan peranti anda di bawah."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"Sila masukkan kata laluan penyulitan peranti anda di bawah. Ini juga akan digunakan untuk menyulitkan arkib sandaran."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Sila masukkan kata laluan yang hendak digunakan untuk menyulitkan data sandaran lengkap. Jika dibiarkan kosong, kata laluan sandaran semasa anda akan digunakan:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Jika anda ingin menyulitkan data sandaran lengkap, masukkan kata laluan di bawah:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"Jika pemulihan data disulitkan, sila masukkan kata laluan di bawah:"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"Sandaran bermula..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"Sandaran selesai"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"Pemulihan bermula..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"Pemulihan berakhir"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"Operasi tamat masa"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-zh-rHK/strings.xml b/packages/BackupRestoreConfirmation/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..d3bcd6e
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-zh-rHK/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="backup_confirm_title" msgid="827563724209303345">"完整備份"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"完整還原"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"系統收到將所有資料完整備份到連線桌上電腦的要求,請問您允許進行備份嗎?\n\n如果您本人並未提出備份要求,請勿允許繼續進行這項作業。"</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"備份我的資料"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"不要備份"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"系統收到從連線的桌上電腦完整還原所有資料的要求,請問您允許進行還原嗎?\n\n如果您本人並未提出還原要求,請勿允許繼續進行這項作業。這項作業將取代裝置上現有的全部資料!"</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"還原我的資料"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"不要還原"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"在下面輸入您目前的備份密碼:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"請在下面輸入您的裝置加密密碼。"</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"請在下面輸入您的裝置加密密碼,這也會用來將封存備份加密。"</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"請輸入為完整備份資料加密的專用密碼。如果留空,系統將使用您目前的備份密碼:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"如果您想將完整的備份資料加密,請在下面輸入一組密碼:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"如果還原的資料經過加密處理,請在下面輸入密碼:"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"正在開始備份..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"備份完畢"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"正在開始還原..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"還原完畢"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"操作逾時"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-zu/strings.xml b/packages/BackupRestoreConfirmation/res/values-zu/strings.xml
index b62b7af..955b26f 100644
--- a/packages/BackupRestoreConfirmation/res/values-zu/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-zu/strings.xml
@@ -29,7 +29,7 @@
<string name="device_encryption_backup_text" msgid="5866590762672844664">"Uyacelwa ukuba ufake iphasiwedi efakwe kudivayisi yakho ngezansi. lokhu kuzosetshenziswa ukufaka kusilondoloza sokusiza lapho kudingeka."</string>
<string name="backup_enc_password_text" msgid="4981585714795233099">"Sicela ufake iphasiwedi ezosetshenziselwa ukubhala ngokufihlekileyo imininingo eyesekwe ngokulondoloza. Uma lokhu kushiywe kungabhalwe lutho, kuzosetshenziswa iphasiwedi yokweseka ngokulondoloza yamanje:"</string>
<string name="backup_enc_password_optional" msgid="1350137345907579306">"Uma ufuna ukufaka ikhowudi kwimininingo yonke eyesekelwe ngokulondoloza faka i-passowrd engezansi:"</string>
- <string name="restore_enc_password_text" msgid="6140898525580710823">"Uma insiza yokubuyiselwa esimweni kwmininingo ibhalwe ngokufihlekileyo, sicela ufake iphasiwedi engezansi:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"Uma uhlelo lokusebenza yokubuyiselwa esimweni kwmininingo ibhalwe ngokufihlekileyo, sicela ufake iphasiwedi engezansi:"</string>
<string name="toast_backup_started" msgid="550354281452756121">"Ukulondoloza kuyaqala..."</string>
<string name="toast_backup_ended" msgid="3818080769548726424">"Ukulondoloza kuphelile"</string>
<string name="toast_restore_started" msgid="7881679218971277385">"Ukubuyisa kuyaqala..."</string>
diff --git a/packages/DefaultContainerService/res/values-en-rIN/strings.xml b/packages/DefaultContainerService/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..216d715
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-en-rIN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"Package Access Helper"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-et-rEE/strings.xml b/packages/DefaultContainerService/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..216d715
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-et-rEE/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"Package Access Helper"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-fr-rCA/strings.xml b/packages/DefaultContainerService/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..69c4e99
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-fr-rCA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"Aide accès au paquet"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-hy-rAM/strings.xml b/packages/DefaultContainerService/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..1e2f587
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-hy-rAM/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"Փաթեթի մուտքի օժանդակող"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-ka-rGE/strings.xml b/packages/DefaultContainerService/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..216d715
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-ka-rGE/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"Package Access Helper"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-km-rKH/strings.xml b/packages/DefaultContainerService/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..1006d56
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-km-rKH/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"កម្មវិធីជំនួយចូលដំណើរការកញ្ចប់"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-lo-rLA/strings.xml b/packages/DefaultContainerService/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..216d715
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-lo-rLA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"Package Access Helper"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-mn-rMN/strings.xml b/packages/DefaultContainerService/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..d9fe647
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-mn-rMN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"Багц хандалтын тусламж"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-ms-rMY/strings.xml b/packages/DefaultContainerService/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..77d7927
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-ms-rMY/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"Pembantu Akses Pakej"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-zh-rHK/strings.xml b/packages/DefaultContainerService/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..9a43509
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-zh-rHK/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"套件存取輔助程式"</string>
+</resources>
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 4c91bd3..1ef7bff 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -11,7 +11,7 @@
<!-- TODO: allow rotation when state saving is in better shape -->
<activity
android:name=".DocumentsActivity"
- android:theme="@android:style/Theme.Holo.Light">
+ android:theme="@style/Theme">
<intent-filter android:priority="100">
<action android:name="android.intent.action.OPEN_DOCUMENT" />
<category android:name="android.intent.category.DEFAULT" />
@@ -39,8 +39,8 @@
<activity
android:name=".SettingsActivity"
- android:title="@string/menu_settings"
- android:theme="@android:style/Theme.Holo.Light"
+ android:label="@string/menu_settings"
+ android:theme="@android:style/Theme.Holo.Light.DialogWhenLarge"
android:exported="false" />
<provider
diff --git a/packages/DocumentsUI/res/drawable/item_root.xml b/packages/DocumentsUI/res/drawable/item_root.xml
index 183d273..6f201cc 100644
--- a/packages/DocumentsUI/res/drawable/item_root.xml
+++ b/packages/DocumentsUI/res/drawable/item_root.xml
@@ -18,5 +18,5 @@
<item android:state_pressed="true" android:drawable="@color/item_root_activated" />
<item android:state_activated="true" android:drawable="@color/item_root_activated" />
<item android:state_focused="true" android:drawable="@color/item_root_activated" />
- <item android:drawable="@android:color/white" />
+ <item android:drawable="@android:color/transparent" />
</selector>
diff --git a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
new file mode 100644
index 0000000..3bea166
--- /dev/null
+++ b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/item_background"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingTop="8dip"
+ android:paddingBottom="8dip"
+ android:orientation="horizontal">
+
+ <FrameLayout
+ android:id="@android:id/icon"
+ android:layout_width="@dimen/icon_size"
+ android:layout_height="@dimen/icon_size"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="20dp"
+ android:layout_gravity="center_vertical">
+
+ <ImageView
+ android:id="@+id/icon_mime"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerInside"
+ android:contentDescription="@null" />
+
+ <ImageView
+ android:id="@+id/icon_thumb"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop"
+ android:contentDescription="@null" />
+
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.5"
+ android:layout_marginEnd="12dp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAlignment="viewStart"
+ style="@style/TextAppearance.Medium" />
+
+ <ImageView
+ android:id="@android:id/icon1"
+ android:layout_width="@dimen/root_icon_size"
+ android:layout_height="@dimen/root_icon_size"
+ android:layout_marginEnd="8dp"
+ android:scaleType="centerInside"
+ android:contentDescription="@null" />
+
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.25"
+ android:layout_marginEnd="12dp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAlignment="viewStart"
+ style="@style/TextAppearance.Small" />
+
+ <TextView
+ android:id="@+id/size"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.125"
+ android:layout_marginEnd="12dp"
+ android:minWidth="70dp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAlignment="viewEnd"
+ style="@style/TextAppearance.Small" />
+
+ <TextView
+ android:id="@+id/date"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.125"
+ android:layout_marginEnd="12dp"
+ android:minWidth="70dp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAlignment="viewEnd"
+ style="@style/TextAppearance.Small" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout-sw720dp/activity.xml b/packages/DocumentsUI/res/layout-sw720dp/activity.xml
new file mode 100644
index 0000000..584a44d
--- /dev/null
+++ b/packages/DocumentsUI/res/layout-sw720dp/activity.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/dialog_roots">
+
+ <FrameLayout
+ android:id="@+id/container_roots"
+ android:layout_width="250dp"
+ android:layout_height="match_parent" />
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="end"
+ android:scaleType="fitXY"
+ android:src="@drawable/ic_drawer_shadow_tablet" />
+
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:id="@+id/container_directory"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1" />
+
+ <FrameLayout
+ android:id="@+id/container_save"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index 881349b..b4138a5 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -24,8 +24,8 @@
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/empty"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:visibility="gone" />
+ android:visibility="gone"
+ style="@style/TextAppearance.Medium" />
<ListView
android:id="@+id/list"
@@ -40,12 +40,4 @@
android:listSelector="@android:color/transparent"
android:visibility="gone" />
- <Button
- android:id="@+id/more"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom"
- android:text="@string/more"
- android:visibility="gone" />
-
</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index 8d1fc9a..b745bb9 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -30,14 +30,29 @@
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
+ android:layout_marginBottom="6dp"
android:background="#fff">
- <ImageView
+ <FrameLayout
android:id="@android:id/icon"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scaleType="centerInside"
- android:contentDescription="@null" />
+ android:layout_height="match_parent">
+
+ <ImageView
+ android:id="@+id/icon_mime"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerInside"
+ android:contentDescription="@null" />
+
+ <ImageView
+ android:id="@+id/icon_thumb"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop"
+ android:contentDescription="@null" />
+
+ </FrameLayout>
<ImageView
android:layout_width="match_parent"
@@ -49,10 +64,10 @@
</FrameLayout>
<LinearLayout
+ android:id="@+id/line1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:paddingTop="6dp"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
@@ -63,8 +78,8 @@
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textAlignment="viewStart" />
+ android:textAlignment="viewStart"
+ style="@style/TextAppearance.Medium" />
<ImageView
android:id="@android:id/icon1"
@@ -93,7 +108,7 @@
android:singleLine="true"
android:ellipsize="marquee"
android:textAlignment="viewStart"
- android:textAppearance="?android:attr/textAppearanceSmall" />
+ style="@style/TextAppearance.Small" />
<TextView
android:id="@+id/size"
@@ -105,19 +120,21 @@
android:singleLine="true"
android:ellipsize="marquee"
android:textAlignment="viewStart"
- android:textAppearance="?android:attr/textAppearanceSmall" />
+ style="@style/TextAppearance.Small" />
- <TextView
- android:id="@android:id/summary"
+ <Space
android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="center_vertical"
- android:layout_marginStart="8dp"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAlignment="viewStart"
- android:textAppearance="?android:attr/textAppearanceSmall" />
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <ImageView
+ android:id="@android:id/icon2"
+ android:layout_width="@dimen/root_icon_size"
+ android:layout_height="@dimen/root_icon_size"
+ android:layout_marginStart="8dip"
+ android:scaleType="centerInside"
+ android:contentDescription="@null"
+ android:visibility="gone" />
</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
index 8372eed..84fda9d 100644
--- a/packages/DocumentsUI/res/layout/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -25,15 +25,29 @@
android:paddingBottom="8dip"
android:orientation="horizontal">
- <ImageView
+ <FrameLayout
android:id="@android:id/icon"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_marginStart="12dp"
android:layout_marginEnd="20dp"
- android:layout_gravity="center_vertical"
- android:scaleType="centerInside"
- android:contentDescription="@null" />
+ android:layout_gravity="center_vertical">
+
+ <ImageView
+ android:id="@+id/icon_mime"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerInside"
+ android:contentDescription="@null" />
+
+ <ImageView
+ android:id="@+id/icon_thumb"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop"
+ android:contentDescription="@null" />
+
+ </FrameLayout>
<LinearLayout
android:layout_width="0dip"
@@ -54,8 +68,8 @@
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textAlignment="viewStart" />
+ android:textAlignment="viewStart"
+ style="@style/TextAppearance.Medium" />
<ImageView
android:id="@android:id/icon1"
@@ -82,7 +96,7 @@
android:singleLine="true"
android:ellipsize="marquee"
android:textAlignment="viewStart"
- android:textAppearance="?android:attr/textAppearanceSmall" />
+ style="@style/TextAppearance.Small" />
<TextView
android:id="@+id/size"
@@ -94,7 +108,7 @@
android:singleLine="true"
android:ellipsize="marquee"
android:textAlignment="viewStart"
- android:textAppearance="?android:attr/textAppearanceSmall" />
+ style="@style/TextAppearance.Small" />
<TextView
android:id="@android:id/summary"
@@ -106,7 +120,7 @@
android:singleLine="true"
android:ellipsize="marquee"
android:textAlignment="viewStart"
- android:textAppearance="?android:attr/textAppearanceSmall" />
+ style="@style/TextAppearance.Small" />
</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_loading_grid.xml b/packages/DocumentsUI/res/layout/item_loading_grid.xml
new file mode 100644
index 0000000..21be137
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_loading_grid.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/grid_height"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingTop="8dip"
+ android:paddingBottom="8dip"
+ android:orientation="horizontal">
+
+ <ProgressBar
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:indeterminate="true"
+ style="?android:attr/progressBarStyle" />
+
+</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_loading.xml b/packages/DocumentsUI/res/layout/item_loading_list.xml
similarity index 100%
rename from packages/DocumentsUI/res/layout/item_loading.xml
rename to packages/DocumentsUI/res/layout/item_loading_list.xml
diff --git a/packages/DocumentsUI/res/layout/item_message_grid.xml b/packages/DocumentsUI/res/layout/item_message_grid.xml
index 941340e..b3bdd28 100644
--- a/packages/DocumentsUI/res/layout/item_message_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_message_grid.xml
@@ -16,44 +16,36 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="180dip"
+ android:layout_height="@dimen/grid_height"
+ android:paddingTop="?android:attr/listPreferredItemPaddingStart"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingBottom="?android:attr/listPreferredItemPaddingEnd"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+ android:foreground="@drawable/item_background">
- <FrameLayout
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/chip"
- android:foreground="@drawable/item_background"
- android:duplicateParentState="true">
+ android:orientation="vertical"
+ android:gravity="center">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="6dp"
- android:orientation="vertical"
- android:gravity="center">
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@null" />
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@null" />
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:maxLines="4"
+ android:ellipsize="end"
+ android:paddingTop="6dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAlignment="viewStart" />
- <TextView
- android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:paddingTop="6dp"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textAlignment="viewStart" />
-
- </LinearLayout>
-
- </FrameLayout>
+ </LinearLayout>
</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_message_list.xml b/packages/DocumentsUI/res/layout/item_message_list.xml
index dda3c80..ffda98c 100644
--- a/packages/DocumentsUI/res/layout/item_message_list.xml
+++ b/packages/DocumentsUI/res/layout/item_message_list.xml
@@ -39,9 +39,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textAlignment="viewStart" />
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:textAlignment="viewStart"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_root.xml b/packages/DocumentsUI/res/layout/item_root.xml
index ce97b57..98d78da 100644
--- a/packages/DocumentsUI/res/layout/item_root.xml
+++ b/packages/DocumentsUI/res/layout/item_root.xml
@@ -43,8 +43,8 @@
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textAlignment="viewStart" />
+ android:textAlignment="viewStart"
+ style="@style/TextAppearance.Medium" />
<TextView
android:id="@android:id/summary"
@@ -52,8 +52,8 @@
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textAlignment="viewStart" />
+ android:textAlignment="viewStart"
+ style="@style/TextAppearance.Small" />
</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_root_header.xml b/packages/DocumentsUI/res/layout/item_root_header.xml
index 127b254..6b9857d 100644
--- a/packages/DocumentsUI/res/layout/item_root_header.xml
+++ b/packages/DocumentsUI/res/layout/item_root_header.xml
@@ -14,6 +14,14 @@
limitations under the License.
-->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/title"
- style="?android:attr/listSeparatorTextViewStyle" />
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="12dp">
+
+ <TextView
+ android:id="@android:id/title"
+ android:textColor="?android:attr/textColorTertiary"
+ style="?android:attr/listSeparatorTextViewStyle" />
+
+</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_title.xml b/packages/DocumentsUI/res/layout/item_title.xml
index 9594e4e..7eb100a 100644
--- a/packages/DocumentsUI/res/layout/item_title.xml
+++ b/packages/DocumentsUI/res/layout/item_title.xml
@@ -38,7 +38,7 @@
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textAlignment="viewStart" />
+ android:textAlignment="viewStart"
+ style="@style/TextAppearance.Medium" />
</LinearLayout>
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index 6c37a4e..d995376 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -19,7 +19,7 @@
android:id="@+id/menu_create_dir"
android:title="@string/menu_create_dir"
android:icon="@drawable/ic_menu_new_folder"
- android:showAsAction="ifRoom" />
+ android:showAsAction="always" />
<item
android:id="@+id/menu_search"
android:title="@string/menu_search"
@@ -48,12 +48,12 @@
android:id="@+id/menu_grid"
android:title="@string/menu_grid"
android:icon="@drawable/ic_menu_view_grid"
- android:showAsAction="ifRoom" />
+ android:showAsAction="never" />
<item
android:id="@+id/menu_list"
android:title="@string/menu_list"
android:icon="@drawable/ic_menu_view_list"
- android:showAsAction="ifRoom" />
+ android:showAsAction="never" />
<item
android:id="@+id/menu_settings"
android:title="@string/menu_settings"
diff --git a/packages/DocumentsUI/res/menu/mode_directory.xml b/packages/DocumentsUI/res/menu/mode_directory.xml
index 624e0247..0a3645f 100644
--- a/packages/DocumentsUI/res/menu/mode_directory.xml
+++ b/packages/DocumentsUI/res/menu/mode_directory.xml
@@ -21,12 +21,12 @@
android:showAsAction="always" />
<item
android:id="@+id/menu_share"
- android:icon="@android:drawable/ic_menu_share"
+ android:icon="@drawable/ic_menu_share"
android:title="@string/menu_share"
android:showAsAction="always" />
<item
android:id="@+id/menu_delete"
- android:icon="@android:drawable/ic_menu_delete"
+ android:icon="@drawable/ic_menu_delete"
android:title="@string/menu_delete"
android:showAsAction="always" />
</menu>
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index a2c3023..2367e4c 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Kon nie dokument stoor nie"</string>
<string name="root_recent" msgid="4470053704320518133">"Onlangs"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> gratis"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Dienste"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Bergingdienste"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Kortpaaie"</string>
<string name="root_type_device" msgid="7121342474653483538">"Toestelle"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Nog programme"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Geen items nie"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Kan lêer nie oopmaak nie"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Kan sommige dokumente nie uitvee nie"</string>
- <string name="more" msgid="7117420986529297171">"Nog"</string>
- <string name="loading" msgid="7933681260296021180">"Laai tans..."</string>
<string name="share_via" msgid="8966594246261344259">"Deel via"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index 1e845b2..b940b2e 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"ሰነድ ማስቀመጥ አልተሳካም"</string>
<string name="root_recent" msgid="4470053704320518133">"የቅርብ ጊዜ"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ነፃ"</string>
- <string name="root_type_service" msgid="2857362700576006694">"አገልግሎቶች"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"የማከማቻ አገልግሎቶች"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"አቋራጮች"</string>
<string name="root_type_device" msgid="7121342474653483538">"መሣሪያዎች"</string>
<string name="root_type_apps" msgid="8838065367985945189">"ተጨማሪ መተግበሪያዎች"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"ምንም ንጥሎች የሉም"</string>
<string name="toast_no_application" msgid="1339885974067891667">"ፋይል መክፈት አይቻልም"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"አንዳንድ ሰነዶችን መሰረዝ አልተቻለም"</string>
- <string name="more" msgid="7117420986529297171">"ተጨማሪ"</string>
- <string name="loading" msgid="7933681260296021180">"በመጫን ላይ…"</string>
<string name="share_via" msgid="8966594246261344259">"በሚከተለው በኩል ያጋሩ"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index 279c0e6..6213450 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"أخفق حفظ المستند"</string>
<string name="root_recent" msgid="4470053704320518133">"الأخيرة"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> خالية"</string>
- <string name="root_type_service" msgid="2857362700576006694">"خدمات"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"خدمات التخزين"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"اختصارات"</string>
<string name="root_type_device" msgid="7121342474653483538">"أجهزة"</string>
<string name="root_type_apps" msgid="8838065367985945189">"المزيد من التطبيقات"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"ليس هناك أي عناصر"</string>
<string name="toast_no_application" msgid="1339885974067891667">"لا يمكن فتح الملف"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"تعذر حذف بعض المستندات"</string>
- <string name="more" msgid="7117420986529297171">"المزيد"</string>
- <string name="loading" msgid="7933681260296021180">"جارٍ التحميل…"</string>
<string name="share_via" msgid="8966594246261344259">"مشاركة عبر"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
index d405fe2..1374982 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml
+++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
@@ -38,7 +38,8 @@
<string name="save_error" msgid="6167009778003223664">"Sənədi yadda saxlaya bilmədi"</string>
<string name="root_recent" msgid="4470053704320518133">"Son"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ödənişsiz"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Xidmətlər"</string>
+ <!-- no translation found for root_type_service (2178854894416775409) -->
+ <skip />
<string name="root_type_shortcut" msgid="3318760609471618093">"Qısa yollar"</string>
<string name="root_type_device" msgid="7121342474653483538">"Cihazlar"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Daha çox tətbiq"</string>
@@ -48,7 +49,5 @@
<string name="empty" msgid="7858882803708117596">"Element yoxdur"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Faylı aça bilmir"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Bəzi sənədləri silə bilmir"</string>
- <string name="more" msgid="7117420986529297171">"Daha çox"</string>
- <string name="loading" msgid="7933681260296021180">"Yüklənir…"</string>
<string name="share_via" msgid="8966594246261344259">"Bunun vasitəsilə paylaş:"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-be/strings.xml b/packages/DocumentsUI/res/values-be/strings.xml
deleted file mode 100644
index 689a935..0000000
--- a/packages/DocumentsUI/res/values-be/strings.xml
+++ /dev/null
@@ -1,88 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (2783841764617238354) -->
- <skip />
- <!-- no translation found for title_open (4353228937663917801) -->
- <skip />
- <!-- no translation found for title_save (2433679664882857999) -->
- <skip />
- <!-- no translation found for menu_create_dir (5947289605844398389) -->
- <skip />
- <!-- no translation found for menu_grid (6878021334497835259) -->
- <skip />
- <!-- no translation found for menu_list (7279285939892417279) -->
- <skip />
- <!-- no translation found for menu_sort (7677740407158414452) -->
- <skip />
- <!-- no translation found for menu_search (3816712084502856974) -->
- <skip />
- <!-- no translation found for menu_settings (6008033148948428823) -->
- <skip />
- <!-- no translation found for menu_open (432922957274920903) -->
- <skip />
- <!-- no translation found for menu_save (2394743337684426338) -->
- <skip />
- <!-- no translation found for menu_share (3075149983979628146) -->
- <skip />
- <!-- no translation found for menu_delete (8138799623850614177) -->
- <skip />
- <!-- no translation found for mode_selected_count (459111894725594625) -->
- <skip />
- <!-- no translation found for sort_name (9183560467917256779) -->
- <skip />
- <!-- no translation found for sort_date (586080032956151448) -->
- <skip />
- <!-- no translation found for sort_size (3350681319735474741) -->
- <skip />
- <!-- no translation found for drawer_open (4545466532430226949) -->
- <skip />
- <!-- no translation found for drawer_close (7602734368552123318) -->
- <skip />
- <!-- no translation found for save_error (6167009778003223664) -->
- <skip />
- <!-- no translation found for root_recent (4470053704320518133) -->
- <skip />
- <!-- no translation found for root_available_bytes (8568452858617033281) -->
- <skip />
- <!-- no translation found for root_type_service (2857362700576006694) -->
- <skip />
- <!-- no translation found for root_type_shortcut (3318760609471618093) -->
- <skip />
- <!-- no translation found for root_type_device (7121342474653483538) -->
- <skip />
- <!-- no translation found for root_type_apps (8838065367985945189) -->
- <skip />
- <!-- no translation found for pref_advanced_devices (903257239609301276) -->
- <skip />
- <!-- no translation found for pref_file_size (2826879315743961459) -->
- <skip />
- <!-- no translation found for pref_device_size (3542106883278997222) -->
- <skip />
- <!-- no translation found for empty (7858882803708117596) -->
- <skip />
- <!-- no translation found for toast_no_application (1339885974067891667) -->
- <skip />
- <!-- no translation found for toast_failed_delete (2180678019407244069) -->
- <skip />
- <!-- no translation found for more (7117420986529297171) -->
- <skip />
- <string name="loading" msgid="7933681260296021180">"Загрузка..."</string>
- <!-- no translation found for share_via (8966594246261344259) -->
- <skip />
-</resources>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index 5ba9107..6eb4b20 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Запазването на документа не бе успешно"</string>
<string name="root_recent" msgid="4470053704320518133">"Скорошно"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Свободно: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Услуги"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Услуги за съхранение"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Преки пътища"</string>
<string name="root_type_device" msgid="7121342474653483538">"Устройства"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Още приложения"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Няма елементи"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Файлът не може да се отвори"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Някои документи не могат да бъдат изтрити"</string>
- <string name="more" msgid="7117420986529297171">"Още"</string>
- <string name="loading" msgid="7933681260296021180">"Зарежда се..."</string>
<string name="share_via" msgid="8966594246261344259">"Споделяне чрез"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index dfaead5..e8d340d 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"No s\'ha pogut desar el document."</string>
<string name="root_recent" msgid="4470053704320518133">"Recent"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> lliures"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Serveis"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Serveis d\'emmagatzematge"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Dreceres"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispositius"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Més aplicacions"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Sense elements"</string>
<string name="toast_no_application" msgid="1339885974067891667">"No es pot obrir el fitxer."</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"No es poden suprimir alguns documents."</string>
- <string name="more" msgid="7117420986529297171">"Més"</string>
- <string name="loading" msgid="7933681260296021180">"S\'està carregant…"</string>
<string name="share_via" msgid="8966594246261344259">"Comparteix mitjançant"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index 053a19a..5d736de 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Uložení dokumentu se nezdařilo"</string>
<string name="root_recent" msgid="4470053704320518133">"Poslední"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Volný prostor: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Služby"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Služby úložiště"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Klávesové zkratky"</string>
<string name="root_type_device" msgid="7121342474653483538">"Zařízení"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Další aplikace"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Žádné položky"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Soubor nelze otevřít"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Některé dokumenty nelze smazat"</string>
- <string name="more" msgid="7117420986529297171">"Více"</string>
- <string name="loading" msgid="7933681260296021180">"Načítání..."</string>
<string name="share_via" msgid="8966594246261344259">"Sdílet pomocí"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index 1c53326..0b1026a 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Dokumentet kunne ikke gemmes"</string>
<string name="root_recent" msgid="4470053704320518133">"Seneste"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ledig plads"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Tjenester"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Lagringstjenester"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Genveje"</string>
<string name="root_type_device" msgid="7121342474653483538">"Enheder"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Flere apps"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Ingen elementer"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Filen kan ikke åbnes"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Nogle dokumenter kan ikke slettes"</string>
- <string name="more" msgid="7117420986529297171">"Mere"</string>
- <string name="loading" msgid="7933681260296021180">"Indlæser…"</string>
<string name="share_via" msgid="8966594246261344259">"Del via"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index 3bbb35a..2729764 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Dokument konnte nicht gespeichert werden."</string>
<string name="root_recent" msgid="4470053704320518133">"Letzte"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> verfügbar"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Dienste"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Speicherdienste"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Verknüpfungen"</string>
<string name="root_type_device" msgid="7121342474653483538">"Geräte"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Weitere Apps"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Keine Elemente"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Datei kann nicht geöffnet werden."</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Einige Dokumente konnten nicht gelöscht werden."</string>
- <string name="more" msgid="7117420986529297171">"Mehr"</string>
- <string name="loading" msgid="7933681260296021180">"Wird geladen…"</string>
<string name="share_via" msgid="8966594246261344259">"Teilen über"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index a31aa13..35eabfb 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Αποτυχία αποθήκευσης του εγγράφου"</string>
<string name="root_recent" msgid="4470053704320518133">"Πρόσφατα"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ελεύθερα"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Υπηρεσίες"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Υπηρεσίες αποθήκευσης"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Συντομεύσεις"</string>
<string name="root_type_device" msgid="7121342474653483538">"Συσκευές"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Περισσότερες εφαρμογές"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Δεν υπάρχουν στοιχεία"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Δεν είναι δυνατό το άνοιγμα του αρχείου"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Δεν είναι δυνατή η διαγραφή ορισμένων εγγράφων"</string>
- <string name="more" msgid="7117420986529297171">"Περισσότερα"</string>
- <string name="loading" msgid="7933681260296021180">"Φόρτωση…"</string>
<string name="share_via" msgid="8966594246261344259">"Κοινή χρήση μέσω"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index b8f2926..15be21d 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Failed to save document"</string>
<string name="root_recent" msgid="4470053704320518133">"Recent"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> free"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Services"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Storage services"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Shortcuts"</string>
<string name="root_type_device" msgid="7121342474653483538">"Devices"</string>
<string name="root_type_apps" msgid="8838065367985945189">"More apps"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"No items"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Cannot open file"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Unable to delete some documents"</string>
- <string name="more" msgid="7117420986529297171">"More"</string>
- <string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="share_via" msgid="8966594246261344259">"Share via"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index b8f2926..15be21d 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Failed to save document"</string>
<string name="root_recent" msgid="4470053704320518133">"Recent"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> free"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Services"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Storage services"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Shortcuts"</string>
<string name="root_type_device" msgid="7121342474653483538">"Devices"</string>
<string name="root_type_apps" msgid="8838065367985945189">"More apps"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"No items"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Cannot open file"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Unable to delete some documents"</string>
- <string name="more" msgid="7117420986529297171">"More"</string>
- <string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="share_via" msgid="8966594246261344259">"Share via"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 91b0098..3b4b870 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Error al guardar el documento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recientes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> de espacio libre"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Servicios"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Almacenamiento"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Accesos directos"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Más aplicaciones"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Sin elementos"</string>
<string name="toast_no_application" msgid="1339885974067891667">"No se puede abrir el archivo."</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"No es posible eliminar algunos documentos."</string>
- <string name="more" msgid="7117420986529297171">"Más"</string>
- <string name="loading" msgid="7933681260296021180">"Cargando…"</string>
<string name="share_via" msgid="8966594246261344259">"Compartir mediante"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 099ccad..3fe73f9 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -24,12 +24,12 @@
<string name="menu_list" msgid="7279285939892417279">"Vista de lista"</string>
<string name="menu_sort" msgid="7677740407158414452">"Ordenar por"</string>
<string name="menu_search" msgid="3816712084502856974">"Buscar"</string>
- <string name="menu_settings" msgid="6008033148948428823">"Configuración"</string>
+ <string name="menu_settings" msgid="6008033148948428823">"Ajustes"</string>
<string name="menu_open" msgid="432922957274920903">"Abrir"</string>
<string name="menu_save" msgid="2394743337684426338">"Guardar"</string>
<string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
- <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> seleccionadas"</string>
+ <string name="mode_selected_count" msgid="459111894725594625">"Seleccionado: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nombre"</string>
<string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string>
<string name="sort_size" msgid="3350681319735474741">"Por tamaño"</string>
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Error al guardar documento"</string>
<string name="root_recent" msgid="4470053704320518133">"Reciente"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> de espacio libre"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Servicios"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Servicios almacenamiento"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Accesos directos"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Más aplicaciones"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Sin elementos"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Error al abrir el archivo"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"No es posible eliminar algunos documentos"</string>
- <string name="more" msgid="7117420986529297171">"Más"</string>
- <string name="loading" msgid="7933681260296021180">"Cargando..."</string>
<string name="share_via" msgid="8966594246261344259">"Compartir a través de"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index 0c21faa..be76e5d 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Dokumendi salvestamine ebaõnnestus"</string>
<string name="root_recent" msgid="4470053704320518133">"Hiljutised"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> on vaba"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Teenused"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Mäluruumi teenused"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Otseteed"</string>
<string name="root_type_device" msgid="7121342474653483538">"Seadmed"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Rohkem rakendusi"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Üksusi ei ole"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Faili ei saa avada"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Mõnda dokumenti ei õnnestu kustutada"</string>
- <string name="more" msgid="7117420986529297171">"Rohkem"</string>
- <string name="loading" msgid="7933681260296021180">"Laadimine ..."</string>
<string name="share_via" msgid="8966594246261344259">"Jagage teenusega"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index 9961af5..7dd1bf1 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"ذخیره سند انجام نشد"</string>
<string name="root_recent" msgid="4470053704320518133">"اخیر"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> آزاد"</string>
- <string name="root_type_service" msgid="2857362700576006694">"خدمات"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"خدمات ذخیرهسازی"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"میانبرها"</string>
<string name="root_type_device" msgid="7121342474653483538">"دستگاهها"</string>
<string name="root_type_apps" msgid="8838065367985945189">"برنامههای بیشتر"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"موردی موجود نیست"</string>
<string name="toast_no_application" msgid="1339885974067891667">"فایل باز نمیشود"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"برخی از اسناد حذف نمیشوند"</string>
- <string name="more" msgid="7117420986529297171">"بیشتر"</string>
- <string name="loading" msgid="7933681260296021180">"در حال بارگیری..."</string>
<string name="share_via" msgid="8966594246261344259">"اشتراکگذاری از طریق"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index c5c5eba..c4769c3 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Asiakirjan tallennus epäonnistui"</string>
<string name="root_recent" msgid="4470053704320518133">"Viimeisimmät"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> vapaana"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Palvelut"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Tallennuspalvelut"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Pikakuvakkeet"</string>
<string name="root_type_device" msgid="7121342474653483538">"Laitteet"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Lisää sovelluksia"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Ei kohteita"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Tiedostoa ei voi avata"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Joitakin asiakirjoja ei voi poistaa"</string>
- <string name="more" msgid="7117420986529297171">"Lisää"</string>
- <string name="loading" msgid="7933681260296021180">"Ladataan…"</string>
<string name="share_via" msgid="8966594246261344259">"Jaa sovelluksessa"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index 5bcc399..3364866 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Échec de l\'enregistrement du document"</string>
<string name="root_recent" msgid="4470053704320518133">"Récents"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> disponible"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Services"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Services de stockage"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Raccourcis"</string>
<string name="root_type_device" msgid="7121342474653483538">"Appareils"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Plus d\'applications"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Aucun élément"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Impossible d\'ouvrir le fichier"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Impossible de supprimer certains documents"</string>
- <string name="more" msgid="7117420986529297171">"Plus"</string>
- <string name="loading" msgid="7933681260296021180">"Chargement en cours..."</string>
<string name="share_via" msgid="8966594246261344259">"Partager par"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 0b83f02..a0ae800 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Échec de l\'enregistrement du document."</string>
<string name="root_recent" msgid="4470053704320518133">"Récents"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Espace disponible : <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Services"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Services de stockage"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Raccourcis"</string>
<string name="root_type_device" msgid="7121342474653483538">"Appareils"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Autres applications"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Aucun élément"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Impossible d\'ouvrir le fichier."</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Impossible de supprimer certains documents."</string>
- <string name="more" msgid="7117420986529297171">"Plus"</string>
- <string name="loading" msgid="7933681260296021180">"Chargement…"</string>
<string name="share_via" msgid="8966594246261344259">"Partager via"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index 290eff7..5b5ffcb 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -38,17 +38,15 @@
<string name="save_error" msgid="6167009778003223664">"दस्तावेज़ सहेजने में विफल रहा"</string>
<string name="root_recent" msgid="4470053704320518133">"हाल ही के"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> रिक्त"</string>
- <string name="root_type_service" msgid="2857362700576006694">"सेवाएं"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"संग्रहण सेवाएं"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"शॉर्टकट"</string>
<string name="root_type_device" msgid="7121342474653483538">"उपकरण"</string>
- <string name="root_type_apps" msgid="8838065367985945189">"अधिक एप्लिकेशन"</string>
+ <string name="root_type_apps" msgid="8838065367985945189">"अधिक एप्स"</string>
<string name="pref_advanced_devices" msgid="903257239609301276">"उन्नत उपकरणों को दिखाएं"</string>
<string name="pref_file_size" msgid="2826879315743961459">"फ़ाइल का आकार दिखाएं"</string>
<string name="pref_device_size" msgid="3542106883278997222">"उपकरण का आकार दिखाएं"</string>
<string name="empty" msgid="7858882803708117596">"कोई आइटम नहीं"</string>
<string name="toast_no_application" msgid="1339885974067891667">"फ़ाइल नहीं खोली जा सकती"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"कुछ दस्तावेज़ों को हटाने में अक्षम"</string>
- <string name="more" msgid="7117420986529297171">"अधिक"</string>
- <string name="loading" msgid="7933681260296021180">"लोड हो रहे हैं..."</string>
<string name="share_via" msgid="8966594246261344259">"इसके द्वारा साझा करें"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index f47a0f7..8b5e94c 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Nije uspjelo spremanje dokumenta"</string>
<string name="root_recent" msgid="4470053704320518133">"Nedavno"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> besplatno"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Usluge"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Usluge pohrane"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Prečaci"</string>
<string name="root_type_device" msgid="7121342474653483538">"Uređaji"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Više aplikacija"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Nema stavki"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Datoteku nije moguće otvoriti"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Nije moguće izbrisati neke dokumente"</string>
- <string name="more" msgid="7117420986529297171">"Više"</string>
- <string name="loading" msgid="7933681260296021180">"Učitavanje…"</string>
<string name="share_via" msgid="8966594246261344259">"Dijeli putem"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index 1187760..f1f450a 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Nem sikerült menteni a dokumentumot"</string>
<string name="root_recent" msgid="4470053704320518133">"Legutóbbiak"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> szabad"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Szolgáltatások"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Tárhelyszolgáltatások"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Parancsikonok"</string>
<string name="root_type_device" msgid="7121342474653483538">"Eszközök"</string>
<string name="root_type_apps" msgid="8838065367985945189">"További alkalmazások"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Nincsenek elemek"</string>
<string name="toast_no_application" msgid="1339885974067891667">"A fájlt nem lehet megnyitni"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Néhány dokumentumot nem lehet törölni"</string>
- <string name="more" msgid="7117420986529297171">"Továbbiak"</string>
- <string name="loading" msgid="7933681260296021180">"Betöltés..."</string>
<string name="share_via" msgid="8966594246261344259">"Megosztás itt:"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 38bf8b6..4d21561 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Չհաջողվեց պահել փաստաթուղթը"</string>
<string name="root_recent" msgid="4470053704320518133">"Վերջին"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ազատ է"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Ծառայություններ"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Պահուստի ծառայություններ"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Դյուրանցումներ"</string>
<string name="root_type_device" msgid="7121342474653483538">"Սարքեր"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Հավելյալ ծրագրեր"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Տարրեր չկան"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Հնարավոր չէ բացել ֆայլը"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Անհնար է ջնջել որոշ փաստաթղթեր"</string>
- <string name="more" msgid="7117420986529297171">"Ավելին"</string>
- <string name="loading" msgid="7933681260296021180">"Բեռնում..."</string>
<string name="share_via" msgid="8966594246261344259">"Տարածել"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 0857869..695196b 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Gagal menyimpan dokumen"</string>
<string name="root_recent" msgid="4470053704320518133">"Terkini"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> bebas"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Layanan"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Layanan penyimpanan"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Pintasan"</string>
<string name="root_type_device" msgid="7121342474653483538">"Perangkat"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Aplikasi lain"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Tidak ada item"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Tidak dapat membuka file"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Tidak dapat menghapus beberapa dokumen"</string>
- <string name="more" msgid="7117420986529297171">"Lainnya"</string>
- <string name="loading" msgid="7933681260296021180">"Memuat..."</string>
<string name="share_via" msgid="8966594246261344259">"Bagikan melalui"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index 9f97c1e..bb1a1d0 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Impossibile salvare il documento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recente"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> liberi"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Servizi"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Servizi di archiviazione"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Scorciatoie"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispositivi"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Altre app"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Nessun articolo"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Impossibile aprire il file"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Impossibile eliminare alcuni documenti"</string>
- <string name="more" msgid="7117420986529297171">"Altro"</string>
- <string name="loading" msgid="7933681260296021180">"Caricamento..."</string>
<string name="share_via" msgid="8966594246261344259">"Condividi via"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 904efb0..4b99d4d 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"שמירת המסמך נכשלה"</string>
<string name="root_recent" msgid="4470053704320518133">"מהזמן האחרון"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> של שטח פנוי"</string>
- <string name="root_type_service" msgid="2857362700576006694">"שירותים"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"שירותי אחסון"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"קיצורי דרך"</string>
<string name="root_type_device" msgid="7121342474653483538">"מכשירים"</string>
<string name="root_type_apps" msgid="8838065367985945189">"עוד אפליקציות"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"אין פריטים"</string>
<string name="toast_no_application" msgid="1339885974067891667">"לא ניתן לפתוח את הקובץ"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"לא ניתן למחוק חלק מהמסמכים"</string>
- <string name="more" msgid="7117420986529297171">"עוד"</string>
- <string name="loading" msgid="7933681260296021180">"טוען..."</string>
<string name="share_via" msgid="8966594246261344259">"שתף באמצעות"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index 3e473ab..034a14b 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"ドキュメントを保存できませんでした"</string>
<string name="root_recent" msgid="4470053704320518133">"最近"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"空き容量: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"サービス"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"ストレージサービス"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"ショートカット"</string>
<string name="root_type_device" msgid="7121342474653483538">"端末"</string>
<string name="root_type_apps" msgid="8838065367985945189">"その他のアプリ"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"アイテムがありません"</string>
<string name="toast_no_application" msgid="1339885974067891667">"ファイルを開けません"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"一部のドキュメントを削除できません"</string>
- <string name="more" msgid="7117420986529297171">"その他"</string>
- <string name="loading" msgid="7933681260296021180">"読み込んでいます..."</string>
<string name="share_via" msgid="8966594246261344259">"共有ツール"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index 26a83d7..89a8fad 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"დოკუმენტის შენახვა ვერ მოხერხდა"</string>
<string name="root_recent" msgid="4470053704320518133">"ბოლო"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> თავისუფალია"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Services"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"მეხსიერების სერვისები"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"მალსახმობები"</string>
<string name="root_type_device" msgid="7121342474653483538">"მოწყობილობები"</string>
<string name="root_type_apps" msgid="8838065367985945189">"მეტი აპები"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"ერთეულები არ არის"</string>
<string name="toast_no_application" msgid="1339885974067891667">"ფაილის გახსნა ვერ ხერხდება"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"ზოგიერთი დოკუმენტის წაშლა ვერ ხერხდება"</string>
- <string name="more" msgid="7117420986529297171">"მეტი"</string>
- <string name="loading" msgid="7933681260296021180">"ჩატვირთვა…"</string>
<string name="share_via" msgid="8966594246261344259">"გაზიარება:"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 12a82ba..876f8055 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"បានបរាជ័យក្នុងការរក្សាទុកឯកសារ"</string>
<string name="root_recent" msgid="4470053704320518133">"ថ្មីៗ"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"ទំនេរ <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"សេវាកម្ម"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"សេវាកម្មផ្ដល់ឧបករណ៍ផ្ទុក"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"ផ្លូវកាត់"</string>
<string name="root_type_device" msgid="7121342474653483538">"ឧបករណ៍"</string>
<string name="root_type_apps" msgid="8838065367985945189">"កម្មវិធីច្រើនទៀត"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"គ្មានធាតុ"</string>
<string name="toast_no_application" msgid="1339885974067891667">"មិនអាចបើកឯកសារ"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"មិនអាចលុបឯកសារមួយចំនួន"</string>
- <string name="more" msgid="7117420986529297171">"ច្រើនទៀត"</string>
- <string name="loading" msgid="7933681260296021180">"កំពុងផ្ទុក..."</string>
<string name="share_via" msgid="8966594246261344259">"ចែករំលែកតាម"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 6e90ff7..2beecd5 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"문서 저장 실패"</string>
<string name="root_recent" msgid="4470053704320518133">"최근"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> 남음"</string>
- <string name="root_type_service" msgid="2857362700576006694">"서비스"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"저장용량 서비스"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"바로가기"</string>
<string name="root_type_device" msgid="7121342474653483538">"기기"</string>
<string name="root_type_apps" msgid="8838065367985945189">"앱 더보기"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"항목 없음"</string>
<string name="toast_no_application" msgid="1339885974067891667">"파일을 열 수 없음"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"일부 문서를 삭제할 수 없음"</string>
- <string name="more" msgid="7117420986529297171">"더보기"</string>
- <string name="loading" msgid="7933681260296021180">"로드 중.."</string>
<string name="share_via" msgid="8966594246261344259">"공유 방법"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index e805643..08f0724 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"ການບັນທຶກເອກະສານລົ້ມເຫລວ"</string>
<string name="root_recent" msgid="4470053704320518133">"ຫາກໍໃຊ້"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"ຟຣີ <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"ບໍລິການ"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"ບໍລິການບ່ອນຈັດເກັບຂໍ້ມູນ"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"ທາງລັດ"</string>
<string name="root_type_device" msgid="7121342474653483538">"ອຸປະກອນ"</string>
<string name="root_type_apps" msgid="8838065367985945189">"ແອັບຯອື່ນໆ"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"ບໍ່ມີລາຍການ"</string>
<string name="toast_no_application" msgid="1339885974067891667">"ບໍ່ສາມດາເປີດໄຟລ໌ໄດ້"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"ບໍ່ສາມາດລຶບບາງເອກະສານໄດ້"</string>
- <string name="more" msgid="7117420986529297171">"ເພີ່ມເຕີມ"</string>
- <string name="loading" msgid="7933681260296021180">"ກຳລັງໂຫລດ..."</string>
<string name="share_via" msgid="8966594246261344259">"ແບ່ງປັນຜ່ານ"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index a5f9402..547d78c 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Nepavyko išsaugoti dokumento"</string>
<string name="root_recent" msgid="4470053704320518133">"Naujausi"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Laisvos vietos: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Paslaugos"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Saugyklos paslaugos"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Spartieji klavišai"</string>
<string name="root_type_device" msgid="7121342474653483538">"Įrenginiai"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Daugiau programų"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Nėra elementų"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Nepavyksta atidaryti failo"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Nepavyko ištrinti kai kurių dokumentų"</string>
- <string name="more" msgid="7117420986529297171">"Daugiau"</string>
- <string name="loading" msgid="7933681260296021180">"Įkeliama..."</string>
<string name="share_via" msgid="8966594246261344259">"Bendrinti naudojant"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 05470e8..7030f7a 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Neizdevās saglabāt dokumentu."</string>
<string name="root_recent" msgid="4470053704320518133">"Pēdējie"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Brīva vieta: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Pakalpojumi"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Glabāšanas pakalpojumi"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Saīsnes"</string>
<string name="root_type_device" msgid="7121342474653483538">"Ierīces"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Vairāk lietotņu"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Nav vienumu"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Nevar atvērt failu."</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Nevar dzēst dažus dokumentus."</string>
- <string name="more" msgid="7117420986529297171">"Vēl"</string>
- <string name="loading" msgid="7933681260296021180">"Notiek ielāde..."</string>
<string name="share_via" msgid="8966594246261344259">"Kopīgot, izmantojot"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 12cf6e1..69d1595 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Документыг хадгалж чадсангүй"</string>
<string name="root_recent" msgid="4470053704320518133">"Саяхны"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> чөлөөтэй"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Үйлчилгээнүүд"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Сангийн үйлчилгээ"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Товчлол"</string>
<string name="root_type_device" msgid="7121342474653483538">"Төхөөрөмжүүд"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Өөр апп-ууд"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Хоосон"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Файлыг нээх боломжгүй"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Зарим документуудыг устгах боломжгүй"</string>
- <string name="more" msgid="7117420986529297171">"Цааш"</string>
- <string name="loading" msgid="7933681260296021180">"Ачааллаж байна..."</string>
<string name="share_via" msgid="8966594246261344259">"Дараахаар дамжуулан хуваалцах"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index ba93dd1..ff404c2 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Gagal menyimpan dokumen"</string>
<string name="root_recent" msgid="4470053704320518133">"Terbaharu"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> kosong"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Perkhidmatan"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Perkhidmatan storan"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Pintasan"</string>
<string name="root_type_device" msgid="7121342474653483538">"Peranti"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Lebih banyak apl"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Tiada item"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Tidak dapat membuka fail"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Tidak dapat memadam beberapa dokumen"</string>
- <string name="more" msgid="7117420986529297171">"Lagi"</string>
- <string name="loading" msgid="7933681260296021180">"Memuatkan…"</string>
<string name="share_via" msgid="8966594246261344259">"Kongsi melalui"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 987b52da..41661c3 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Kunne ikke lagre dokumentet"</string>
<string name="root_recent" msgid="4470053704320518133">"Siste"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> gratis"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Tjenester"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Lagringstjenester"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Snarveier"</string>
<string name="root_type_device" msgid="7121342474653483538">"Enheter"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Flere apper"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Ingen elementer"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Kan ikke åpne filen"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Enkelte dokumenter kunne ikke slettes"</string>
- <string name="more" msgid="7117420986529297171">"Mer"</string>
- <string name="loading" msgid="7933681260296021180">"Laster inn …"</string>
<string name="share_via" msgid="8966594246261344259">"Del via"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index 6130b58..d2606df 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -38,7 +38,8 @@
<string name="save_error" msgid="6167009778003223664">"कागजात सुरक्षित गर्न विफल भयो"</string>
<string name="root_recent" msgid="4470053704320518133">"हालैको"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> खाली"</string>
- <string name="root_type_service" msgid="2857362700576006694">"सेवाहरू"</string>
+ <!-- no translation found for root_type_service (2178854894416775409) -->
+ <skip />
<string name="root_type_shortcut" msgid="3318760609471618093">"सर्टकटहरू"</string>
<string name="root_type_device" msgid="7121342474653483538">"उपकरणहरू"</string>
<string name="root_type_apps" msgid="8838065367985945189">"थप अनुप्रयोगहरू"</string>
@@ -48,7 +49,5 @@
<string name="empty" msgid="7858882803708117596">"कुनै वस्तु छैन।"</string>
<string name="toast_no_application" msgid="1339885974067891667">"फाइल खोल्न सक्दैन"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"केही कागजातहरू मेट्न असमर्थ छ"</string>
- <string name="more" msgid="7117420986529297171">"थप"</string>
- <string name="loading" msgid="7933681260296021180">"लोड हुँदै..."</string>
<string name="share_via" msgid="8966594246261344259">"माध्यमबाट साझेदारी गर्नुहोस्"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 03ba12c..4e1dfb7 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Kan document niet opslaan"</string>
<string name="root_recent" msgid="4470053704320518133">"Recent"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> vrij"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Services"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Opslagservices"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Sneltoetsen"</string>
<string name="root_type_device" msgid="7121342474653483538">"Apparaten"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Meer apps"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Geen items"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Kan bestand niet openen"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Kan bepaalde documenten niet verwijderen"</string>
- <string name="more" msgid="7117420986529297171">"Meer"</string>
- <string name="loading" msgid="7933681260296021180">"Laden..."</string>
<string name="share_via" msgid="8966594246261344259">"Delen via"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 8ef3e6f..412a84b 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -31,14 +31,14 @@
<string name="menu_delete" msgid="8138799623850614177">"Usuń"</string>
<string name="mode_selected_count" msgid="459111894725594625">"Wybrano: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Według nazwy"</string>
- <string name="sort_date" msgid="586080032956151448">"Według daty zmiany"</string>
+ <string name="sort_date" msgid="586080032956151448">"Według daty edycji"</string>
<string name="sort_size" msgid="3350681319735474741">"Według rozmiaru"</string>
<string name="drawer_open" msgid="4545466532430226949">"Pokaż elementy główne"</string>
<string name="drawer_close" msgid="7602734368552123318">"Ukryj elementy główne"</string>
<string name="save_error" msgid="6167009778003223664">"Nie udało się zapisać dokumentu"</string>
<string name="root_recent" msgid="4470053704320518133">"Ostatnie"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> wolne"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Usługi"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Usługi pamięci masowej"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Skróty"</string>
<string name="root_type_device" msgid="7121342474653483538">"Urządzenia"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Więcej aplikacji"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Brak elementów"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Nie można otworzyć pliku"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Nie można usunąć niektórych dokumentów"</string>
- <string name="more" msgid="7117420986529297171">"Więcej"</string>
- <string name="loading" msgid="7933681260296021180">"Wczytywanie…"</string>
<string name="share_via" msgid="8966594246261344259">"Udostępnij przez"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index 7ae43db..42efd0d 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Falha ao guardar o documento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recentes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> espaço livre"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Serviços"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Serv. de armazenamento"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Atalhos"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Mais aplicações"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Sem itens"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Não é possível abrir o ficheiro"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Não é possível eliminar alguns documentos"</string>
- <string name="more" msgid="7117420986529297171">"Mais"</string>
- <string name="loading" msgid="7933681260296021180">"A carregar…"</string>
<string name="share_via" msgid="8966594246261344259">"Partilhar através de"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index d07f78f..98bd74e 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Falha ao salvar o documento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recentes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> livres"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Serviços"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Serviços de armazenamento"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Atalhos"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Mais aplicativos"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Nenhum item"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Não é possível abrir o arquivo"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Não foi possível excluir alguns documentos"</string>
- <string name="more" msgid="7117420986529297171">"Mais"</string>
- <string name="loading" msgid="7933681260296021180">"Carregando…"</string>
<string name="share_via" msgid="8966594246261344259">"Compartilhar via"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 06ab5ff..b91d959 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Salvarea documentului nu a reușit"</string>
<string name="root_recent" msgid="4470053704320518133">"Recente"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> spațiu liber"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Servicii"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Servicii de stocare"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Comenzi rapide"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispozitive"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Alte aplicații"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Nu există elemente"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Fișierul nu poate fi deschis"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Unele documente nu au putut fi șterse"</string>
- <string name="more" msgid="7117420986529297171">"Mai multe"</string>
- <string name="loading" msgid="7933681260296021180">"Se încarcă…"</string>
- <string name="share_via" msgid="8966594246261344259">"Distribuiţi prin"</string>
+ <string name="share_via" msgid="8966594246261344259">"Distribuiți prin"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index 3b9c3f3..b099900 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Не удалось сохранить документ"</string>
<string name="root_recent" msgid="4470053704320518133">"Недавние"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Свободно <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Сервисы"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Службы хранения"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Ярлыки"</string>
<string name="root_type_device" msgid="7121342474653483538">"Устройства"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Другие приложения"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Ничего нет"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Не удалось открыть файл"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Не удалось удалить некоторые документы"</string>
- <string name="more" msgid="7117420986529297171">"Ещё"</string>
- <string name="loading" msgid="7933681260296021180">"Загрузка…"</string>
- <string name="share_via" msgid="8966594246261344259">"Способ отправки"</string>
+ <string name="share_via" msgid="8966594246261344259">"Поделиться"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index 9b1fb9b..6263b82 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -38,7 +38,8 @@
<string name="save_error" msgid="6167009778003223664">"ලේඛනය සුරැකීමට අපොහොසත් විය"</string>
<string name="root_recent" msgid="4470053704320518133">"මෑත"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ඉතිරියි"</string>
- <string name="root_type_service" msgid="2857362700576006694">"සේවා"</string>
+ <!-- no translation found for root_type_service (2178854894416775409) -->
+ <skip />
<string name="root_type_shortcut" msgid="3318760609471618093">"කෙටිමං"</string>
<string name="root_type_device" msgid="7121342474653483538">"උපාංග"</string>
<string name="root_type_apps" msgid="8838065367985945189">"තවත් යෙදුම්"</string>
@@ -48,7 +49,5 @@
<string name="empty" msgid="7858882803708117596">"අයිතම නැත"</string>
<string name="toast_no_application" msgid="1339885974067891667">"ගොනුව විවෘත කළ නොහැක"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"සමහර ලේඛන මැකීමට නොහැකි විය"</string>
- <string name="more" msgid="7117420986529297171">"තව"</string>
- <string name="loading" msgid="7933681260296021180">"පූරණය වෙමින්..."</string>
<string name="share_via" msgid="8966594246261344259">"හරහා බෙදාගන්න"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index a4850c1..0275cc6 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Dokument sa nepodarilo uložiť"</string>
<string name="root_recent" msgid="4470053704320518133">"Nedávne"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Voľné: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Služby"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Služby úložiska"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Skratky"</string>
<string name="root_type_device" msgid="7121342474653483538">"Zariadenia"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Ďalšie aplikácie"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Žiadne položky"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Súbor sa nepodarilo otvoriť"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Niektoré dokumenty sa nepodarilo odstrániť"</string>
- <string name="more" msgid="7117420986529297171">"Viac"</string>
- <string name="loading" msgid="7933681260296021180">"Prebieha načítavanie..."</string>
<string name="share_via" msgid="8966594246261344259">"Zdieľať pomocou"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index c1cfbd9..7e76193 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Dokumenta ni bilo mogoče shraniti"</string>
<string name="root_recent" msgid="4470053704320518133">"Nedavno"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Prosto: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Storitve"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Storitve shrambe"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Bližnjice"</string>
<string name="root_type_device" msgid="7121342474653483538">"Naprave"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Več aplikacij"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Ni elementov"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Datoteke ni mogoče odpreti"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Nekaterih dokumentov ni mogoče izbrisati"</string>
- <string name="more" msgid="7117420986529297171">"Več"</string>
- <string name="loading" msgid="7933681260296021180">"Nalaganje …"</string>
<string name="share_via" msgid="8966594246261344259">"Deli z drugimi prek"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index eaec4e5..48e32e9 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Чување документа није успело"</string>
<string name="root_recent" msgid="4470053704320518133">"Недавно"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Слободно је <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Услуге"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Услуге складиштења"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Пречице"</string>
<string name="root_type_device" msgid="7121342474653483538">"Уређаји"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Још апликација"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Нема ставки"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Није могуће отворити датотеку"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Није могуће избрисати неке документе"</string>
- <string name="more" msgid="7117420986529297171">"Још"</string>
- <string name="loading" msgid="7933681260296021180">"Учитавање…"</string>
- <string name="share_via" msgid="8966594246261344259">"Дељење преко"</string>
+ <string name="share_via" msgid="8966594246261344259">"Делите преко"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index 6d93d4d..7e2a5bb 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Det gick inte att spara dokumentet"</string>
<string name="root_recent" msgid="4470053704320518133">"Senaste"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ledigt"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Tjänster"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Lagringstjänster"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Genvägar"</string>
<string name="root_type_device" msgid="7121342474653483538">"Enheter"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Fler appar"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Inga objekt"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Det går inte att öppna filen"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Det gick inte att ta bort vissa dokument"</string>
- <string name="more" msgid="7117420986529297171">"Mer"</string>
- <string name="loading" msgid="7933681260296021180">"Läser in …"</string>
<string name="share_via" msgid="8966594246261344259">"Dela via"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index 915f851..9730836 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -31,14 +31,14 @@
<string name="menu_delete" msgid="8138799623850614177">"Futa"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> zimechaguliwa"</string>
<string name="sort_name" msgid="9183560467917256779">"Kwa jina"</string>
- <string name="sort_date" msgid="586080032956151448">"Kwa tarehe iliporekebishwa"</string>
+ <string name="sort_date" msgid="586080032956151448">"Kwa tarehe viliporekebishwa"</string>
<string name="sort_size" msgid="3350681319735474741">"Kwa ukubwa"</string>
<string name="drawer_open" msgid="4545466532430226949">"Onyesha usuli"</string>
<string name="drawer_close" msgid="7602734368552123318">"Ficha usuli"</string>
<string name="save_error" msgid="6167009778003223664">"Imeshindwa kuhifadhi hati"</string>
<string name="root_recent" msgid="4470053704320518133">"Hivi karibuni"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> bila malipo"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Huduma"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Huduma za hifadhi"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Njia za mkato"</string>
<string name="root_type_device" msgid="7121342474653483538">"Vifaa"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Programu zaidi"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Hakuna vipengee"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Haiwezi kufungua faili"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Imeshindwa kufuta baadhi ya hati"</string>
- <string name="more" msgid="7117420986529297171">"Zaidi"</string>
- <string name="loading" msgid="7933681260296021180">"Inapakia…"</string>
<string name="share_via" msgid="8966594246261344259">"Shiriki kupitia"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml b/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..961608c
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <bool name="always_show_summary">true</bool>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/dimens.xml b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
new file mode 100644
index 0000000..3be243a
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <bool name="show_as_dialog">true</bool>
+
+ <item type="dimen" name="dialog_width">85%</item>
+ <item type="dimen" name="dialog_height">90%</item>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/styles.xml b/packages/DocumentsUI/res/values-sw720dp/styles.xml
new file mode 100644
index 0000000..4ff1c60
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style name="Theme" parent="@android:style/Theme.Holo.Light">
+ <item name="android:windowBackground">@*android:drawable/dialog_full_holo_light</item>
+ <item name="android:colorBackgroundCacheHint">@null</item>
+ <item name="android:windowIsTranslucent">true</item>
+ </style>
+</resources>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index b1603f0..0436f5b 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"การบันทึกเอกสารล้มเหลว"</string>
<string name="root_recent" msgid="4470053704320518133">"ล่าสุด"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"ว่าง <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"บริการ"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"บริการที่เก็บข้อมูล"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"ทางลัด"</string>
<string name="root_type_device" msgid="7121342474653483538">"อุปกรณ์"</string>
<string name="root_type_apps" msgid="8838065367985945189">"แอปเพิ่มเติม"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"ไม่มีรายการ"</string>
<string name="toast_no_application" msgid="1339885974067891667">"ไม่สามารถเปิดไฟล์ได้"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"ไม่สามารถลบเอกสารบางรายการ"</string>
- <string name="more" msgid="7117420986529297171">"เพิ่มเติม"</string>
- <string name="loading" msgid="7933681260296021180">"กำลังโหลด..."</string>
<string name="share_via" msgid="8966594246261344259">"แชร์ผ่าน"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index d47be6f..298c2e2 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Hindi na-save ang dokumento"</string>
<string name="root_recent" msgid="4470053704320518133">"Kamakailan"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ang libre"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Mga Serbisyo"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Mga serbisyo ng storage"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Mga Shortcut"</string>
<string name="root_type_device" msgid="7121342474653483538">"Mga Device"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Higit pang apps"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Walang mga item"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Hindi mabuksan ang file"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Hindi matanggal ang ilang dokumento"</string>
- <string name="more" msgid="7117420986529297171">"Higit pa"</string>
- <string name="loading" msgid="7933681260296021180">"Naglo-load…"</string>
<string name="share_via" msgid="8966594246261344259">"Ibahagi sa pamamagitan ng"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 46688bd..c3f4594 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Doküman kaydedilemedi"</string>
<string name="root_recent" msgid="4470053704320518133">"En son"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> boş"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Hizmetler"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Depolama hizmetleri"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Kısayollar"</string>
<string name="root_type_device" msgid="7121342474653483538">"Cihazlar"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Diğer uygulamalar"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Öğe yok"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Dosya açılamıyor"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Bazı dokümanlar silinemiyor"</string>
- <string name="more" msgid="7117420986529297171">"Diğer"</string>
- <string name="loading" msgid="7933681260296021180">"Yükleniyor..."</string>
<string name="share_via" msgid="8966594246261344259">"Şunu kullanarak paylaş:"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index 1d793a1..f49e04c 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Не вдалося зберегти документ"</string>
<string name="root_recent" msgid="4470053704320518133">"Останні"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> вільного місця"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Служби"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Онлайн-сховища"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Ярлики"</string>
<string name="root_type_device" msgid="7121342474653483538">"Пристрої"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Інші програми"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Немає елементів"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Не вдалося відкрити файл"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Не вдалося видалити деякі документи"</string>
- <string name="more" msgid="7117420986529297171">"Більше"</string>
- <string name="loading" msgid="7933681260296021180">"Завантаження..."</string>
<string name="share_via" msgid="8966594246261344259">"Надіслати через"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 5a7e6cc..2c8a8b1 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Không lưu tài liệu được"</string>
<string name="root_recent" msgid="4470053704320518133">"Gần đây"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> còn trống"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Dịch vụ"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Dịch vụ lưu trữ"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Lối tắt"</string>
<string name="root_type_device" msgid="7121342474653483538">"Thiết bị"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Các ứng dụng khác"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Không có mục nào"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Không thể mở tệp"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Không thể xóa một số tài liệu"</string>
- <string name="more" msgid="7117420986529297171">"Thêm"</string>
- <string name="loading" msgid="7933681260296021180">"Đang tải…"</string>
<string name="share_via" msgid="8966594246261344259">"Chia sẻ qua"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 7b8f2f9..297312c 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -38,8 +38,8 @@
<string name="save_error" msgid="6167009778003223664">"无法保存文档"</string>
<string name="root_recent" msgid="4470053704320518133">"最近"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"可用空间:<xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"服务"</string>
- <string name="root_type_shortcut" msgid="3318760609471618093">"快捷方式"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"存储服务"</string>
+ <string name="root_type_shortcut" msgid="3318760609471618093">"捷径"</string>
<string name="root_type_device" msgid="7121342474653483538">"设备"</string>
<string name="root_type_apps" msgid="8838065367985945189">"更多应用"</string>
<string name="pref_advanced_devices" msgid="903257239609301276">"显示高级设备"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"无任何文件"</string>
<string name="toast_no_application" msgid="1339885974067891667">"无法打开文件"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"无法删除部分文档"</string>
- <string name="more" msgid="7117420986529297171">"更多"</string>
- <string name="loading" msgid="7933681260296021180">"正在加载..."</string>
- <string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
+ <string name="share_via" msgid="8966594246261344259">"分享方式"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 6fc0503..f90f5ff 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"無法儲存文件"</string>
<string name="root_recent" msgid="4470053704320518133">"近期用過"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"可用空間:<xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"服務"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"儲存空間服務"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"捷徑"</string>
<string name="root_type_device" msgid="7121342474653483538">"裝置"</string>
<string name="root_type_apps" msgid="8838065367985945189">"更多應用程式"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"沒有項目"</string>
<string name="toast_no_application" msgid="1339885974067891667">"無法開啟檔案"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"無法刪除部分文件"</string>
- <string name="more" msgid="7117420986529297171">"更多"</string>
- <string name="loading" msgid="7933681260296021180">"正在載入..."</string>
<string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index 8ca664d..9ed898a 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"無法儲存文件"</string>
<string name="root_recent" msgid="4470053704320518133">"最近使用過的項目"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"可用空間:<xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <string name="root_type_service" msgid="2857362700576006694">"服務"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"儲存空間服務"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"捷徑"</string>
<string name="root_type_device" msgid="7121342474653483538">"裝置"</string>
<string name="root_type_apps" msgid="8838065367985945189">"更多應用程式"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"沒有項目"</string>
<string name="toast_no_application" msgid="1339885974067891667">"無法開啟檔案"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"無法刪除部分文件"</string>
- <string name="more" msgid="7117420986529297171">"更多"</string>
- <string name="loading" msgid="7933681260296021180">"載入中…"</string>
<string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index 02db890..03ce312 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -38,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Yehlulekile ukulondoloza idokhumenti"</string>
<string name="root_recent" msgid="4470053704320518133">"Okwakamuva"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> okhululekile"</string>
- <string name="root_type_service" msgid="2857362700576006694">"Amasevisi"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Amasevisi wesitoreji"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Izinqamuleli"</string>
<string name="root_type_device" msgid="7121342474653483538">"Amadivayisi"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Izinhlelo zokusebenza eziningi"</string>
@@ -48,7 +48,5 @@
<string name="empty" msgid="7858882803708117596">"Azikho izinto"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Ayikwazi ukuvula ifayela"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Ayikwazi ukususa amanye amadokhumenti"</string>
- <string name="more" msgid="7117420986529297171">"Okuningi"</string>
- <string name="loading" msgid="7933681260296021180">"Iyalayisha…"</string>
<string name="share_via" msgid="8966594246261344259">"Yabelana nge-"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values/dimens.xml b/packages/DocumentsUI/res/values/dimens.xml
index e5b5b4e..25b0f84 100644
--- a/packages/DocumentsUI/res/values/dimens.xml
+++ b/packages/DocumentsUI/res/values/dimens.xml
@@ -19,4 +19,7 @@
<dimen name="root_icon_size">24dp</dimen>
<dimen name="grid_width">180dp</dimen>
<dimen name="grid_height">180dp</dimen>
+
+ <bool name="show_as_dialog">false</bool>
+ <bool name="always_show_summary">false</bool>
</resources>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index f4a822d..682ae4a 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -15,54 +15,83 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Title of the documents application [CHAR LIMIT=32] -->
<string name="app_label">Documents</string>
+ <!-- Action bar title prompting user to choose a location to open a document from [CHAR LIMIT=32] -->
<string name="title_open">Open from</string>
+ <!-- Action bar title prompting user to choose a location to save a document to [CHAR LIMIT=32] -->
<string name="title_save">Save to</string>
+ <!-- Menu item that creates a new directory/folder at the current location [CHAR LIMIT=24] -->
<string name="menu_create_dir">Create folder</string>
+ <!-- Menu item that switches view to show documents as a large-format grid of thumbnails [CHAR LIMIT=24] -->
<string name="menu_grid">Grid view</string>
+ <!-- Menu item that switches view to show documents as a list [CHAR LIMIT=24] -->
<string name="menu_list">List view</string>
+ <!-- Menu item that switches the criteria with which documents are sorted [CHAR LIMIT=24] -->
<string name="menu_sort">Sort by</string>
+ <!-- Menu item that enters a mode to search for documents [CHAR LIMIT=24] -->
<string name="menu_search">Search</string>
+ <!-- Menu item that enters activity to change settings [CHAR LIMIT=24] -->
<string name="menu_settings">Settings</string>
+ <!-- Menu item title that opens the selected documents [CHAR LIMIT=24] -->
<string name="menu_open">Open</string>
+ <!-- Menu item title that saves the current document [CHAR LIMIT=24] -->
<string name="menu_save">Save</string>
+ <!-- Menu item title that shares the selected documents [CHAR LIMIT=24] -->
<string name="menu_share">Share</string>
+ <!-- Menu item title that deletes the selected documents [CHAR LIMIT=24] -->
<string name="menu_delete">Delete</string>
+ <!-- Action mode title summarizing the number of documents selected [CHAR LIMIT=32] -->
<string name="mode_selected_count"><xliff:g id="count" example="3">%1$d</xliff:g> selected</string>
+ <!-- Mode that sorts documents by their display name alphabetically [CHAR LIMIT=24] -->
<string name="sort_name">By name</string>
+ <!-- Mode that sorts documents by their last modified time in descending order; most recent first [CHAR LIMIT=24] -->
<string name="sort_date">By date modified</string>
+ <!-- Mode that sorts documents by their file size in descending order; largest first [CHAR LIMIT=24] -->
<string name="sort_size">By size</string>
+ <!-- Accessibility title to open the drawer showing all roots where documents can be stored [CHAR LIMIT=32] -->
<string name="drawer_open">Show roots</string>
+ <!-- Accessibility title to close the drawer showing all roots where documents can be stored [CHAR LIMIT=32] -->
<string name="drawer_close">Hide roots</string>
+ <!-- Toast shown when saving a document failed with an error [CHAR LIMIT=48] -->
<string name="save_error">Failed to save document</string>
+ <!-- Title of storage root location that contains recently modified or used documents [CHAR LIMIT=24] -->
<string name="root_recent">Recent</string>
+ <!-- Subtitle of storage root indicating the total free space available, in bytes [CHAR LIMIT=24] -->
<string name="root_available_bytes"><xliff:g id="size" example="3GB">%1$s</xliff:g> free</string>
- <string name="root_type_service">Services</string>
+ <!-- Header title for list of storage roots that contains cloud services [CHAR LIMIT=24] -->
+ <string name="root_type_service">Storage services</string>
+ <!-- Header title for list of storage roots that contains shortcuts to documents that may be available elsewhere [CHAR LIMIT=24] -->
<string name="root_type_shortcut">Shortcuts</string>
+ <!-- Header title for list of storage roots that contains physical devices [CHAR LIMIT=24] -->
<string name="root_type_device">Devices</string>
+ <!-- Header title for list of additional apps that can provide documents [CHAR LIMIT=24] -->
<string name="root_type_apps">More apps</string>
+ <!-- Title for setting that will show all advanced storage devices [CHAR LIMIT=32] -->
<string name="pref_advanced_devices">Display advanced devices</string>
+ <!-- Title for setting that will show file sizes for all documents [CHAR LIMIT=32] -->
<string name="pref_file_size">Display file size</string>
<string name="pref_device_size">Display device size</string>
+ <!-- Text shown when a directory of documents is empty [CHAR LIMIT=24] -->
<string name="empty">No items</string>
+ <!-- Toast shown when no app can be found to open the selected document [CHAR LIMIT=48] -->
<string name="toast_no_application">Can\'t open file</string>
+ <!-- Toast shown when some of the selected documents failed to be deleted [CHAR LIMIT=48] -->
<string name="toast_failed_delete">Unable to delete some documents</string>
- <string name="more">More</string>
- <string name="loading">Loading\u2026</string>
-
+ <!-- Title of dialog when prompting user to select an app to share documents with [CHAR LIMIT=32] -->
<string name="share_via">Share via</string>
</resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
new file mode 100644
index 0000000..945e7ae
--- /dev/null
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style name="TextAppearance" />
+
+ <style name="TextAppearance.Medium">
+ <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+
+ <style name="TextAppearance.Small">
+ <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+ <item name="android:textColor">?android:attr/textColorTertiary</item>
+ </style>
+
+ <!-- Normally just a redirection, but this is used to make ourselves a
+ dialog on large tablets -->
+ <style name="Theme" parent="@android:style/Theme.Holo.Light" />
+</resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index f9ac3f3..198927c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -31,15 +31,18 @@
import android.app.FragmentTransaction;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ContentResolver;
+import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Point;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.CancellationSignal;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.text.format.DateUtils;
@@ -55,6 +58,7 @@
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.MultiChoiceModeListener;
+import android.widget.AbsListView.RecyclerListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
@@ -65,6 +69,7 @@
import android.widget.Toast;
import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.RecentsProvider.StateColumns;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
import com.android.internal.util.Predicate;
@@ -95,6 +100,9 @@
private int mLastMode = MODE_UNKNOWN;
private int mLastSortOrder = SORT_ORDER_UNKNOWN;
+ private boolean mLastShowSize = false;
+
+ private boolean mHideGridTitles = false;
private Point mThumbSize;
@@ -106,11 +114,6 @@
private static final String EXTRA_DOC = "doc";
private static final String EXTRA_QUERY = "query";
- /**
- * MIME types that should always show thumbnails in list mode.
- */
- private static final String[] LIST_THUMBNAIL_MIMES = new String[] { "image/*", "video/*" };
-
private static AtomicInteger sLoaderId = new AtomicInteger(4000);
private final int mLoaderId = sLoaderId.incrementAndGet();
@@ -119,9 +122,8 @@
show(fm, TYPE_NORMAL, root, doc, null);
}
- public static void showSearch(
- FragmentManager fm, RootInfo root, DocumentInfo doc, String query) {
- show(fm, TYPE_SEARCH, root, doc, query);
+ public static void showSearch(FragmentManager fm, RootInfo root, String query) {
+ show(fm, TYPE_SEARCH, root, null, query);
}
public static void showRecentsOpen(FragmentManager fm) {
@@ -160,10 +162,12 @@
mListView = (ListView) view.findViewById(R.id.list);
mListView.setOnItemClickListener(mItemListener);
mListView.setMultiChoiceModeListener(mMultiListener);
+ mListView.setRecyclerListener(mRecycleListener);
mGridView = (GridView) view.findViewById(R.id.grid);
mGridView.setOnItemClickListener(mItemListener);
mGridView.setMultiChoiceModeListener(mMultiListener);
+ mGridView.setRecyclerListener(mRecycleListener);
return view;
}
@@ -175,14 +179,23 @@
final Context context = getActivity();
final State state = getDisplayState(DirectoryFragment.this);
+ final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
+ final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
+
mAdapter = new DocumentsAdapter();
mType = getArguments().getInt(EXTRA_TYPE);
+ if (mType == TYPE_RECENT_OPEN) {
+ // Hide titles when showing recents for picking images/videos
+ mHideGridTitles = MimePredicate.mimeMatches(
+ MimePredicate.VISUAL_MIMES, state.acceptMimes);
+ } else {
+ mHideGridTitles = (doc != null) && doc.isGridTitlesHidden();
+ }
+
mCallbacks = new LoaderCallbacks<DirectoryResult>() {
@Override
public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
- final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
- final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
final String query = getArguments().getString(EXTRA_QUERY);
Uri contentsUri;
@@ -190,11 +203,19 @@
case TYPE_NORMAL:
contentsUri = DocumentsContract.buildChildDocumentsUri(
doc.authority, doc.documentId);
- return new DirectoryLoader(context, root, doc, contentsUri);
+ if (state.action == ACTION_MANAGE) {
+ contentsUri = DocumentsContract.setManageMode(contentsUri);
+ }
+ return new DirectoryLoader(
+ context, mType, root, doc, contentsUri, state.userSortOrder);
case TYPE_SEARCH:
contentsUri = DocumentsContract.buildSearchDocumentsUri(
- doc.authority, doc.documentId, query);
- return new DirectoryLoader(context, root, doc, contentsUri);
+ root.authority, root.rootId, query);
+ if (state.action == ACTION_MANAGE) {
+ contentsUri = DocumentsContract.setManageMode(contentsUri);
+ }
+ return new DirectoryLoader(
+ context, mType, root, doc, contentsUri, state.userSortOrder);
case TYPE_RECENT_OPEN:
final RootsCache roots = DocumentsApplication.getRootsCache(context);
final List<RootInfo> matchingRoots = roots.getMatchingRoots(state);
@@ -212,14 +233,16 @@
// Push latest state up to UI
// TODO: if mode change was racing with us, don't overwrite it
- state.mode = result.mode;
- state.sortOrder = result.sortOrder;
+ if (result.mode != MODE_UNKNOWN) {
+ state.derivedMode = result.mode;
+ }
+ state.derivedSortOrder = result.sortOrder;
((DocumentsActivity) context).onStateChanged();
updateDisplayState();
- if (mLastSortOrder != result.sortOrder) {
- mLastSortOrder = result.sortOrder;
+ if (mLastSortOrder != state.derivedSortOrder) {
+ mLastSortOrder = state.derivedSortOrder;
mListView.smoothScrollToPosition(0);
mGridView.smoothScrollToPosition(0);
}
@@ -238,18 +261,44 @@
}
@Override
- public void onStart() {
- super.onStart();
+ public void onResume() {
+ super.onResume();
updateDisplayState();
}
public void onUserSortOrderChanged() {
- // User change always triggers reload
+ // Sort order change always triggers reload; we'll trigger state change
+ // on the flip side.
getLoaderManager().restartLoader(mLoaderId, null, mCallbacks);
}
public void onUserModeChanged() {
- // Mode change is just display; no need to reload
+ final ContentResolver resolver = getActivity().getContentResolver();
+ final State state = getDisplayState(this);
+
+ final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
+ final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
+
+ if (root != null && doc != null) {
+ final Uri stateUri = RecentsProvider.buildState(
+ root.authority, root.rootId, doc.documentId);
+ final ContentValues values = new ContentValues();
+ values.put(StateColumns.MODE, state.userMode);
+
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ resolver.insert(stateUri, values);
+ return null;
+ }
+ }.execute();
+ }
+
+ // Mode change is just visual change; no need to kick loader, and
+ // deliver change event immediately.
+ state.derivedMode = state.userMode;
+ ((DocumentsActivity) getActivity()).onStateChanged();
+
updateDisplayState();
}
@@ -258,11 +307,12 @@
mFilter = new MimePredicate(state.acceptMimes);
- if (mLastMode == state.mode) return;
- mLastMode = state.mode;
+ if (mLastMode == state.derivedMode && mLastShowSize == state.showSize) return;
+ mLastMode = state.derivedMode;
+ mLastShowSize = state.showSize;
- mListView.setVisibility(state.mode == MODE_LIST ? View.VISIBLE : View.GONE);
- mGridView.setVisibility(state.mode == MODE_GRID ? View.VISIBLE : View.GONE);
+ mListView.setVisibility(state.derivedMode == MODE_LIST ? View.VISIBLE : View.GONE);
+ mGridView.setVisibility(state.derivedMode == MODE_GRID ? View.VISIBLE : View.GONE);
final int choiceMode;
if (state.allowMultiple) {
@@ -272,7 +322,7 @@
}
final int thumbSize;
- if (state.mode == MODE_GRID) {
+ if (state.derivedMode == MODE_GRID) {
thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width);
mListView.setAdapter(null);
mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
@@ -281,7 +331,7 @@
mGridView.setNumColumns(GridView.AUTO_FIT);
mGridView.setChoiceMode(choiceMode);
mCurrentView = mGridView;
- } else if (state.mode == MODE_LIST) {
+ } else if (state.derivedMode == MODE_LIST) {
thumbSize = getResources().getDimensionPixelSize(R.dimen.icon_size);
mGridView.setAdapter(null);
mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE);
@@ -289,7 +339,7 @@
mListView.setChoiceMode(choiceMode);
mCurrentView = mListView;
} else {
- throw new IllegalStateException("Unknown state " + state.mode);
+ throw new IllegalStateException("Unknown state " + state.derivedMode);
}
mThumbSize = new Point(thumbSize, thumbSize);
@@ -397,6 +447,20 @@
}
};
+ private RecyclerListener mRecycleListener = new RecyclerListener() {
+ @Override
+ public void onMovedToScrapHeap(View view) {
+ final ImageView iconThumb = (ImageView) view.findViewById(R.id.icon_thumb);
+ if (iconThumb != null) {
+ final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) iconThumb.getTag();
+ if (oldTask != null) {
+ oldTask.reallyCancel();
+ iconThumb.setTag(null);
+ }
+ }
+ }
+ };
+
private void onShareDocuments(List<DocumentInfo> docs) {
Intent intent;
if (docs.size() == 1) {
@@ -472,7 +536,7 @@
}
}
- private static class LoadingFooter extends Footer {
+ private class LoadingFooter extends Footer {
public LoadingFooter() {
super(1);
}
@@ -480,10 +544,19 @@
@Override
public View getView(View convertView, ViewGroup parent) {
final Context context = parent.getContext();
+ final State state = getDisplayState(DirectoryFragment.this);
+
if (convertView == null) {
final LayoutInflater inflater = LayoutInflater.from(context);
- convertView = inflater.inflate(R.layout.item_loading, parent, false);
+ if (state.derivedMode == MODE_LIST) {
+ convertView = inflater.inflate(R.layout.item_loading_list, parent, false);
+ } else if (state.derivedMode == MODE_GRID) {
+ convertView = inflater.inflate(R.layout.item_loading_grid, parent, false);
+ } else {
+ throw new IllegalStateException();
+ }
}
+
return convertView;
}
}
@@ -505,9 +578,9 @@
if (convertView == null) {
final LayoutInflater inflater = LayoutInflater.from(context);
- if (state.mode == MODE_LIST) {
+ if (state.derivedMode == MODE_LIST) {
convertView = inflater.inflate(R.layout.item_message_list, parent, false);
- } else if (state.mode == MODE_GRID) {
+ } else if (state.derivedMode == MODE_GRID) {
convertView = inflater.inflate(R.layout.item_message_grid, parent, false);
} else {
throw new IllegalStateException();
@@ -576,15 +649,17 @@
final Context context = parent.getContext();
final State state = getDisplayState(DirectoryFragment.this);
+ final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
+
final RootsCache roots = DocumentsApplication.getRootsCache(context);
final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
context, mThumbSize);
if (convertView == null) {
final LayoutInflater inflater = LayoutInflater.from(context);
- if (state.mode == MODE_LIST) {
+ if (state.derivedMode == MODE_LIST) {
convertView = inflater.inflate(R.layout.item_doc_list, parent, false);
- } else if (state.mode == MODE_GRID) {
+ } else if (state.derivedMode == MODE_GRID) {
convertView = inflater.inflate(R.layout.item_doc_grid, parent, false);
} else {
throw new IllegalStateException();
@@ -604,60 +679,127 @@
final String docSummary = getCursorString(cursor, Document.COLUMN_SUMMARY);
final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
- final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
- final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+ final View line1 = convertView.findViewById(R.id.line1);
final View line2 = convertView.findViewById(R.id.line2);
+
+ final View icon = convertView.findViewById(android.R.id.icon);
+ final ImageView iconMime = (ImageView) convertView.findViewById(R.id.icon_mime);
+ final ImageView iconThumb = (ImageView) convertView.findViewById(R.id.icon_thumb);
+ final TextView title = (TextView) convertView.findViewById(android.R.id.title);
final ImageView icon1 = (ImageView) convertView.findViewById(android.R.id.icon1);
+ final ImageView icon2 = (ImageView) convertView.findViewById(android.R.id.icon2);
final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
final TextView date = (TextView) convertView.findViewById(R.id.date);
final TextView size = (TextView) convertView.findViewById(R.id.size);
- final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) icon.getTag();
+ final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) iconThumb.getTag();
if (oldTask != null) {
- oldTask.cancel(false);
+ oldTask.reallyCancel();
+ iconThumb.setTag(null);
}
- final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
- final boolean allowThumbnail = (state.mode == MODE_GRID)
- || MimePredicate.mimeMatches(LIST_THUMBNAIL_MIMES, docMimeType);
+ iconMime.animate().cancel();
+ iconThumb.animate().cancel();
- if (supportsThumbnail && allowThumbnail) {
+ final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
+ final boolean allowThumbnail = (state.derivedMode == MODE_GRID)
+ || MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, docMimeType);
+ final boolean showThumbnail = supportsThumbnail && allowThumbnail;
+
+ boolean cacheHit = false;
+ if (showThumbnail) {
final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
final Bitmap cachedResult = thumbs.get(uri);
if (cachedResult != null) {
- icon.setImageBitmap(cachedResult);
+ iconThumb.setImageBitmap(cachedResult);
+ cacheHit = true;
} else {
- final ThumbnailAsyncTask task = new ThumbnailAsyncTask(icon, mThumbSize);
- icon.setImageBitmap(null);
- icon.setTag(task);
- task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, uri);
+ iconThumb.setImageDrawable(null);
+ final ThumbnailAsyncTask task = new ThumbnailAsyncTask(
+ uri, iconMime, iconThumb, mThumbSize);
+ iconThumb.setTag(task);
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
- } else if (docIcon != 0) {
- icon.setImageDrawable(IconUtils.loadPackageIcon(context, docAuthority, docIcon));
- } else {
- icon.setImageDrawable(IconUtils.loadMimeIcon(context, docMimeType));
}
- title.setText(docDisplayName);
+ // Always throw MIME icon into place, even when a thumbnail is being
+ // loaded in background.
+ if (cacheHit) {
+ iconMime.setAlpha(0f);
+ iconThumb.setAlpha(1f);
+ } else {
+ iconMime.setAlpha(1f);
+ iconThumb.setAlpha(0f);
+ if (docIcon != 0) {
+ iconMime.setImageDrawable(
+ IconUtils.loadPackageIcon(context, docAuthority, docIcon));
+ } else {
+ iconMime.setImageDrawable(IconUtils.loadMimeIcon(context, docMimeType));
+ }
+ }
+ boolean hasLine1 = false;
boolean hasLine2 = false;
+ final boolean hideTitle = (state.derivedMode == MODE_GRID) && mHideGridTitles;
+ if (!hideTitle) {
+ title.setText(docDisplayName);
+ hasLine1 = true;
+ }
+
+ Drawable iconDrawable = null;
if (mType == TYPE_RECENT_OPEN) {
final RootInfo root = roots.getRoot(docAuthority, docRootId);
- icon1.setVisibility(View.VISIBLE);
- icon1.setImageDrawable(root.loadIcon(context));
- summary.setText(root.getDirectoryString());
- summary.setVisibility(View.VISIBLE);
- summary.setTextAlignment(TextView.TEXT_ALIGNMENT_TEXT_END);
- hasLine2 = true;
+ iconDrawable = root.loadIcon(context);
+
+ if (summary != null) {
+ final boolean alwaysShowSummary = getResources()
+ .getBoolean(R.bool.always_show_summary);
+ if (alwaysShowSummary) {
+ summary.setText(root.getDirectoryString());
+ summary.setVisibility(View.VISIBLE);
+ hasLine2 = true;
+ } else {
+ if (iconDrawable != null && roots.isIconUnique(root)) {
+ // No summary needed if icon speaks for itself
+ summary.setVisibility(View.INVISIBLE);
+ } else {
+ summary.setText(root.getDirectoryString());
+ summary.setVisibility(View.VISIBLE);
+ summary.setTextAlignment(TextView.TEXT_ALIGNMENT_TEXT_END);
+ hasLine2 = true;
+ }
+ }
+ }
} else {
- icon1.setVisibility(View.GONE);
- if (docSummary != null) {
- summary.setText(docSummary);
- summary.setVisibility(View.VISIBLE);
- hasLine2 = true;
+ // Directories showing thumbnails in grid mode get a little icon
+ // hint to remind user they're a directory.
+ if (Document.MIME_TYPE_DIR.equals(docMimeType) && state.derivedMode == MODE_GRID
+ && showThumbnail) {
+ iconDrawable = context.getResources().getDrawable(R.drawable.ic_root_folder);
+ }
+
+ if (summary != null) {
+ if (docSummary != null) {
+ summary.setText(docSummary);
+ summary.setVisibility(View.VISIBLE);
+ hasLine2 = true;
+ } else {
+ summary.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
+ if (icon1 != null) icon1.setVisibility(View.GONE);
+ if (icon2 != null) icon2.setVisibility(View.GONE);
+
+ if (iconDrawable != null) {
+ if (hasLine1) {
+ icon1.setVisibility(View.VISIBLE);
+ icon1.setImageDrawable(iconDrawable);
} else {
- summary.setVisibility(View.INVISIBLE);
+ icon2.setVisibility(View.VISIBLE);
+ icon2.setImageDrawable(iconDrawable);
}
}
@@ -680,18 +822,25 @@
size.setVisibility(View.GONE);
}
- line2.setVisibility(hasLine2 ? View.VISIBLE : View.GONE);
+ if (line1 != null) {
+ line1.setVisibility(hasLine1 ? View.VISIBLE : View.GONE);
+ }
+ if (line2 != null) {
+ line2.setVisibility(hasLine2 ? View.VISIBLE : View.GONE);
+ }
final boolean enabled = Document.MIME_TYPE_DIR.equals(docMimeType)
|| MimePredicate.mimeMatches(state.acceptMimes, docMimeType);
if (enabled) {
setEnabledRecursive(convertView, true);
icon.setAlpha(1f);
- icon1.setAlpha(1f);
+ if (icon1 != null) icon1.setAlpha(1f);
+ if (icon2 != null) icon2.setAlpha(1f);
} else {
setEnabledRecursive(convertView, false);
icon.setAlpha(0.5f);
- icon1.setAlpha(0.5f);
+ if (icon1 != null) icon1.setAlpha(0.5f);
+ if (icon2 != null) icon2.setAlpha(0.5f);
}
return convertView;
@@ -734,32 +883,39 @@
}
private static class ThumbnailAsyncTask extends AsyncTask<Uri, Void, Bitmap> {
- private final ImageView mTarget;
+ private final Uri mUri;
+ private final ImageView mIconMime;
+ private final ImageView mIconThumb;
private final Point mThumbSize;
+ private final CancellationSignal mSignal;
- public ThumbnailAsyncTask(ImageView target, Point thumbSize) {
- mTarget = target;
+ public ThumbnailAsyncTask(
+ Uri uri, ImageView iconMime, ImageView iconThumb, Point thumbSize) {
+ mUri = uri;
+ mIconMime = iconMime;
+ mIconThumb = iconThumb;
mThumbSize = thumbSize;
+ mSignal = new CancellationSignal();
}
- @Override
- protected void onPreExecute() {
- mTarget.setTag(this);
+ public void reallyCancel() {
+ cancel(false);
+ mSignal.cancel();
}
@Override
protected Bitmap doInBackground(Uri... params) {
- final Context context = mTarget.getContext();
- final Uri uri = params[0];
+ final Context context = mIconThumb.getContext();
Bitmap result = null;
try {
+ // TODO: switch to using unstable provider
result = DocumentsContract.getDocumentThumbnail(
- context.getContentResolver(), uri, mThumbSize, null);
+ context.getContentResolver(), mUri, mThumbSize, mSignal);
if (result != null) {
final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
context, mThumbSize);
- thumbs.put(uri, result);
+ thumbs.put(mUri, result);
}
} catch (Exception e) {
Log.w(TAG, "Failed to load thumbnail: " + e);
@@ -769,9 +925,14 @@
@Override
protected void onPostExecute(Bitmap result) {
- if (mTarget.getTag() == this) {
- mTarget.setImageBitmap(result);
- mTarget.setTag(null);
+ if (mIconThumb.getTag() == this && result != null) {
+ mIconThumb.setTag(null);
+ mIconThumb.setImageBitmap(result);
+
+ mIconMime.setAlpha(1f);
+ mIconMime.animate().alpha(0f).start();
+ mIconThumb.setAlpha(0f);
+ mIconThumb.animate().alpha(1f).start();
}
}
}
@@ -822,6 +983,7 @@
}
private void setEnabledRecursive(View v, boolean enabled) {
+ if (v == null) return;
if (v.isEnabled() == enabled) return;
v.setEnabled(enabled);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 72dfa30..8627ecf 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -32,6 +32,7 @@
import android.net.Uri;
import android.os.CancellationSignal;
import android.os.OperationCanceledException;
+import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.util.Log;
@@ -42,6 +43,8 @@
import libcore.io.IoUtils;
+import java.io.FileNotFoundException;
+
class DirectoryResult implements AutoCloseable {
ContentProviderClient client;
Cursor cursor;
@@ -62,18 +65,23 @@
public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
+ private final int mType;
private final RootInfo mRoot;
- private final DocumentInfo mDoc;
+ private DocumentInfo mDoc;
private final Uri mUri;
+ private final int mUserSortOrder;
private CancellationSignal mSignal;
private DirectoryResult mResult;
- public DirectoryLoader(Context context, RootInfo root, DocumentInfo doc, Uri uri) {
+ public DirectoryLoader(Context context, int type, RootInfo root, DocumentInfo doc, Uri uri,
+ int userSortOrder) {
super(context);
+ mType = type;
mRoot = root;
mDoc = doc;
mUri = uri;
+ mUserSortOrder = userSortOrder;
}
@Override
@@ -91,7 +99,19 @@
final DirectoryResult result = new DirectoryResult();
int userMode = State.MODE_UNKNOWN;
- int userSortOrder = State.SORT_ORDER_UNKNOWN;
+
+ // Use default document when searching
+ if (mType == DirectoryFragment.TYPE_SEARCH) {
+ final Uri docUri = DocumentsContract.buildDocumentUri(
+ mRoot.authority, mRoot.documentId);
+ try {
+ mDoc = DocumentInfo.fromUri(resolver, docUri);
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Failed to query", e);
+ result.exception = e;
+ return result;
+ }
+ }
// Pick up any custom modes requested by user
Cursor cursor = null;
@@ -101,7 +121,6 @@
cursor = resolver.query(stateUri, null, null, null, null);
if (cursor.moveToFirst()) {
userMode = getCursorInt(cursor, StateColumns.MODE);
- userSortOrder = getCursorInt(cursor, StateColumns.SORT_ORDER);
}
} finally {
IoUtils.closeQuietly(cursor);
@@ -117,8 +136,8 @@
}
}
- if (userSortOrder != State.SORT_ORDER_UNKNOWN) {
- result.sortOrder = userSortOrder;
+ if (mUserSortOrder != State.SORT_ORDER_UNKNOWN) {
+ result.sortOrder = mUserSortOrder;
} else {
if ((mDoc.flags & Document.FLAG_DIR_PREFERS_LAST_MODIFIED) != 0) {
result.sortOrder = State.SORT_ORDER_LAST_MODIFIED;
@@ -127,7 +146,12 @@
}
}
- Log.d(TAG, "userMode=" + userMode + ", userSortOrder=" + userSortOrder + " --> mode="
+ // Search always uses ranking from provider
+ if (mType == DirectoryFragment.TYPE_SEARCH) {
+ result.sortOrder = State.SORT_ORDER_UNKNOWN;
+ }
+
+ Log.d(TAG, "userMode=" + userMode + ", userSortOrder=" + mUserSortOrder + " --> mode="
+ result.mode + ", sortOrder=" + result.sortOrder);
try {
@@ -136,13 +160,20 @@
mUri, null, null, null, getQuerySortOrder(result.sortOrder), mSignal);
cursor.registerContentObserver(mObserver);
- final Cursor withRoot = new RootCursorWrapper(
- mUri.getAuthority(), mRoot.rootId, cursor, -1);
- final Cursor sorted = new SortingCursorWrapper(withRoot, result.sortOrder);
+ cursor = new RootCursorWrapper(mUri.getAuthority(), mRoot.rootId, cursor, -1);
- result.cursor = sorted;
+ if (mType == DirectoryFragment.TYPE_SEARCH) {
+ // Filter directories out of search results, for now
+ cursor = new FilteringCursorWrapper(cursor, null, new String[] {
+ Document.MIME_TYPE_DIR });
+ } else {
+ // Normal directories should have sorting applied
+ cursor = new SortingCursorWrapper(cursor, result.sortOrder);
+ }
+
+ result.cursor = cursor;
} catch (Exception e) {
- Log.d(TAG, "Failed to query", e);
+ Log.w(TAG, "Failed to query", e);
result.exception = e;
ContentProviderClient.closeQuietly(result.client);
} finally {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index fe39800..f6cb481 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -22,7 +22,6 @@
import static com.android.documentsui.DocumentsActivity.State.ACTION_OPEN;
import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
import android.app.ActionBar;
import android.app.ActionBar.OnNavigationListener;
@@ -36,12 +35,17 @@
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.database.Cursor;
+import android.graphics.Point;
import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Root;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
@@ -50,19 +54,21 @@
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.MenuItem.OnActionExpandListener;
+import android.view.MotionEvent;
import android.view.View;
+import android.view.View.OnTouchListener;
import android.view.ViewGroup;
+import android.view.WindowManager;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.SearchView;
-import android.widget.SearchView.OnCloseListener;
import android.widget.SearchView.OnQueryTextListener;
import android.widget.TextView;
import android.widget.Toast;
import com.android.documentsui.RecentsProvider.RecentColumns;
import com.android.documentsui.RecentsProvider.ResumeColumns;
-import com.android.documentsui.RecentsProvider.StateColumns;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
@@ -78,15 +84,19 @@
public class DocumentsActivity extends Activity {
public static final String TAG = "Documents";
- private SearchView mSearchView;
-
- private View mRootsContainer;
- private DrawerLayout mDrawerLayout;
- private ActionBarDrawerToggle mDrawerToggle;
-
private static final String EXTRA_STATE = "state";
+ private boolean mShowAsDialog;
+
+ private SearchView mSearchView;
+
+ private DrawerLayout mDrawerLayout;
+ private ActionBarDrawerToggle mDrawerToggle;
+ private View mRootsContainer;
+
private boolean mIgnoreNextNavigation;
+ private boolean mIgnoreNextClose;
+ private boolean mIgnoreNextCollapse;
private RootsCache mRoots;
private State mState;
@@ -100,15 +110,60 @@
setResult(Activity.RESULT_CANCELED);
setContentView(R.layout.activity);
- mRootsContainer = findViewById(R.id.container_roots);
+ final Resources res = getResources();
+ mShowAsDialog = res.getBoolean(R.bool.show_as_dialog);
- mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+ if (mShowAsDialog) {
+ // backgroundDimAmount from theme isn't applied; do it manually
+ final WindowManager.LayoutParams a = getWindow().getAttributes();
+ a.dimAmount = 0.6f;
+ getWindow().setAttributes(a);
- mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
- R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close);
+ getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
+ getWindow().setFlags(~0, WindowManager.LayoutParams.FLAG_DIM_BEHIND);
- mDrawerLayout.setDrawerListener(mDrawerListener);
- mDrawerLayout.setDrawerShadow(R.drawable.ic_drawer_shadow, GravityCompat.START);
+ // Inset ourselves to look like a dialog
+ final Point size = new Point();
+ getWindowManager().getDefaultDisplay().getSize(size);
+
+ final int width = (int) res.getFraction(R.dimen.dialog_width, size.x, size.x);
+ final int height = (int) res.getFraction(R.dimen.dialog_height, size.y, size.y);
+ final int insetX = (size.x - width) / 2;
+ final int insetY = (size.y - height) / 2;
+
+ final Drawable before = getWindow().getDecorView().getBackground();
+ final Drawable after = new InsetDrawable(before, insetX, insetY, insetX, insetY);
+ getWindow().getDecorView().setBackground(after);
+
+ // Dismiss when touch down in the dimmed inset area
+ getWindow().getDecorView().setOnTouchListener(new OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ final float x = event.getX();
+ final float y = event.getY();
+ if (x < insetX || x > v.getWidth() - insetX || y < insetY
+ || y > v.getHeight() - insetY) {
+ finish();
+ return true;
+ }
+ }
+ return false;
+ }
+ });
+
+ } else {
+ // Non-dialog means we have a drawer
+ mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+
+ mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
+ R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close);
+
+ mDrawerLayout.setDrawerListener(mDrawerListener);
+ mDrawerLayout.setDrawerShadow(R.drawable.ic_drawer_shadow, GravityCompat.START);
+
+ mRootsContainer = findViewById(R.id.container_roots);
+ }
if (icicle != null) {
mState = icicle.getParcelable(EXTRA_STATE);
@@ -116,8 +171,13 @@
buildDefaultState();
}
+ // Hide roots when we're managing a specific root
if (mState.action == ACTION_MANAGE) {
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+ if (mShowAsDialog) {
+ findViewById(R.id.dialog_roots).setVisibility(View.GONE);
+ } else {
+ mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+ }
}
if (mState.action == ACTION_CREATE) {
@@ -171,10 +231,6 @@
mState.showAdvanced = SettingsActivity.getDisplayAdvancedDevices(this);
if (mState.action == ACTION_MANAGE) {
- mState.sortOrder = SORT_ORDER_LAST_MODIFIED;
- }
-
- if (mState.action == ACTION_MANAGE) {
final Uri uri = intent.getData();
final String rootId = DocumentsContract.getRootId(uri);
final RootInfo root = mRoots.getRoot(uri.getAuthority(), rootId);
@@ -188,6 +244,7 @@
} else {
// Restore last stack for calling package
// TODO: move into async loader
+ boolean restoredStack = false;
final String packageName = getCallingPackage();
final Cursor cursor = getContentResolver()
.query(RecentsProvider.buildResume(packageName), null, null, null, null);
@@ -196,6 +253,7 @@
final byte[] rawStack = cursor.getBlob(
cursor.getColumnIndex(ResumeColumns.STACK));
DurableUtils.readFromArray(rawStack, mState.stack);
+ restoredStack = true;
}
} catch (IOException e) {
Log.w(TAG, "Failed to resume", e);
@@ -208,18 +266,21 @@
final List<RootInfo> matchingRoots = mRoots.getMatchingRoots(mState);
if (!matchingRoots.contains(root)) {
mState.stack.reset();
+ restoredStack = false;
}
- // Only open drawer when showing recents
- if (mState.stack.isRecents()) {
- mDrawerLayout.openDrawer(mRootsContainer);
+ // Only open drawer when not restoring stack, and when not showing
+ // visual content.
+ if (!restoredStack
+ && !MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) {
+ setRootsDrawerOpen(true);
}
}
}
@Override
- public void onStart() {
- super.onStart();
+ public void onResume() {
+ super.onResume();
if (mState.action == ACTION_MANAGE) {
mState.showSize = true;
@@ -238,12 +299,14 @@
public void onDrawerOpened(View drawerView) {
mDrawerToggle.onDrawerOpened(drawerView);
updateActionBar();
+ invalidateOptionsMenu();
}
@Override
public void onDrawerClosed(View drawerView) {
mDrawerToggle.onDrawerClosed(drawerView);
updateActionBar();
+ invalidateOptionsMenu();
}
@Override
@@ -255,7 +318,27 @@
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
- mDrawerToggle.syncState();
+ if (mDrawerToggle != null) {
+ mDrawerToggle.syncState();
+ }
+ }
+
+ public void setRootsDrawerOpen(boolean open) {
+ if (!mShowAsDialog) {
+ if (open) {
+ mDrawerLayout.openDrawer(mRootsContainer);
+ } else {
+ mDrawerLayout.closeDrawer(mRootsContainer);
+ }
+ }
+ }
+
+ private boolean isRootsDrawerOpen() {
+ if (mShowAsDialog) {
+ return false;
+ } else {
+ return mDrawerLayout.isDrawerOpen(mRootsContainer);
+ }
}
public void updateActionBar() {
@@ -263,15 +346,13 @@
actionBar.setDisplayShowHomeEnabled(true);
- if (mState.action == ACTION_MANAGE) {
- actionBar.setDisplayHomeAsUpEnabled(false);
- mDrawerToggle.setDrawerIndicatorEnabled(false);
- } else {
- actionBar.setDisplayHomeAsUpEnabled(true);
- mDrawerToggle.setDrawerIndicatorEnabled(true);
+ final boolean showIndicator = !mShowAsDialog && (mState.action != ACTION_MANAGE);
+ actionBar.setDisplayHomeAsUpEnabled(showIndicator);
+ if (mDrawerToggle != null) {
+ mDrawerToggle.setDrawerIndicatorEnabled(showIndicator);
}
- if (mDrawerLayout.isDrawerOpen(mRootsContainer)) {
+ if (isRootsDrawerOpen()) {
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setIcon(new ColorDrawable());
@@ -302,14 +383,21 @@
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.activity, menu);
+ // Actions are always visible when showing as dialog
+ if (mShowAsDialog) {
+ for (int i = 0; i < menu.size(); i++) {
+ menu.getItem(i).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ }
+ }
+
final MenuItem searchMenu = menu.findItem(R.id.menu_search);
mSearchView = (SearchView) searchMenu.getActionView();
mSearchView.setOnQueryTextListener(new OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
mState.currentSearch = query;
+ mSearchView.clearFocus();
onCurrentDirectoryChanged();
- mSearchView.setIconified(true);
return true;
}
@@ -319,9 +407,33 @@
}
});
- mSearchView.setOnCloseListener(new OnCloseListener() {
+ searchMenu.setOnActionExpandListener(new OnActionExpandListener() {
+ @Override
+ public boolean onMenuItemActionExpand(MenuItem item) {
+ return true;
+ }
+
+ @Override
+ public boolean onMenuItemActionCollapse(MenuItem item) {
+ if (mIgnoreNextCollapse) {
+ mIgnoreNextCollapse = false;
+ return true;
+ }
+
+ mState.currentSearch = null;
+ onCurrentDirectoryChanged();
+ return true;
+ }
+ });
+
+ mSearchView.setOnCloseListener(new SearchView.OnCloseListener() {
@Override
public boolean onClose() {
+ if (mIgnoreNextClose) {
+ mIgnoreNextClose = false;
+ return false;
+ }
+
mState.currentSearch = null;
onCurrentDirectoryChanged();
return false;
@@ -336,6 +448,8 @@
super.onPrepareOptionsMenu(menu);
final FragmentManager fm = getFragmentManager();
+
+ final RootInfo root = getCurrentRoot();
final DocumentInfo cwd = getCurrentDirectory();
final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
@@ -346,14 +460,38 @@
final MenuItem list = menu.findItem(R.id.menu_list);
final MenuItem settings = menu.findItem(R.id.menu_settings);
- if (cwd != null) {
- sort.setVisible(true);
- grid.setVisible(mState.mode != MODE_GRID);
- list.setVisible(mState.mode != MODE_LIST);
- } else {
+ // Open drawer means we hide most actions
+ if (isRootsDrawerOpen()) {
+ createDir.setVisible(false);
+ search.setVisible(false);
sort.setVisible(false);
grid.setVisible(false);
list.setVisible(false);
+ mIgnoreNextCollapse = true;
+ search.collapseActionView();
+ return true;
+ }
+
+ sort.setVisible(cwd != null);
+ grid.setVisible(mState.derivedMode != MODE_GRID);
+ list.setVisible(mState.derivedMode != MODE_LIST);
+
+ if (mState.currentSearch != null) {
+ // Search uses backend ranking; no sorting
+ sort.setVisible(false);
+
+ search.expandActionView();
+
+ mSearchView.setIconified(false);
+ mSearchView.clearFocus();
+ mSearchView.setQuery(mState.currentSearch, false);
+ } else {
+ mIgnoreNextClose = true;
+ mSearchView.setIconified(true);
+ mSearchView.clearFocus();
+
+ mIgnoreNextCollapse = true;
+ search.collapseActionView();
}
// Only sort by size when visible
@@ -373,7 +511,9 @@
SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
} else {
createDir.setVisible(false);
- searchVisible = cwd != null && cwd.isSearchSupported();
+
+ searchVisible = root != null
+ && ((root.flags & Root.FLAG_SUPPORTS_SEARCH) != 0);
}
// TODO: close any search in-progress when hiding
@@ -386,7 +526,7 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- if (mDrawerToggle.onOptionsItemSelected(item)) {
+ if (mDrawerToggle != null && mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
@@ -433,47 +573,30 @@
* Set state sort order based on explicit user action.
*/
private void setUserSortOrder(int sortOrder) {
- final RootInfo root = getCurrentRoot();
- final DocumentInfo cwd = getCurrentDirectory();
-
- // TODO: persist async, then trigger rebind
- final Uri stateUri = RecentsProvider.buildState(
- root.authority, root.rootId, cwd.documentId);
- final ContentValues values = new ContentValues();
- values.put(StateColumns.SORT_ORDER, sortOrder);
- getContentResolver().insert(stateUri, values);
-
+ mState.userSortOrder = sortOrder;
DirectoryFragment.get(getFragmentManager()).onUserSortOrderChanged();
- onStateChanged();
}
/**
* Set state mode based on explicit user action.
*/
private void setUserMode(int mode) {
- final RootInfo root = getCurrentRoot();
- final DocumentInfo cwd = getCurrentDirectory();
-
- // TODO: persist async, then trigger rebind
- final Uri stateUri = RecentsProvider.buildState(
- root.authority, root.rootId, cwd.documentId);
- final ContentValues values = new ContentValues();
- values.put(StateColumns.MODE, mode);
- getContentResolver().insert(stateUri, values);
-
- mState.mode = mode;
-
+ mState.userMode = mode;
DirectoryFragment.get(getFragmentManager()).onUserModeChanged();
- onStateChanged();
}
@Override
public void onBackPressed() {
+ if (!mState.stackTouched) {
+ super.onBackPressed();
+ return;
+ }
+
final int size = mState.stack.size();
if (size > 1) {
mState.stack.pop();
onCurrentDirectoryChanged();
- } else if (size == 1 && !mDrawerLayout.isDrawerOpen(mRootsContainer)) {
+ } else if (size == 1 && !isRootsDrawerOpen()) {
// TODO: open root drawer once we can capture back key
super.onBackPressed();
} else {
@@ -564,6 +687,7 @@
}
while (mState.stack.size() > itemPosition + 1) {
+ mState.stackTouched = true;
mState.stack.pop();
}
onCurrentDirectoryChanged();
@@ -598,11 +722,17 @@
RecentsCreateFragment.show(fm);
} else {
DirectoryFragment.showRecentsOpen(fm);
+
+ // Start recents in relevant mode
+ final boolean acceptImages = MimePredicate.mimeMatches(
+ "image/*", mState.acceptMimes);
+ mState.userMode = acceptImages ? MODE_GRID : MODE_LIST;
+ mState.derivedMode = mState.userMode;
}
} else {
if (mState.currentSearch != null) {
// Ongoing search
- DirectoryFragment.showSearch(fm, root, cwd, mState.currentSearch);
+ DirectoryFragment.showSearch(fm, root, mState.currentSearch);
} else {
// Normal boring directory
DirectoryFragment.showNormal(fm, root, cwd);
@@ -629,6 +759,7 @@
public void onStackPicked(DocumentStack stack) {
mState.stack = stack;
+ mState.stackTouched = true;
onCurrentDirectoryChanged();
}
@@ -636,6 +767,7 @@
// Clear entire backstack and start in new root
mState.stack.root = root;
mState.stack.clear();
+ mState.stackTouched = true;
if (!mRoots.isRecentsRoot(root)) {
try {
@@ -648,7 +780,7 @@
}
if (closeDrawer) {
- mDrawerLayout.closeDrawers();
+ setRootsDrawerOpen(false);
}
}
@@ -664,13 +796,8 @@
public void onDocumentPicked(DocumentInfo doc) {
final FragmentManager fm = getFragmentManager();
if (doc.isDirectory()) {
- // TODO: query display mode user preference for this dir
- if (doc.isGridPreferred()) {
- mState.mode = MODE_GRID;
- } else {
- mState.mode = MODE_LIST;
- }
mState.stack.push(doc);
+ mState.stackTouched = true;
onCurrentDirectoryChanged();
} else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
// Explicit file picked, return
@@ -774,13 +901,23 @@
public static class State implements android.os.Parcelable {
public int action;
- public int mode = MODE_LIST;
public String[] acceptMimes;
- public int sortOrder = SORT_ORDER_DISPLAY_NAME;
+
+ /** Explicit user choice */
+ public int userMode = MODE_UNKNOWN;
+ /** Derived after loader */
+ public int derivedMode = MODE_LIST;
+
+ /** Explicit user choice */
+ public int userSortOrder = SORT_ORDER_UNKNOWN;
+ /** Derived after loader */
+ public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
+
public boolean allowMultiple = false;
public boolean showSize = false;
public boolean localOnly = false;
public boolean showAdvanced = false;
+ public boolean stackTouched = false;
/** Current user navigation stack; empty implies recents. */
public DocumentStack stack = new DocumentStack();
@@ -809,13 +946,14 @@
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(action);
- out.writeInt(mode);
+ out.writeInt(userMode);
out.writeStringArray(acceptMimes);
- out.writeInt(sortOrder);
+ out.writeInt(userSortOrder);
out.writeInt(allowMultiple ? 1 : 0);
out.writeInt(showSize ? 1 : 0);
out.writeInt(localOnly ? 1 : 0);
out.writeInt(showAdvanced ? 1 : 0);
+ out.writeInt(stackTouched ? 1 : 0);
DurableUtils.writeToParcel(out, stack);
out.writeString(currentSearch);
}
@@ -825,13 +963,14 @@
public State createFromParcel(Parcel in) {
final State state = new State();
state.action = in.readInt();
- state.mode = in.readInt();
+ state.userMode = in.readInt();
state.acceptMimes = in.readStringArray();
- state.sortOrder = in.readInt();
+ state.userSortOrder = in.readInt();
state.allowMultiple = in.readInt() != 0;
state.showSize = in.readInt() != 0;
state.localOnly = in.readInt() != 0;
state.showAdvanced = in.readInt() != 0;
+ state.stackTouched = in.readInt() != 0;
DurableUtils.readFromParcel(in, state.stack);
state.currentSearch = in.readString();
return state;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java
index 0a6cbc0..180ddef 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java
@@ -56,7 +56,11 @@
packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
packageFilter.addDataScheme("package");
- registerReceiver(mPackageReceiver, packageFilter);
+ registerReceiver(mCacheReceiver, packageFilter);
+
+ final IntentFilter localeFilter = new IntentFilter();
+ localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
+ registerReceiver(mCacheReceiver, localeFilter);
}
@Override
@@ -70,7 +74,7 @@
}
}
- private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
+ private BroadcastReceiver mCacheReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// TODO: narrow changed/removed to only packages that have backends
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
index 60f0103..5f56963 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
@@ -34,6 +34,10 @@
private int mCount;
public FilteringCursorWrapper(Cursor cursor, String[] acceptMimes) {
+ this(cursor, acceptMimes, null);
+ }
+
+ public FilteringCursorWrapper(Cursor cursor, String[] acceptMimes, String[] rejectMimes) {
mCursor = cursor;
final int count = cursor.getCount();
@@ -43,6 +47,9 @@
while (cursor.moveToNext()) {
final String mimeType = cursor.getString(
cursor.getColumnIndex(Document.COLUMN_MIME_TYPE));
+ if (rejectMimes != null && MimePredicate.mimeMatches(rejectMimes, mimeType)) {
+ continue;
+ }
if (MimePredicate.mimeMatches(acceptMimes, mimeType)) {
mPosition[mCount++] = cursor.getPosition();
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
index b55ce82..2d96876 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
@@ -22,6 +22,12 @@
public class MimePredicate implements Predicate<DocumentInfo> {
private final String[] mFilters;
+ /**
+ * MIME types that are visual in nature. For example, they should always be
+ * shown as thumbnails in list mode.
+ */
+ public static final String[] VISUAL_MIMES = new String[] { "image/*", "video/*" };
+
public MimePredicate(String[] filters) {
mFilters = filters;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index 57442a0..1912010 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -17,8 +17,6 @@
package com.android.documentsui;
import static com.android.documentsui.DocumentsActivity.TAG;
-import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
-import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
import android.content.AsyncTaskLoader;
@@ -29,6 +27,7 @@
import android.database.MergeCursor;
import android.net.Uri;
import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
import android.util.Log;
@@ -178,7 +177,7 @@
try {
final Cursor cursor = task.get();
final FilteringCursorWrapper filtered = new FilteringCursorWrapper(
- cursor, mAcceptMimes) {
+ cursor, mAcceptMimes, new String[] { Document.MIME_TYPE_DIR }) {
@Override
public void close() {
// Ignored, since we manage cursor lifecycle internally
@@ -194,9 +193,6 @@
}
final DirectoryResult result = new DirectoryResult();
-
- final boolean acceptImages = MimePredicate.mimeMatches("image/*", mAcceptMimes);
- result.mode = acceptImages ? MODE_GRID : MODE_LIST;
result.sortOrder = SORT_ORDER_LAST_MODIFIED;
if (cursors.size() > 0) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index 3642478..140373b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -183,12 +183,12 @@
convertView = inflater.inflate(R.layout.item_doc_list, parent, false);
}
- final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
+ final ImageView iconMime = (ImageView) convertView.findViewById(R.id.icon_mime);
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
final View line2 = convertView.findViewById(R.id.line2);
final DocumentStack stack = getItem(position);
- icon.setImageDrawable(stack.root.loadIcon(context));
+ iconMime.setImageDrawable(stack.root.loadIcon(context));
final Drawable crumb = context.getResources()
.getDrawable(R.drawable.ic_breadcrumb_arrow);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index 1fe5d54..af79c93 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -151,18 +151,18 @@
case URI_RECENT:
final long cutoff = System.currentTimeMillis() - MAX_HISTORY_IN_MILLIS;
return db.query(TABLE_RECENT, projection, RecentColumns.TIMESTAMP + ">" + cutoff,
- null, null, null, null);
+ null, null, null, sortOrder);
case URI_STATE:
final String authority = uri.getPathSegments().get(1);
final String rootId = uri.getPathSegments().get(2);
final String documentId = uri.getPathSegments().get(3);
return db.query(TABLE_STATE, projection, StateColumns.AUTHORITY + "=? AND "
+ StateColumns.ROOT_ID + "=? AND " + StateColumns.DOCUMENT_ID + "=?",
- new String[] { authority, rootId, documentId }, null, null, null);
+ new String[] { authority, rootId, documentId }, null, null, sortOrder);
case URI_RESUME:
final String packageName = uri.getPathSegments().get(1);
return db.query(TABLE_RESUME, projection, ResumeColumns.PACKAGE_NAME + "=?",
- new String[] { packageName }, null, null, null);
+ new String[] { packageName }, null, null, sortOrder);
default:
throw new UnsupportedOperationException("Unsupported Uri " + uri);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 8530a9f..9b54948 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -90,7 +90,6 @@
if (info.metaData != null && info.metaData.containsKey(
DocumentsContract.META_DATA_DOCUMENT_PROVIDER)) {
- // TODO: remove deprecated customRoots flag
// TODO: populate roots on background thread, and cache results
final Uri rootsUri = DocumentsContract.buildRootsUri(info.authority);
final ContentProviderClient client = resolver
@@ -110,6 +109,8 @@
}
}
}
+
+ Log.d(TAG, "Update found " + mRoots.size() + " roots");
}
@Deprecated
@@ -135,6 +136,23 @@
}
@GuardedBy("ActivityThread")
+ public boolean isIconUnique(RootInfo root) {
+ final int rootIcon = root.derivedIcon != 0 ? root.derivedIcon : root.icon;
+ for (RootInfo test : mRoots) {
+ if (Objects.equal(test.authority, root.authority)) {
+ if (Objects.equal(test.rootId, root.rootId)) {
+ continue;
+ }
+ final int testIcon = test.derivedIcon != 0 ? test.derivedIcon : test.icon;
+ if (testIcon == rootIcon) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @GuardedBy("ActivityThread")
public RootInfo getRecentsRoot() {
return mRecentsRoot;
}
@@ -160,6 +178,7 @@
final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 0;
final boolean advanced = (root.flags & Root.FLAG_ADVANCED) != 0;
final boolean localOnly = (root.flags & Root.FLAG_LOCAL_ONLY) != 0;
+ final boolean empty = (root.flags & Root.FLAG_EMPTY) != 0;
// Exclude read-only devices when creating
if (state.action == State.ACTION_CREATE && !supportsCreate) continue;
@@ -167,6 +186,8 @@
if (!state.showAdvanced && advanced) continue;
// Exclude non-local devices when local only
if (state.localOnly && !localOnly) continue;
+ // Only show empty roots when creating
+ if (state.action != State.ACTION_CREATE && empty) continue;
// Only include roots that serve requested content
final boolean overlap =
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index efb972d..908729c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -25,6 +25,7 @@
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.provider.DocumentsContract.Root;
+import android.text.TextUtils;
import android.text.format.Formatter;
import android.view.LayoutInflater;
import android.view.View;
@@ -34,6 +35,7 @@
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
+import android.widget.Space;
import android.widget.TextView;
import com.android.documentsui.DocumentsActivity.State;
@@ -85,8 +87,8 @@
}
@Override
- public void onStart() {
- super.onStart();
+ public void onResume() {
+ super.onResume();
updateRootsAdapter();
}
@@ -135,11 +137,8 @@
};
private static class RootsAdapter extends ArrayAdapter<RootInfo> implements SectionAdapter {
- private int mHeaderId;
-
- public RootsAdapter(Context context, int headerId) {
+ public RootsAdapter(Context context) {
super(context, 0);
- mHeaderId = headerId;
}
@Override
@@ -168,7 +167,7 @@
}
summary.setText(summaryText);
- summary.setVisibility(summaryText != null ? View.VISIBLE : View.GONE);
+ summary.setVisibility(TextUtils.isEmpty(summaryText) ? View.GONE : View.VISIBLE);
return convertView;
}
@@ -176,13 +175,8 @@
@Override
public View getHeaderView(View convertView, ViewGroup parent) {
if (convertView == null) {
- convertView = LayoutInflater.from(parent.getContext())
- .inflate(R.layout.item_root_header, parent, false);
+ convertView = new Space(parent.getContext());
}
-
- final TextView title = (TextView) convertView.findViewById(android.R.id.title);
- title.setText(mHeaderId);
-
return convertView;
}
}
@@ -236,9 +230,9 @@
private final AppsAdapter mApps;
public SectionedRootsAdapter(Context context, List<RootInfo> roots, Intent includeApps) {
- mServices = new RootsAdapter(context, R.string.root_type_service);
- mShortcuts = new RootsAdapter(context, R.string.root_type_shortcut);
- mDevices = new RootsAdapter(context, R.string.root_type_device);
+ mServices = new RootsAdapter(context);
+ mShortcuts = new RootsAdapter(context);
+ mDevices = new RootsAdapter(context);
mApps = new AppsAdapter(context);
for (RootInfo root : roots) {
@@ -273,15 +267,15 @@
mShortcuts.sort(comp);
mDevices.sort(comp);
- if (mServices.getCount() > 0) {
- addSection(mServices);
- }
if (mShortcuts.getCount() > 0) {
addSection(mShortcuts);
}
if (mDevices.getCount() > 0) {
addSection(mDevices);
}
+ if (mServices.getCount() > 0) {
+ addSection(mServices);
+ }
if (mApps.getCount() > 0) {
addSection(mApps);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SettingsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/SettingsActivity.java
index ceeaaae..a85f6a9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SettingsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SettingsActivity.java
@@ -16,6 +16,7 @@
package com.android.documentsui;
+import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
@@ -39,8 +40,14 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
getFragmentManager()
.beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
+
+ final ActionBar bar = getActionBar();
+ if (bar != null) {
+ bar.setDisplayShowHomeEnabled(false);
+ }
}
public static class SettingsFragment extends PreferenceFragment {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index c69103e..681cc9b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -188,10 +188,6 @@
return (flags & Document.FLAG_DIR_SUPPORTS_CREATE) != 0;
}
- public boolean isSearchSupported() {
- return (flags & Document.FLAG_DIR_SUPPORTS_SEARCH) != 0;
- }
-
public boolean isThumbnailSupported() {
return (flags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
}
@@ -208,6 +204,10 @@
return (flags & Document.FLAG_SUPPORTS_DELETE) != 0;
}
+ public boolean isGridTitlesHidden() {
+ return (flags & Document.FLAG_DIR_HIDE_GRID_TITLES) != 0;
+ }
+
public static String getCursorString(Cursor cursor, String columnName) {
final int index = cursor.getColumnIndex(columnName);
return (index != -1) ? cursor.getString(index) : null;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index e0e8acf..1afc80a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -26,6 +26,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.DocumentsContract.Root;
+import android.text.TextUtils;
import com.android.documentsui.IconUtils;
import com.android.documentsui.R;
@@ -160,15 +161,21 @@
// TODO: remove these special case icons
if ("com.android.externalstorage.documents".equals(authority)) {
- derivedIcon = R.drawable.ic_root_sdcard;
+ if ("documents".equals(rootId)) {
+ derivedIcon = R.drawable.ic_doc_text;
+ } else {
+ derivedIcon = R.drawable.ic_root_sdcard;
+ }
}
if ("com.android.providers.downloads.documents".equals(authority)) {
derivedIcon = R.drawable.ic_root_download;
}
if ("com.android.providers.media.documents".equals(authority)) {
- if ("image".equals(rootId)) {
+ if ("images_root".equals(rootId)) {
derivedIcon = R.drawable.ic_doc_image;
- } else if ("audio".equals(rootId)) {
+ } else if ("videos_root".equals(rootId)) {
+ derivedIcon = R.drawable.ic_doc_video;
+ } else if ("audio_root".equals(rootId)) {
derivedIcon = R.drawable.ic_doc_audio;
}
}
@@ -203,6 +210,6 @@
}
public String getDirectoryString() {
- return (summary != null) ? summary : title;
+ return !TextUtils.isEmpty(summary) ? summary : title;
}
}
diff --git a/packages/ExternalStorageProvider/res/values-af/strings.xml b/packages/ExternalStorageProvider/res/values-af/strings.xml
index 56552fd..1de881d 100644
--- a/packages/ExternalStorageProvider/res/values-af/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-af/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Eksterne berging"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interne berging"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumente"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-am/strings.xml b/packages/ExternalStorageProvider/res/values-am/strings.xml
index f0255a1..e646909 100644
--- a/packages/ExternalStorageProvider/res/values-am/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-am/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ውጫዊ ማከማቻ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ውስጣዊ ማከማቻ"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ar/strings.xml b/packages/ExternalStorageProvider/res/values-ar/strings.xml
index 67a600d..b20a056 100644
--- a/packages/ExternalStorageProvider/res/values-ar/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ar/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"وحدة تخزين خارجية"</string>
<string name="root_internal_storage" msgid="827844243068584127">"وحدة تخزين داخلية"</string>
+ <string name="root_documents" msgid="4051252304075469250">"مستندات"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-bg/strings.xml b/packages/ExternalStorageProvider/res/values-bg/strings.xml
index 919e8b5..f3b4dac 100644
--- a/packages/ExternalStorageProvider/res/values-bg/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-bg/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Външно хранилище"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Вътрешно хранилище"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ca/strings.xml b/packages/ExternalStorageProvider/res/values-ca/strings.xml
index 958ea99..7c0ad8b 100644
--- a/packages/ExternalStorageProvider/res/values-ca/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ca/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Emmagatzematge extern"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Emmagatzematge intern"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-cs/strings.xml b/packages/ExternalStorageProvider/res/values-cs/strings.xml
index 469ecf9..353cb6c 100644
--- a/packages/ExternalStorageProvider/res/values-cs/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-cs/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Externí úložiště"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interní úložiště"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-da/strings.xml b/packages/ExternalStorageProvider/res/values-da/strings.xml
index b94e665..a9ecb69 100644
--- a/packages/ExternalStorageProvider/res/values-da/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-da/strings.xml
@@ -16,6 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="7123375275748530234">"Ekstern lagerplads"</string>
- <string name="root_internal_storage" msgid="827844243068584127">"Intern lagerplads"</string>
+ <string name="app_label" msgid="7123375275748530234">"Ekstern lagring"</string>
+ <string name="root_internal_storage" msgid="827844243068584127">"Intern lagring"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenter"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-de/strings.xml b/packages/ExternalStorageProvider/res/values-de/strings.xml
index 1f6ef45..318634a 100644
--- a/packages/ExternalStorageProvider/res/values-de/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-de/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Externer Speicher"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interner Speicher"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumente"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-el/strings.xml b/packages/ExternalStorageProvider/res/values-el/strings.xml
index 06e26d7..b3aa792 100644
--- a/packages/ExternalStorageProvider/res/values-el/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-el/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Εξωτερικός αποθηκευτικός χώρος"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Εσωτερικός αποθηκευτικός χώρος"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Έγγραφα"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml b/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml
index 360d941..f88eb9e 100644
--- a/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"External Storage"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Internal storage"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml
index 360d941..f88eb9e 100644
--- a/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"External Storage"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Internal storage"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml b/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml
index 8e35245..7285a34 100644
--- a/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Almacenamiento externo"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Almacenamiento interno"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-es/strings.xml b/packages/ExternalStorageProvider/res/values-es/strings.xml
index 8e35245..e7e38b5 100644
--- a/packages/ExternalStorageProvider/res/values-es/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-es/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Almacenamiento externo"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Almacenamiento interno"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml b/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml
index d651806..6824e9d 100644
--- a/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Väline talletusruum"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Sisemine salvestusruum"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumendid"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-fa/strings.xml b/packages/ExternalStorageProvider/res/values-fa/strings.xml
index 5f82a06..8471fc7 100644
--- a/packages/ExternalStorageProvider/res/values-fa/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fa/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"فضای ذخیره خارجی"</string>
<string name="root_internal_storage" msgid="827844243068584127">"حافظهٔ داخلی"</string>
+ <string name="root_documents" msgid="4051252304075469250">"اسناد"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-fi/strings.xml b/packages/ExternalStorageProvider/res/values-fi/strings.xml
index f98b086..9d1fbaa 100644
--- a/packages/ExternalStorageProvider/res/values-fi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fi/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Ulkoinen tallennustila"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Sisäinen tallennustila"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumentit"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml b/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml
index 5861477..294bd69 100644
--- a/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Stockage externe"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Mémoire de stockage interne"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-fr/strings.xml b/packages/ExternalStorageProvider/res/values-fr/strings.xml
index 5861477..b3fdd48 100644
--- a/packages/ExternalStorageProvider/res/values-fr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fr/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Stockage externe"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Mémoire de stockage interne"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-hi/strings.xml b/packages/ExternalStorageProvider/res/values-hi/strings.xml
index 302ece1..1227bd4 100644
--- a/packages/ExternalStorageProvider/res/values-hi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hi/strings.xml
@@ -17,5 +17,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"बाहरी संग्रहण"</string>
- <string name="root_internal_storage" msgid="827844243068584127">"आंतरिक संग्रहण"</string>
+ <string name="root_internal_storage" msgid="827844243068584127">"मोबाइल संग्रहण"</string>
+ <string name="root_documents" msgid="4051252304075469250">"दस्तावेज़"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-hr/strings.xml b/packages/ExternalStorageProvider/res/values-hr/strings.xml
index 79429a7..a74f8e8 100644
--- a/packages/ExternalStorageProvider/res/values-hr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hr/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Vanjska pohrana"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Unutarnja pohrana"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-hu/strings.xml b/packages/ExternalStorageProvider/res/values-hu/strings.xml
index 8175c42..3f72b41 100644
--- a/packages/ExternalStorageProvider/res/values-hu/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hu/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Külső tárhely"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Belső tárhely"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumentumok"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml b/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml
index c30a03b..5360124 100644
--- a/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Արտաքին պահոց"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Ներքին պահոց"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Փաստաթղթեր"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-in/strings.xml b/packages/ExternalStorageProvider/res/values-in/strings.xml
index 7180518..553e656 100644
--- a/packages/ExternalStorageProvider/res/values-in/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-in/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Penyimpanan Eksternal"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Penyimpanan internal"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-it/strings.xml b/packages/ExternalStorageProvider/res/values-it/strings.xml
index c5dcacd..957b5ff 100644
--- a/packages/ExternalStorageProvider/res/values-it/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-it/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Archivio esterno"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Memoria interna"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-iw/strings.xml b/packages/ExternalStorageProvider/res/values-iw/strings.xml
index 62f4471..775506a 100644
--- a/packages/ExternalStorageProvider/res/values-iw/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-iw/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"אחסון חיצוני"</string>
<string name="root_internal_storage" msgid="827844243068584127">"אחסון פנימי"</string>
+ <string name="root_documents" msgid="4051252304075469250">"מסמכים"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ja/strings.xml b/packages/ExternalStorageProvider/res/values-ja/strings.xml
index 8d9502562..6c204eb 100644
--- a/packages/ExternalStorageProvider/res/values-ja/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ja/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"外部ストレージ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"内部ストレージ"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml b/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml
index 6a26acd..18920e6 100644
--- a/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"გარე მეხსიერება"</string>
<string name="root_internal_storage" msgid="827844243068584127">"შიდა მეხსიერება"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml b/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
index 302ce4b..9cf76d40 100644
--- a/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ឧបករណ៍ផ្ទុកខាងក្រៅ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ឧបករណ៍ផ្ទុកខាងក្នុង"</string>
+ <string name="root_documents" msgid="4051252304075469250">"ឯកសារ"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ko/strings.xml b/packages/ExternalStorageProvider/res/values-ko/strings.xml
index 07c9e83..4be48bf 100644
--- a/packages/ExternalStorageProvider/res/values-ko/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ko/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"외부 저장소"</string>
<string name="root_internal_storage" msgid="827844243068584127">"내부 저장소"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml b/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml
index dd6e55a..cecd9f5 100644
--- a/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ບ່ອນຈັດເກັບຂໍ້ມູນພາຍນອກ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ບ່ອນຈັດເກັບຂໍ້ມູນພາຍໃນ"</string>
+ <string name="root_documents" msgid="4051252304075469250">"ເອກະສານ"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-lt/strings.xml b/packages/ExternalStorageProvider/res/values-lt/strings.xml
index b62efdc..240ea89 100644
--- a/packages/ExternalStorageProvider/res/values-lt/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-lt/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Išorinė atmintinė"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Vidinė atmintinė"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumentai"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-lv/strings.xml b/packages/ExternalStorageProvider/res/values-lv/strings.xml
index 23b7a0f..d308fe8 100644
--- a/packages/ExternalStorageProvider/res/values-lv/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-lv/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Ārējā krātuve"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Iekšējā atmiņa"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml b/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..3d7b7f7
--- /dev/null
+++ b/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="7123375275748530234">"Гадаад сан"</string>
+ <string name="root_internal_storage" msgid="827844243068584127">"Дотоод сан"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Документүүд"</string>
+</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml b/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml
index 245d52d..e8c6011 100644
--- a/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Storan Luaran"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Storan dalaman"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-nb/strings.xml b/packages/ExternalStorageProvider/res/values-nb/strings.xml
index 223eb7a..a9ecb69 100644
--- a/packages/ExternalStorageProvider/res/values-nb/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-nb/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Ekstern lagring"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Intern lagring"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenter"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-nl/strings.xml b/packages/ExternalStorageProvider/res/values-nl/strings.xml
index 402c94b..bde6166 100644
--- a/packages/ExternalStorageProvider/res/values-nl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-nl/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Externe opslag"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interne opslag"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documenten"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-pl/strings.xml b/packages/ExternalStorageProvider/res/values-pl/strings.xml
index 1ac244d..6c5e7d7 100644
--- a/packages/ExternalStorageProvider/res/values-pl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pl/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Pamięć zewnętrzna"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Pamięć wewnętrzna"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenty"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml b/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
index 629b715..77c89b8 100644
--- a/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
@@ -16,6 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="7123375275748530234">"Armazenamento Externo"</string>
+ <string name="app_label" msgid="7123375275748530234">"Armazenamento externo"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Armazenamento interno"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-pt/strings.xml b/packages/ExternalStorageProvider/res/values-pt/strings.xml
index bc5b35d..eec824f 100644
--- a/packages/ExternalStorageProvider/res/values-pt/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pt/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Armazenamento externo"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Armazenamento interno"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ro/strings.xml b/packages/ExternalStorageProvider/res/values-ro/strings.xml
index 4295c22..16b963b 100644
--- a/packages/ExternalStorageProvider/res/values-ro/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ro/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Stocare externă"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Stocare internă"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ru/strings.xml b/packages/ExternalStorageProvider/res/values-ru/strings.xml
index 8c3599d..3dee3b6 100644
--- a/packages/ExternalStorageProvider/res/values-ru/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ru/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Внешний накопитель"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Внутренняя память"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sk/strings.xml b/packages/ExternalStorageProvider/res/values-sk/strings.xml
index 90fc971..73e4552 100644
--- a/packages/ExternalStorageProvider/res/values-sk/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sk/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Externý ukladací priestor"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interný ukladací priestor"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sl/strings.xml b/packages/ExternalStorageProvider/res/values-sl/strings.xml
index 7925fec..6ffa698 100644
--- a/packages/ExternalStorageProvider/res/values-sl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sl/strings.xml
@@ -17,5 +17,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Zunanja shramba"</string>
- <string name="root_internal_storage" msgid="827844243068584127">"Notranji pomnilnik"</string>
+ <string name="root_internal_storage" msgid="827844243068584127">"Notranja shramba"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sr/strings.xml b/packages/ExternalStorageProvider/res/values-sr/strings.xml
index 23b5561..54238a4 100644
--- a/packages/ExternalStorageProvider/res/values-sr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sr/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Спољна меморија"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Интерна меморија"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Документи"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sv/strings.xml b/packages/ExternalStorageProvider/res/values-sv/strings.xml
index 6b82ab3..1837096 100644
--- a/packages/ExternalStorageProvider/res/values-sv/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sv/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Extern lagring"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Intern lagring"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sw/strings.xml b/packages/ExternalStorageProvider/res/values-sw/strings.xml
index 2f9a1f6..0d0e483 100644
--- a/packages/ExternalStorageProvider/res/values-sw/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sw/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Hifadhi ya Nje"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Hifadhi ya ndani"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Hati"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-th/strings.xml b/packages/ExternalStorageProvider/res/values-th/strings.xml
index d7e0191..796635e 100644
--- a/packages/ExternalStorageProvider/res/values-th/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-th/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ที่จัดเก็บข้อมูลภายนอก"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ที่จัดเก็บข้อมูลภายใน"</string>
+ <string name="root_documents" msgid="4051252304075469250">"เอกสาร"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-tl/strings.xml b/packages/ExternalStorageProvider/res/values-tl/strings.xml
index 360d941..529cdc2 100644
--- a/packages/ExternalStorageProvider/res/values-tl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-tl/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"External Storage"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Internal storage"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Mga Dokumento"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-tr/strings.xml b/packages/ExternalStorageProvider/res/values-tr/strings.xml
index 547f4df..ff3f68a 100644
--- a/packages/ExternalStorageProvider/res/values-tr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-tr/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Harici Depolama"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Dahili depolama"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-uk/strings.xml b/packages/ExternalStorageProvider/res/values-uk/strings.xml
index 7a8c161..b8206e0 100644
--- a/packages/ExternalStorageProvider/res/values-uk/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-uk/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Зовнішня пам’ять"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Внутрішня пам’ять"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Документи"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-vi/strings.xml b/packages/ExternalStorageProvider/res/values-vi/strings.xml
index f5c8889..b171c93 100644
--- a/packages/ExternalStorageProvider/res/values-vi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-vi/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Bộ nhớ ngoài"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Bộ nhớ trong"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Tài liệu"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml b/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml
index 772ef94..0550c50 100644
--- a/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"外部存储设备"</string>
<string name="root_internal_storage" msgid="827844243068584127">"内部存储空间"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml b/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
index 6163163..62d8afb 100644
--- a/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"外部儲存空間"</string>
<string name="root_internal_storage" msgid="827844243068584127">"內部儲存空間"</string>
+ <string name="root_documents" msgid="4051252304075469250">"文件"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml b/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml
index 6163163..62d8afb 100644
--- a/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"外部儲存空間"</string>
<string name="root_internal_storage" msgid="827844243068584127">"內部儲存空間"</string>
+ <string name="root_documents" msgid="4051252304075469250">"文件"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-zu/strings.xml b/packages/ExternalStorageProvider/res/values-zu/strings.xml
index 3c4cd95..dcaefc5 100644
--- a/packages/ExternalStorageProvider/res/values-zu/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zu/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Isitoreji sangaphandle"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Isitoreji sangaphakathi"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values/strings.xml b/packages/ExternalStorageProvider/res/values/strings.xml
index 0eaf500a..f1c1ade 100644
--- a/packages/ExternalStorageProvider/res/values/strings.xml
+++ b/packages/ExternalStorageProvider/res/values/strings.xml
@@ -15,6 +15,11 @@
-->
<resources>
+ <!-- Title of the external storage application [CHAR LIMIT=32] -->
<string name="app_label">External Storage</string>
+
+ <!-- Title for documents backend that offers internal storage. [CHAR LIMIT=24] -->
<string name="root_internal_storage">Internal storage</string>
+ <!-- Title for documents backend that offers documents. [CHAR LIMIT=24] -->
+ <string name="root_documents">Documents</string>
</resources>
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 226d635..3e2cd15 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -62,7 +62,6 @@
public String rootId;
public int rootType;
public int flags;
- public int icon;
public String title;
public String docId;
}
@@ -85,9 +84,10 @@
mIdToPath.put(rootId, path);
final RootInfo root = new RootInfo();
- root.rootId = "primary";
+ root.rootId = rootId;
root.rootType = Root.ROOT_TYPE_DEVICE;
- root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED;
+ root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED
+ | Root.FLAG_SUPPORTS_SEARCH;
root.title = getContext().getString(R.string.root_internal_storage);
root.docId = getDocIdForFile(path);
mRoots.add(root);
@@ -96,6 +96,25 @@
throw new IllegalStateException(e);
}
+ try {
+ final String rootId = "documents";
+ final File path = Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_DOCUMENTS);
+ mIdToPath.put(rootId, path);
+
+ final RootInfo root = new RootInfo();
+ root.rootId = rootId;
+ root.rootType = Root.ROOT_TYPE_SHORTCUT;
+ root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY
+ | Root.FLAG_SUPPORTS_SEARCH;
+ root.title = getContext().getString(R.string.root_documents);
+ root.docId = getDocIdForFile(path);
+ mRoots.add(root);
+ mIdToRoot.put(rootId, root);
+ } catch (FileNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
+
return true;
}
@@ -146,6 +165,9 @@
if (target == null) {
throw new FileNotFoundException("No root for " + tag);
}
+ if (!target.exists()) {
+ target.mkdirs();
+ }
target = new File(target, path);
if (!target.exists()) {
throw new FileNotFoundException("Missing file for " + docId + " at " + target);
@@ -163,9 +185,6 @@
int flags = 0;
- if (file.isDirectory()) {
- flags |= Document.FLAG_DIR_SUPPORTS_SEARCH;
- }
if (file.isDirectory() && file.canWrite()) {
flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
}
@@ -181,12 +200,12 @@
}
final RowBuilder row = result.newRow();
- row.offer(Document.COLUMN_DOCUMENT_ID, docId);
- row.offer(Document.COLUMN_DISPLAY_NAME, displayName);
- row.offer(Document.COLUMN_SIZE, file.length());
- row.offer(Document.COLUMN_MIME_TYPE, mimeType);
- row.offer(Document.COLUMN_LAST_MODIFIED, file.lastModified());
- row.offer(Document.COLUMN_FLAGS, flags);
+ row.add(Document.COLUMN_DOCUMENT_ID, docId);
+ row.add(Document.COLUMN_DISPLAY_NAME, displayName);
+ row.add(Document.COLUMN_SIZE, file.length());
+ row.add(Document.COLUMN_MIME_TYPE, mimeType);
+ row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified());
+ row.add(Document.COLUMN_FLAGS, flags);
}
@Override
@@ -197,13 +216,12 @@
final File path = mIdToPath.get(rootId);
final RowBuilder row = result.newRow();
- row.offer(Root.COLUMN_ROOT_ID, root.rootId);
- row.offer(Root.COLUMN_ROOT_TYPE, root.rootType);
- row.offer(Root.COLUMN_FLAGS, root.flags);
- row.offer(Root.COLUMN_ICON, root.icon);
- row.offer(Root.COLUMN_TITLE, root.title);
- row.offer(Root.COLUMN_DOCUMENT_ID, root.docId);
- row.offer(Root.COLUMN_AVAILABLE_BYTES, path.getFreeSpace());
+ row.add(Root.COLUMN_ROOT_ID, root.rootId);
+ row.add(Root.COLUMN_ROOT_TYPE, root.rootType);
+ row.add(Root.COLUMN_FLAGS, root.flags);
+ row.add(Root.COLUMN_TITLE, root.title);
+ row.add(Root.COLUMN_DOCUMENT_ID, root.docId);
+ row.add(Root.COLUMN_AVAILABLE_BYTES, path.getFreeSpace());
}
return result;
}
@@ -260,23 +278,22 @@
}
@Override
- public Cursor querySearchDocuments(String parentDocumentId, String query, String[] projection)
+ public Cursor querySearchDocuments(String rootId, String query, String[] projection)
throws FileNotFoundException {
final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
- final File parent = getFileForDocId(parentDocumentId);
+ final File parent = mIdToPath.get(rootId);
final LinkedList<File> pending = new LinkedList<File>();
pending.add(parent);
- while (!pending.isEmpty() && result.getCount() < 20) {
+ while (!pending.isEmpty() && result.getCount() < 24) {
final File file = pending.removeFirst();
if (file.isDirectory()) {
for (File child : file.listFiles()) {
pending.add(child);
}
- } else {
- if (file.getName().toLowerCase().contains(query)) {
- includeFile(result, null, file);
- }
+ }
+ if (file.getName().toLowerCase().contains(query)) {
+ includeFile(result, null, file);
}
}
return result;
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
index 93db592..a917e3f 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
@@ -17,10 +17,18 @@
package com.android.externalstorage;
import android.content.ContentResolver;
+import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.MatrixCursor.RowBuilder;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Point;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
@@ -31,7 +39,14 @@
import android.provider.DocumentsProvider;
import android.util.Log;
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.lang.ref.WeakReference;
public class TestDocumentsProvider extends DocumentsProvider {
@@ -69,13 +84,13 @@
final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
final RowBuilder row = result.newRow();
- row.offer(Root.COLUMN_ROOT_ID, MY_ROOT_ID);
- row.offer(Root.COLUMN_ROOT_TYPE, Root.ROOT_TYPE_SERVICE);
- row.offer(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_RECENTS);
- row.offer(Root.COLUMN_TITLE, "_Test title which is really long");
- row.offer(Root.COLUMN_SUMMARY, "_Summary which is also super long text");
- row.offer(Root.COLUMN_DOCUMENT_ID, MY_DOC_ID);
- row.offer(Root.COLUMN_AVAILABLE_BYTES, 1024);
+ row.add(Root.COLUMN_ROOT_ID, MY_ROOT_ID);
+ row.add(Root.COLUMN_ROOT_TYPE, Root.ROOT_TYPE_SERVICE);
+ row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_RECENTS);
+ row.add(Root.COLUMN_TITLE, "_Test title which is really long");
+ row.add(Root.COLUMN_SUMMARY, "_Summary which is also super long text");
+ row.add(Root.COLUMN_DOCUMENT_ID, MY_DOC_ID);
+ row.add(Root.COLUMN_AVAILABLE_BYTES, 1024);
return result;
}
@@ -85,7 +100,7 @@
if (CRASH_DOCUMENT) System.exit(12);
final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
- includeFile(result, documentId);
+ includeFile(result, documentId, 0);
return result;
}
@@ -122,12 +137,12 @@
public boolean includeIfFinished(MatrixCursor result) {
Log.d(TAG, hashCode() + ": includeIfFinished() found " + mFinished);
if (mFinished) {
- includeFile(result, "_networkfile1");
- includeFile(result, "_networkfile2");
- includeFile(result, "_networkfile3");
- includeFile(result, "_networkfile4");
- includeFile(result, "_networkfile5");
- includeFile(result, "_networkfile6");
+ includeFile(result, "_networkfile1", 0);
+ includeFile(result, "_networkfile2", 0);
+ includeFile(result, "_networkfile3", 0);
+ includeFile(result, "_networkfile4", 0);
+ includeFile(result, "_networkfile5", 0);
+ includeFile(result, "_networkfile6", 0);
return true;
} else {
return false;
@@ -162,11 +177,11 @@
result.setNotificationUri(resolver, notifyUri);
// Always include local results
- includeFile(result, MY_DOC_NULL);
- includeFile(result, "localfile1");
- includeFile(result, "localfile2");
- includeFile(result, "localfile3");
- includeFile(result, "localfile4");
+ includeFile(result, MY_DOC_NULL, 0);
+ includeFile(result, "localfile1", 0);
+ includeFile(result, "localfile2", Document.FLAG_SUPPORTS_THUMBNAIL);
+ includeFile(result, "localfile3", 0);
+ includeFile(result, "localfile4", 0);
synchronized (this) {
// Try picking up an existing network fetch
@@ -217,7 +232,8 @@
SystemClock.sleep(3000);
final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
- includeFile(result, "It was /worth/ the_wait for?the file:with the&incredibly long name");
+ includeFile(
+ result, "It was /worth/ the_wait for?the file:with the&incredibly long name", 0);
return result;
}
@@ -228,22 +244,58 @@
}
@Override
+ public AssetFileDescriptor openDocumentThumbnail(
+ String docId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException {
+ final Bitmap bitmap = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(bitmap);
+ final Paint paint = new Paint();
+ paint.setColor(Color.BLUE);
+ canvas.drawColor(Color.RED);
+ canvas.drawLine(0, 0, 32, 32, paint);
+
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ bitmap.compress(CompressFormat.JPEG, 50, bos);
+
+ final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+ try {
+ final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createReliablePipe();
+ new AsyncTask<Object, Object, Object>() {
+ @Override
+ protected Object doInBackground(Object... params) {
+ final FileOutputStream fos = new FileOutputStream(fds[1].getFileDescriptor());
+ try {
+ Streams.copy(bis, fos);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ IoUtils.closeQuietly(fds[1]);
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ return new AssetFileDescriptor(fds[0], 0, AssetFileDescriptor.UNKNOWN_LENGTH);
+ } catch (IOException e) {
+ throw new FileNotFoundException(e.getMessage());
+ }
+ }
+
+ @Override
public boolean onCreate() {
return true;
}
- private static void includeFile(MatrixCursor result, String docId) {
+ private static void includeFile(MatrixCursor result, String docId, int flags) {
final RowBuilder row = result.newRow();
- row.offer(Document.COLUMN_DOCUMENT_ID, docId);
- row.offer(Document.COLUMN_DISPLAY_NAME, docId);
- row.offer(Document.COLUMN_LAST_MODIFIED, System.currentTimeMillis());
+ row.add(Document.COLUMN_DOCUMENT_ID, docId);
+ row.add(Document.COLUMN_DISPLAY_NAME, docId);
+ row.add(Document.COLUMN_LAST_MODIFIED, System.currentTimeMillis());
+ row.add(Document.COLUMN_FLAGS, flags);
if (MY_DOC_ID.equals(docId)) {
- row.offer(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
+ row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
} else if (MY_DOC_NULL.equals(docId)) {
// No MIME type
} else {
- row.offer(Document.COLUMN_MIME_TYPE, "application/octet-stream");
+ row.add(Document.COLUMN_MIME_TYPE, "application/octet-stream");
}
}
}
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
index d2c82c8..7d77c48 100644
--- a/packages/Keyguard/AndroidManifest.xml
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -37,8 +37,6 @@
<uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
<uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
- <!-- Permission to perform hotword recognition -->
- <uses-permission android:name="android.permission.HOTWORD_RECOGNITION" />
<application android:label="@string/app_name"
android:process="com.android.systemui"
diff --git a/packages/Keyguard/res/values-en-rIN/strings.xml b/packages/Keyguard/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..967c3fa
--- /dev/null
+++ b/packages/Keyguard/res/values-en-rIN/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Type PIN code"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Type PUK and new PIN code"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK code"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"New PIN Code"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Touch to type password"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Type password to unlock"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Type PIN to unlock"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Incorrect PIN code."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"To unlock, press Menu, then 0."</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maximum Face Unlock attempts exceeded"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Charged"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"Charging, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"Connect your charger."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Press Menu to unlock."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Network locked"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"No SIM card"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"No SIM card in tablet."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"No SIM card in phone."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Insert a SIM card."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"The SIM card is missing or not readable. Insert a SIM card."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Unusable SIM card."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Your SIM card has been permanently disabled.\n Contact your wireless service provider for another SIM card."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM card is locked."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM card is PUK-locked."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Unlocking SIM card…"</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d of %3$d."</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Add widget"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Empty"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Unlock area expanded."</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Unlock area collapsed."</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"User selector"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Camera"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Media controls"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Widget reordering started."</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Widget reordering ended."</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> deleted."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Expand unlock area."</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Slide unlock."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Pattern unlock."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Face unlock."</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin unlock."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Password unlock."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Pattern area."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Slide area."</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Previous track button"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Next track button"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pause button"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Play button"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stop button"</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Done"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mode change"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"Unlock"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"Camera"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"Silent"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"Sound on"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Search"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Slide down for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Slide left for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Slide right for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency call"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Forgot Pattern"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Wrong Pattern"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Wrong Password"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"Wrong PIN"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Try again in <xliff:g id="NUMBER">%d</xliff:g> seconds."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Draw your pattern"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Enter SIM PIN"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"Enter PIN"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Enter Password"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Enter desired PIN code"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirm desired PIN code"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Unlocking SIM card…"</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Incorrect PIN code."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Type a PIN that is 4 to 8 numbers."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK code should be 8 numbers or more."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN codes do not match"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Too many pattern attempts"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"To unlock, sign in with your Google account."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Username (email)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Sign in"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"Invalid username or password."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Forgot your username or password?\nVisit "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"Checking account…"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the tablet will be reset to factory default and all user data will be lost."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the phone will be reset to factory default and all user data will be lost."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The tablet will now be reset to factory default."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The phone will now be reset to factory default."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+ <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remove"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Previous track button"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Next track button"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pause button"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Play button"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Stop button"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"No service."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-es/strings.xml b/packages/Keyguard/res/values-es/strings.xml
index d0c79eb..3e4fe54 100644
--- a/packages/Keyguard/res/values-es/strings.xml
+++ b/packages/Keyguard/res/values-es/strings.xml
@@ -30,7 +30,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorrecto"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear el teléfono, pulsa la tecla de menú y, a continuación, pulsa 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se ha superado el número máximo de intentos de desbloqueo facial."</string>
- <string name="keyguard_charged" msgid="3272223906073492454">"Cargado"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Cargada"</string>
<string name="keyguard_plugged_in" msgid="8117572000639998388">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Conecta el cargador."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Ve al menú para desbloquear la pantalla."</string>
diff --git a/packages/Keyguard/res/values-et-rEE/strings.xml b/packages/Keyguard/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..0a17a9c
--- /dev/null
+++ b/packages/Keyguard/res/values-et-rEE/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Sisestage PIN-kood"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Sisestage PUK-kood ja uus PIN-kood"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK-kood"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Uus PIN-kood"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Puudutage parooli sisestamiseks"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Avamiseks sisestage parool"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Avamiseks sisestage PIN-kood"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Vale PIN-kood."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"Avamiseks vajutage menüüklahvi, seejärel klahvi 0."</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maksimaalne teenusega Face Unlock avamise katsete arv on ületatud"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Laetud"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"Laadimine, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"Ühendage laadija."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Avamiseks vajutage menüüklahvi."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Võrk on suletud"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"SIM-kaarti pole"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Tahvelarvutis pole SIM-kaarti."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Telefonis pole SIM-kaarti."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Sisestage SIM-kaart."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM-kaart puudub või on loetamatu. Sisestage SIM-kaart."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Kasutamiskõlbmatu SIM-kaart."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM-kaart on jäädavalt keelatud.\n Uue SIM-kaardi saamiseks võtke ühendust oma mobiilsideoperaatoriga."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kaart on lukus."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kaart on PUK-lukus."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM-kaardi avamine ..."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Vidin %2$d/%3$d."</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Vidina lisamine."</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tühi"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Avamisala on laiendatud."</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Avamisala on ahendatud."</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Vidin <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Kasutaja valija"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Olek"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kaamera"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Meedia juhtnupud"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Vidina ümberkorraldamine algas."</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Vidina ümberkorraldamine lõppes."</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Vidin <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> on kustutatud."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Avamisala laiendamine."</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Lohistamisega avamine."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Mustriga avamine."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Näoga avamine."</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN-koodiga avamine."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Parooliga avamine."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Mustri ala."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Lohistamisala."</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Nupp Eelmine lugu"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Nupp Järgmine lugu"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Nupp Peata"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Nupp Esita"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Nupp Peata"</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Tühista"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Kustuta"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Valmis"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Režiimi muutmine"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Tõstuklahv"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Sisestusklahv"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"Luku avamine"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"Kaamera"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"Hääletu"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"Heli on sees"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Otsing"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"Lohistage üles: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Lohistage alla: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Lohistage vasakule: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Lohistage paremale: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Praegune kasutaja <xliff:g id="NAME">%1$s</xliff:g>."</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"Hädaabikõne"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Unustasin mustri"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Vale muster"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Vale parool"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"Vale PIN-kood"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Proovige uuesti <xliff:g id="NUMBER">%d</xliff:g> sekundi pärast."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Joonistage oma muster"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Sisestage SIM-i PIN-kood"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"Sisestage PIN-kood"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Sisestage parool"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM on nüüd keelatud. Jätkamiseks sisestage PUK-kood. Üksikasju küsige operaatorilt."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Sisestage soovitud PIN-kood"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Kinnitage soovitud PIN-kood"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-kaardi avamine ..."</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Vale PIN-kood."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Sisestage 4–8-numbriline PIN-kood."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koodi pikkus peab olema vähemalt 8 numbrit."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Sisestage uuesti õige PUK-kood. Korduvkatsete korral keelatakse SIM jäädavalt."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koodid ei ole vastavuses"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liiga palju mustrikatseid"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"Avamiseks logige sisse oma Google\'i kontoga."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Kasutajanimi (e-post)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"Parool"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Logi sisse"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"Vale kasutajanimi või parool."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Kas unustasite kasutajanime või parooli?\nKülastage aadressi "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"Konto kontrollimine ..."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olete PIN-koodi <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud.\n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olete parooli <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud. \n\nProovige uuesti <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti.\n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Olete üritanud <xliff:g id="NUMBER_0">%d</xliff:g> korda tahvelarvutit valesti avada. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset lähtestatakse tahvelarvuti tehase vaikeseadetele ja kõik kasutajaandmed lähevad kaotsi."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Olete üritanud <xliff:g id="NUMBER_0">%d</xliff:g> korda telefoni valesti avada. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset lähtestatakse telefon tehase vaikeseadetele ja kõik kasutajaandmed lähevad kaotsi."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Olete püüdnud tahvelarvutit <xliff:g id="NUMBER">%d</xliff:g> korda valesti avada. Tahvelarvuti lähtestatakse nüüd tehase vaikeseadetele."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Olete püüdnud telefoni <xliff:g id="NUMBER">%d</xliff:g> korda valesti avada. Telefon lähtestatakse nüüd tehase vaikeseadetele."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
+ <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eemalda"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Nupp Eelmine lugu"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Nupp Järgmine lugu"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Nupp Peata"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Nupp Esita"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Nupp Peata"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"Teenus puudub."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-fr-rCA/strings.xml b/packages/Keyguard/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..35e897d
--- /dev/null
+++ b/packages/Keyguard/res/values-fr-rCA/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Saisissez le NIP."</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Saisissez la clé PUK et le nouveau NIP."</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Clé PUK"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Nouveau NIP"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Appuyer pour saisir mot passe"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Saisissez le mot de passe pour déverrouiller le clavier."</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Saisissez le NIP pour déverrouiller le clavier."</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"NIP erroné."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"Pour déverrouiller le téléphone, appuyez sur \"Menu\", puis sur 0."</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Nombre maximal autorisé de tentatives Face Unlock atteint."</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Chargé"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"En charge (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"Branchez votre chargeur."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Appuyez sur \"Menu\" pour déverrouiller l\'appareil."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Réseau verrouillé"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Aucune carte SIM"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Aucune carte SIM n\'est insérée dans la tablette."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Aucune carte SIM n\'est insérée dans le téléphone."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Insérez une carte SIM."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Carte SIM absente ou illisible. Veuillez insérer une carte SIM."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Carte SIM inutilisable."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Votre carte SIM a été définitivement désactivée.\n Veuillez contacter votre opérateur de téléphonie mobile pour en obtenir une autre."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"La carte SIM est verrouillée."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"La carte SIM est verrouillée par clé PUK."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Déverrouillage de la carte SIM en cours…"</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d sur %3$d."</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Ajouter un widget"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vide"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Développement de la zone de déverrouillage"</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Réduction de la zone de déverrouillage"</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Sélecteur d\'utilisateur"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"État"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Caméra"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Commandes multimédias"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Début de la réorganisation des widgets"</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Fin de la réorganisation des widgets"</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Le widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> a été supprimé."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Développer la zone de déverrouillage"</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Déverrouillage en faisant glisser votre doigt sur l\'écran"</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Déverrouillage par schéma"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Déverrouillage par reconnaissance faciale"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Déverrouillage par NIP"</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Déverrouillage par mot de passe"</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Zone du schéma"</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Zone où faire glisser votre doigt sur l\'écran"</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Bouton pour revenir au titre précédent"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Bouton pour atteindre le titre suivant"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Bouton de pause"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Bouton de lecture"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Bouton d\'arrêt"</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuler"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Supprimer"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Terminé"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Changement de mode"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Maj"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Entrée"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"Déverrouiller"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"Appareil photo"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"Mode silencieux"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"Son activé"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Recherche"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"Faire glisser le doigt vers le haut : <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Faire glisser le doigt vers le bas : <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Faites glisser votre doigt vers la gauche pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Faites glisser votre doigt vers la droite pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"Appel d\'urgence"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"J\'ai oublié le schéma"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Schéma incorrect."</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Mot de passe incorrect."</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"NIP incorrect."</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Réessayez dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Dessinez votre schéma."</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Saisissez le NIP de la carte SIM"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"Saisissez le NIP."</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Saisissez votre mot de passe."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"La carte SIM est maintenant désactivée. Saisissez le code PUK pour continuer. Contactez votre opérateur pour en savoir plus."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Saisir le NIP souhaité"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirmer le NIP souhaité"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Déblocage de la carte SIM en cours…"</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"NIP erroné."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Saisissez un NIP comprenant entre quatre et huit chiffres"</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Le code PUK doit contenir au moins 8 chiffres."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Veuillez saisir de nouveau le code PUK correct. Des tentatives répétées désactivent définitivement la carte SIM."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Les codes PIN ne correspondent pas."</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Trop de tentatives."</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"Pour déverrouiller l\'appareil, connectez-vous avec votre compte Google."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Nom d\'utilisateur (courriel)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"Mot de passe"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Connexion"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nom d\'utilisateur ou mot de passe non valide."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Vous avez oublié votre nom d\'utilisateur ou votre mot de passe?\nRendez-vous sur la page "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"Vérification du compte en cours…"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi un NIP incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Vous avez tenté de déverrouiller la tablette de façon incorrecte à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, sa configuration d\'usine sera rétablie, et toutes les données utilisateur seront perdues."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Vous avez tenté de déverrouiller le téléphone de façon incorrecte à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, sa configuration d\'usine sera rétablie, et toutes les données utilisateur seront perdues."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Vous avez tenté de déverrouiller la tablette de façon incorrecte à <xliff:g id="NUMBER">%d</xliff:g> reprises. Sa configuration d\'usine va être rétablie."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Vous avez tenté de déverrouiller le téléphone de façon incorrecte à <xliff:g id="NUMBER">%d</xliff:g> reprises. Sa configuration d\'usine va être rétablie."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+ <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Supprimer"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Bouton pour revenir au titre précédent"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Bouton pour atteindre le titre suivant"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Bouton de pause"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Bouton de lecture"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Bouton d\'arrêt"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aucun service"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml
index 714d9fb..2c6188a 100644
--- a/packages/Keyguard/res/values-hi/strings.xml
+++ b/packages/Keyguard/res/values-hi/strings.xml
@@ -60,11 +60,11 @@
<string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"विजेट <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> को हटा दिया गया."</string>
<string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"अनलॉक क्षेत्र विस्तृत करें."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"स्लाइड अनलॉक."</string>
- <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"प्रतिमान अनलॉक."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"आकार अनलॉक."</string>
<string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"फेस अनलॉक."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"पिन अनलॉक."</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"पासवर्ड अनलॉक."</string>
- <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"प्रतिमान क्षेत्र."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"आकार क्षेत्र."</string>
<string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"स्लाइड क्षेत्र."</string>
<string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"पिछला ट्रैक बटन"</string>
<string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"अगला ट्रैक बटन"</string>
@@ -92,12 +92,12 @@
<string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए दाएं स्लाइड करें."</string>
<string name="user_switched" msgid="3768006783166984410">"वर्तमान उपयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"आपातकालीन कॉल"</string>
- <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"प्रतिमान भूल गए"</string>
- <string name="kg_wrong_pattern" msgid="1850806070801358830">"गलत प्रतिमान"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"आकार भूल गए"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"गलत आकार"</string>
<string name="kg_wrong_password" msgid="2333281762128113157">"गलत पासवर्ड"</string>
<string name="kg_wrong_pin" msgid="1131306510833563801">"गलत PIN"</string>
<string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="kg_pattern_instructions" msgid="398978611683075868">"अपना प्रतिमान आरेखित करें"</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"अपना आकार आरेखित करें"</string>
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"सिम PIN डालें"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"PIN डालें"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"पासवर्ड डालें"</string>
@@ -110,23 +110,23 @@
<string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK कोड 8 या अधिक संख्या वाला होना चाहिए."</string>
<string name="kg_invalid_puk" msgid="3638289409676051243">"सही PUK कोड पुन: डालें. बार-बार प्रयास करने से सिम स्थायी रूप से अक्षम हो जाएगी."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"पिन कोड का मिलान नहीं होता"</string>
- <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बहुत अधिक प्रतिमान प्रयास"</string>
- <string name="kg_login_instructions" msgid="1100551261265506448">"अनलॉक करने के लिए, अपने Google खाते से साइन इन करें."</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बहुत अधिक आकार प्रयास"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"अनलॉक करने के लिए, अपने Google खाते से प्रवेश करें."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"उपयोगकर्ता नाम (ईमेल)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"पासवर्ड"</string>
- <string name="kg_login_submit_button" msgid="5355904582674054702">"साइन इन करें"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"प्रवेश करें"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"अमान्य उपयोगकर्ता नाम या पासवर्ड."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"अपना उपयोगकर्ता नाम या पासवर्ड भूल गए?\n "<b>"google.com/accounts/recovery"</b>" पर जाएं."</string>
<string name="kg_login_checking_password" msgid="1052685197710252395">"खाते की जांच की जा रही है…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आप अपना PIN <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आप अपना पासवर्ड <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपने अपना अनलॉक प्रतिमान <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"आप टेबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, टेबलेट फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"आप फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, फ़ोन फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"आप टेबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. टेबलेट अब फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"आप फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. फ़ोन अब फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक प्रतिमान को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टेबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक प्रतिमान को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टेबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"निकालें"</string>
<string name="keyguard_transport_prev_description" msgid="8229108430245669854">"पिछला ट्रैक बटन"</string>
diff --git a/packages/Keyguard/res/values-hy-rAM/strings.xml b/packages/Keyguard/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..19b3c79
--- /dev/null
+++ b/packages/Keyguard/res/values-hy-rAM/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Մուտքագրեք PIN կոդը"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Մուտքագրեք PUK-ը և նոր PIN կոդը"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK կոդ"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Նոր PIN ծածկագիր"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Հպեք` գաղտնաբառը մուտքագրելու համար"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Մուտքագրեք գաղտնաբառը ապակողպման համար"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Մուտքագրեք PIN-ը ապակողպման համար"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Սխալ PIN ծածկագիր:"</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"Ապակողպման համար սեղմեք Ցանկ, ապա 0:"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Առավելագույն Դեմքով ապակողպման փորձերը գերազանցված են"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Լիցքավորված է"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"Լիցքավորում, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"Միացրեք ձեր լիցքավորիչը:"</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Ապակողպելու համար սեղմեք Ցանկը:"</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Ցանցը կողպված է"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"SIM քարտ չկա"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Գրասալիկում SIM քարտ չկա:"</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Հեռախոսի մեջ SIM քարտ չկա:"</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Զետեղեք SIM քարտը:"</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM քարտը բացակայում է կամ չի կարող կարդացվել: Մտցրեք SIM քարտ:"</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Անպիտան SIM քարտ:"</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Ձեր SIM քարտը ընդմիշտ կասեցվել է:\nԿապվեք ձեր բջջային ծառայության մատակարարի հետ նոր SIM քարտ ձեռք բերելու համար:"</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM քարտը կողպված է:"</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM քարտը PUK-ով կողպված է:"</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM քարտը ապակողպվում է..."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Վիջեթ %2$d of %3$d:"</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Ավելացնել վիջեթ:"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Դատարկ"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Ապակողպման տարածքն ընդլայնված է:"</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Ապակողպման տարածքը ետ է ծալված:"</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> վիջեթ:"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Օգտվողի ընտրիչ"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Կարգավիճակ"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Ֆոտոխցիկ"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Մեդիա կարգավորումներ"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Վիջեթների վերադասավորումը մեկնարկել է:"</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Վիջեթի վերադասավորումն ավարտվեց:"</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Վիջեթ <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>-ը ջնջված է:"</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Ընդլայնել ապակողպման տարածությունը:"</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Էջի ապակողպում:"</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Սխեմայով ապակողպում:"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Դեմքով ապակողպում:"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin-ն ապակողպված է:"</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Գաղտնաբառի ապակողպում:"</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Սխեմայի տարածք:"</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Սահեցման տարածք:"</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Նախորդ հետագծի կոճակը"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Հաջորդ հետագծի կոճակը"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Դադարի կոճակ"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Նվագարկման կոճակ"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Կանգի կոճակ"</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Չեղարկել"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ջնջել"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Կատարված է"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Ռեժիմի փոփոխում"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Մուտք"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"Ապակողպել"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"Ֆոտոխցիկ"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"Լուռ"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"Ձայնը միացնել"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Որոնել"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"Սահեցրեք վերև <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Սահեցրեք ցած <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Սահեցրեք ձախ` <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Սահեցրեք աջ` <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
+ <string name="user_switched" msgid="3768006783166984410">"Ներկայիս օգտվողը <xliff:g id="NAME">%1$s</xliff:g>:"</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"Արտակարգ իրավիճակի հեռախոսազանգ"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Մոռացել եմ սխեման"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Սխալ սխեմա"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Սխալ գաղտնաբառ"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"Սխալ PIN"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Փորձեք կրկին <xliff:g id="NUMBER">%d</xliff:g> վայրկյանից:"</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Հավաքեք ձեր սխեման"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Մուտքագրեք SIM-ի PIN-ը"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"Մուտքագրեք PIN-ը"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Մուտքագրեք գաղտնաբառը"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-ը այս պահին անջատված է: Մուտքագրեք PUK կոդը շարունակելու համար: Մանրամասների համար կապվեք օպերատորի հետ:"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Մուտքագրեք ցանկալի PIN ծածկագիրը"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Հաստատեք ցանկալի PIN ծածկագիրը"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ապակողպում է SIM քարտը ..."</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Սխալ PIN ծածկագիր:"</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Մուտքագրեք PIN, որը 4-ից 8 թիվ է:"</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK կոդը պետք է լինի 8 կամ ավելի թիվ:"</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Վերամուտքագրեք ճիշտ PUK ծածկագիրը: Կրկնվող փորձերը ընդմիշտ կկասեցնեն SIM քարտը:"</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN ծածկագրերը չեն համընկնում"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Չափից շատ սխեմայի փորձեր"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"Ապակողպելու համար` մուտք գործեք ձեր Google հաշվով:"</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Օգտանուն (էլփոստ)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"Գաղտնաբառը"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Մուտք գործել"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"Սխալ օգտանուն կամ գաղտնաբառ:"</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Մոռացե՞լ եք ձեր օգտանունը կամ գաղտնաբառը:\nԱյցելեք "<b>"google.com /accounts/recovery"</b>":"</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"Հաշիվը ստուգվում է..."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ եք մուտքագրել ձեր PIN-ը: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:"</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Դուք սխալ եք մուտքագրել ձեր գաղտնաբառը <xliff:g id="NUMBER_0">%d</xliff:g> անգամ: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:"</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ եք հավաքել ձեր ապակողպման սխեման: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ փորձ եք արել գրասալիկն ապակողպելու համար: <xliff:g id="NUMBER_1">%d</xliff:g> անգամից ավել անհաջող փորձերից հետո գրասալիկը կվերակարգավորվի գործարանային լռելյայնի, և օգտվողի բոլոր տվյալները կկորեն:"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ փորձ եք արել հեռախոսն ապակողպելու համար: <xliff:g id="NUMBER_1">%d</xliff:g> անգամից ավել անհաջող փորձերից հետո հեռախոսը կվերակարգավորվի գործարանային լռելյայնի, և օգտվողի բոլոր տվյալները կկորեն:"</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Դուք <xliff:g id="NUMBER">%d</xliff:g> անգամ սխալ փորձ եք արել գրասալիկն ապակողպելու համար: Գրասալիկն այժմ կվերակարգավորվի գործարանային լռելյայնի:"</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Դուք <xliff:g id="NUMBER">%d</xliff:g> անգամ սխալ փորձ եք արել հեռախոսն ապակողպելու համար: Հեռախոսն այժմ կվերակարգավորվի գործարանային լռելյայնի:"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Դուք սխալ եք հավաքել ձեր ապակողպման սխեման <xliff:g id="NUMBER_0">%d</xliff:g> անգամ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել ձեր գրասալիկը` օգտագործելով էլփոստի հաշիվ:\n\n Փորձեք կրկին <xliff:g id="NUMBER_2">%d</xliff:g> վայրկյանից:"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ եք հավաքել ձեր ապակողպման նմուշը: <xliff:g id="NUMBER_1">%d</xliff:g> անգամից ավել անհաջող փորձերից հետո ձեզ կառաջարկվի ապակողպել ձեր հեռախոսը` օգտագործելով էլփոստի հաշիվ:\n\n Փորձեք կրկին <xliff:g id="NUMBER_2">%d</xliff:g> վայրկյանից:"</string>
+ <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Հեռացնել"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Նախորդ հետագծի կոճակ"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Հաջորդ հետագծի կոճակ"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Դադարի կոճակ"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Նվագարկման կոճակ"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Դադարի կոճակ"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ծառայություն չկա:"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-iw/strings.xml b/packages/Keyguard/res/values-iw/strings.xml
index 8d36309..c12a0e8 100644
--- a/packages/Keyguard/res/values-iw/strings.xml
+++ b/packages/Keyguard/res/values-iw/strings.xml
@@ -29,7 +29,7 @@
<string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"הקלד קוד PIN לביטול הנעילה"</string>
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"קוד PIN שגוי"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"כדי לבטל את הנעילה, לחץ על \'תפריט\' ולאחר מכן על 0."</string>
- <string name="faceunlock_multiple_failures" msgid="754137583022792429">"חרגת ממספר הניסיונות המרבי של זיהוי פרצוף"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"חרגת ממספר הניסיונות המרבי של זיהוי פנים"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"טעון"</string>
<string name="keyguard_plugged_in" msgid="8117572000639998388">"טוען, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"חבר את המטען."</string>
@@ -61,7 +61,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"הרחב את אזור ביטול הנעילה."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"ביטול נעילה באמצעות הסטה."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"ביטול נעילה באמצעות ציור קו."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ביטול נעילה באמצעות זיהוי פרצוף."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ביטול נעילה באמצעות זיהוי פנים."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"ביטול נעילה באמצעות מספר PIN."</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"ביטול נעילה באמצעות סיסמה."</string>
<string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"אזור ציור קו."</string>
diff --git a/packages/Keyguard/res/values-ka-rGE/strings.xml b/packages/Keyguard/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..b901bf4
--- /dev/null
+++ b/packages/Keyguard/res/values-ka-rGE/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"აკრიფეთ PIN კოდი"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"დაბეჭდეთ PUK კოდი და ახალი PIN კოდი."</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK კოდი"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"ახალი PIN კოდი"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384">"შეეხეთ "<font size="17">"-ს პაროლის"</font>" დასაბეჭდად."</string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"განსაბლოკად აკრიფეთ პაროლი"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"განსაბლოკად აკრიფეთ PIN კოდი"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"არასწორი PIN კოდი."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"განბლოკვისათვის დააჭირეთ მენიუს და შემდეგ 0-ს."</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"სახის ამოცნობით განბლოკვის მცდელობამ დაშვებულ რაოდენობას გადააჭარბა"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"დამუხტულია"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"მიმდინარეობს დამუხტვა (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"შეაერთეთ დამტენი."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"განბლოკვისთვის დააჭირეთ მენიუს."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"ქსელი ჩაკეტილია"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"SIM ბარათი არ არის"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"ტაბლეტში არ დევს SIM ბარათი."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"არ არის SIM ბარათი ტელეფონში."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"ჩადეთ SIM ბარათი."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM ბარათი არ არის ან არ იკითხება. ჩადეთ SIM ბარათი."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"არამოხმარებადი SIM ბარათი."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"თქვენი SIM ბარათი გამუდმებით გამორთული იყო.\n დაუკავშირდით თქვენი უკაბელო სერვისის პროვაიდერს სხვა SIM ბარათისთვის."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM ბარათი დაბლოკილია."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM ბარათი დაბლოკილია PUK კოდით."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"მიმდინარეობს SIM ბარათის განბლოკვა…"</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. ვიჯეტი %2$d of %3$d."</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ვიჯეტის დამატება"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ცარიელი"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"განბლოკვის სივრცე გაშლილია."</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"განბლოკვის სივრცე ჩაკეცილია."</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ვიჯეტი."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"მომხმარებლის ამომრჩეველი"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"სტატუსი"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"კამერა"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"მედიის მართვის ელემენტები"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"დაიწყო ვიჯეტის ხელახლა განლაგება."</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"ვიჯეტების გადახარისხება დასრულებულია."</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"ვიჯეტი <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> წაიშალა."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"განბლოკვის სივრცის გაშლა."</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"გასრიალებით განბლოკვა"</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"განბლოკვა ნიმუშით."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"განბლოკვა სახით"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"განბლოკვა Pin-ით."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"პაროლის განბლოკვა"</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"ნიმუშების სივრცე."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"გადასრიალების სივრცე."</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"წინა ჩანაწერის ღილაკი"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"შემდეგი ჩანაწერის ღილაკი"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"პაუზის ღილაკი"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"დაკვრის ღილაკი"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stop ღილაკი"</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"გაუქმება"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"წაშლა"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"დასრულდა"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"რეჟიმის შეცვლა"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift-"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"შეყვანა"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"განბლოკვა"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"კამერა"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"უხმო"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"ხმის ჩართვა"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"ძიება"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"გაასრიალეთ ზემოთ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"გაასრიალეთ ქვემოთ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"გაასრიალეთ მარცხნივ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"გაასრიალეთ მარჯვნივ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
+ <string name="user_switched" msgid="3768006783166984410">"ამჟამინდელი მომხმარებელი <xliff:g id="NAME">%1$s</xliff:g>."</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"გადაუდებელი დახმარების ზარი"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"დაგავიწყდათ ნიმუში"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"არასწორი ნიმუში"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"არასწორი პაროლი"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"არასწორი PIN"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"კიდევ სცადეთ <xliff:g id="NUMBER">%d</xliff:g> წამში."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"დახატეთ თქვენი ნიმუში."</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN-ის შეყვანა"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"შეიყვანეთ PIN"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"პაროლის შეყვანა"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM ამჟამად დეაქტივირებულია. გასაგრძელებლად შეიყვანეთ PUK კოდი. დეტალებისთვის მიმართეთ მობილურ ოპერატორს."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"სასურველი PIN კოდის შეყვანა"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"სასურველი PIN კოდის დადასტურება"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM ბარათის განბლოკვა…"</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"არასწორი PIN კოდი."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"აკრიფეთ PIN, რომელიც შედგება 4-დან 8 ციფრამდე."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK კოდი უნდა იყოს რვა ან მეტი ციფრისგან შემდგარი."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"ხელახლა შეიყვანეთ სწორი PUK კოდი. რამდენიმე წარუმატებელი მცდელობა გამოიწვევს SIM ბარათის დაბლოკვას."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN კოდები არ ემთხვევა"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ნახატი ნიმუშის ძალიან ბევრი მცდელობა"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"განბლოკვისთვის გაიარეთ ავტორიზაცია თქვენი Google ანგარიშით."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"მომხმარებლის სახელი (ელფოსტა)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"პაროლი"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"შესვლა"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"არასწორი სახელი, ან პაროლი."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"დაგავიწყდათ მომხმარებლის სახელი და პაროლი?\nეწვიეთ "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"მიმდინარეობს ანგარიშის შემოწმება…"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"თქვენ <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ არასწორად შეიყვანეთ PIN კოდი. \n\nსცადეთ ხელახლა <xliff:g id="NUMBER_1">%d</xliff:g> წამში."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"თქვენ <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ არასწორად დაბეჭდეთ თქვენი პაროლი. \n\nხელახლა სცადეთ <xliff:g id="NUMBER_1">%d</xliff:g> წამში."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"თქვენ <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ დახატეთ განბლოკვის ნიმუში. \n\nსცადეთ ხელახლა <xliff:g id="NUMBER_1">%d</xliff:g> წამში."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"თქვენ არასწორად სცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი ცდის შემდეგ ტაბლეტზე დაყენდება საწყისი, ქარხნული პარამეტრები და მომხმარებლის ყველა მონაცემი დაიკარგება."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი ცდის შემდეგ ტელეფონზე დაყენდება საწყისი, ქარხნული პარამეტრები და მომხმარებლის ყველა მონაცემი დაიკარგება."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"თქვენ არასწორად სცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ტაბლეტზე დაყენდება საწყისი, ქარხნული პარამეტრები და მომხმარებლის ყველა მონაცემი დაიკარგება."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"თქვენ <xliff:g id="NUMBER">%d</xliff:g>-ჯერ არასწორად სცადეთ ტელეფონის განბლოკვა. ამიტომ ტელეფონზე დადგება საწყისი, ქარხნული პარამეტრები."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი ცდის შემდეგ მოგთხოვთ ტაბლეტის განბლოკვას ელფოსტის ანგარიშის გამოყენებით.\n\n ხელახლა სცადეთ <xliff:g id="NUMBER_2">%d</xliff:g> წამში."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი ცდის შემდეგ, დაგჭირდებათ თქვენი ტელეფონის განბლოკვა ელფოსტის ანგარიშის გამოყენებით.\n\n ხელახლა სცადეთ <xliff:g id="NUMBER_2">%d</xliff:g> წამში."</string>
+ <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ამოშლა"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"წინა ჩანაწერზე გადასვლის ღილაკი"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"შემდეგი ჩანაწერის ღილაკი"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"პაუზის ღილაკი"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"დაკვრის ღილაკი"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"შეჩერების ღილაკი"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"არ არის სერვისი."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-km-rKH/strings.xml b/packages/Keyguard/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..586169e
--- /dev/null
+++ b/packages/Keyguard/res/values-km-rKH/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"បញ្ចូលកូដ PIN"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"បញ្ចូលកូដ PUK និង PIN ថ្មី"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"កូដ PUK"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"កូដ PIN ថ្មី"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"ប៉ះ ដើម្បីបញ្ចូលពាក្យសម្ងាត់"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"បញ្ចូលពាក្យសម្ងាត់ ដើម្បីដោះសោ"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"បញ្ចូលកូដ PIN ដើម្បីដោះសោ"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"កូដ PIN មិនត្រឹមត្រូវ។"</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"ដើម្បីដោះសោ ចុចម៉ឺនុយ បន្ទាប់មក 0 ។"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"បានលើសការព្យាយាមដោះសោតាមទម្រង់មុខ"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"បានបញ្ចូលពេញ"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"បញ្ចូលថ្ម <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"ភ្ជាប់ឧបករណ៍បញ្ចូលថ្ម។"</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"ចុចម៉ឺនុយ ដើម្បីដោះសោ។"</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"បណ្ដាញជាប់សោ"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"គ្មានស៊ីមកាត"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"គ្មានស៊ីមកាតនៅក្នុងកុំព្យូទ័របន្ទះ។"</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"គ្មានស៊ីមកាតក្នុងទូរស័ព្ទ។"</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"បញ្ចូលស៊ីមកាត។"</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"បាត់ស៊ីមកាត ឬមិនអាចអាន។ បញ្ចូលស៊ីមកាត។"</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"ស៊ីមកាតមិនអាចប្រើបាន។"</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"បានបិទស៊ីមកាតរបស់អ្នកជាអចិន្ត្រៃយ៍។\n ទាក់ទងក្រុមហ៊ុនផ្ដល់សេវាកម្មឥតខ្សែសម្រាប់ស៊ីមកាតផ្សេង។"</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"ស៊ីមកាតជាប់សោ។"</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"ស៊ីមកាតជាប់កូដ PUK ។"</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"កំពុងដោះសោស៊ីមកាត..."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. ធាតុក្រាហ្វិក %2$d នៃ %3$d ។"</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"បន្ថែមធាតុក្រាហ្វិក។"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ទទេ"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"បានពង្រីកផ្ទៃដោះសោ។"</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"បានបង្រួមផ្ទៃដោះសោ។"</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ធាតុក្រាហ្វិក។"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ឧបករណ៍ជ្រើសអ្នកប្រើ"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"ស្ថានភាព"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"ម៉ាស៊ីនថត"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"ពិនិត្យមេឌៀ"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"បានចាប់ផ្ដើមតម្រៀបធាតុក្រាហ្វិកឡើងវិញ។"</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"បានបញ្ចប់ការបង្ហាញធាតុក្រាហ្វិក។"</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"បានលុបធាតុក្រាហ្វិក <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ។"</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ពង្រីកតំបន់ដោះសោ។"</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"រុញដោះសោ។"</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"លំនាំដោះសោ។"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ដោះសោតាមទម្រង់មុខ។"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"កូដ PIN ដោះសោ។"</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"ពាក្យសម្ងាត់ដោះសោ។"</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"ផ្ទៃលំនាំ។"</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"ផ្ទៃរុញ។"</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"ប៊ូតុងបទមុន"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"ប៊ូតុងបទបន្ទាប់"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"ប៊ូតុងផ្អាក"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"ប៊ូតុងចាក់"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"ប៊ូតុងបញ្ឈប់"</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"បោះបង់"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"លុប"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"រួចរាល់"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ប្ដូររបៀប"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"ដោះសោ"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"ម៉ាស៊ីនថត"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"ស្ងាត់"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"បើកសំឡេង"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"ស្វែងរក"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"រុញឡើងលើដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"រុញចុះក្រោមសម្រាប់ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"រុញទៅឆ្វេងដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"រុញទៅស្ដាំដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
+ <string name="user_switched" msgid="3768006783166984410">"អ្នកប្រើបច្ចុប្បន្ន <xliff:g id="NAME">%1$s</xliff:g> ។"</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"ការហៅពេលអាសន្ន"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ភ្លេចលំនាំ"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"លំនាំមិនត្រឹមត្រូវ"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"ពាក្យសម្ងាត់មិនត្រឹមត្រូវ"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"កូដ PIN មិនត្រឹមត្រូវ"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"ព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER">%d</xliff:g> វិនាទី។"</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"គូរលំនាំរបស់អ្នក"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"បញ្ចូលកូដ PIN ស៊ីមកាត"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"បញ្ចូលកូដ PIN"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"បញ្ចូលពាក្យសម្ងាត់"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"ឥឡូវស៊ីមកាតត្រូវបានបិទ។ បញ្ចូលកូដ PUK ដើម្បីបន្ត។ ចំពោះព័ត៌មានលម្អិតទាក់ទងក្រុមហ៊ុនបញ្ជូនរបស់អ្នក។"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"បញ្ចូលកូដ PIN ដែលចង់បាន"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"បញ្ជាក់កូដ PIN ដែលចង់បាន"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"កំពុងដោះសោស៊ីមកាត..."</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"កូដ PIN មិនត្រឹមត្រូវ។"</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"បញ្ចូលកូដ PIN ដែលមានពី ៤ ដល់ ៨ លេខ។"</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"កូដ PUK គួរតែមាន ៨ លេខ ឬច្រើនជាងនេះ។"</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"បញ្ចូលកូដ PUK ម្ដងទៀត។ ការព្យាយាមដដែលច្រើនដឹងនឹងបិទស៊ីមកាតជាអចិន្ត្រៃយ៍។"</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"កូដ PIN មិនដូចគ្នា"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ព្យាយាមលំនាំច្រើនពេក"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"ដើម្បីដោះសោ ចូលក្នុងគណនី Google ។"</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"ឈ្មោះអ្នកប្រើ (អ៊ីម៉ែល)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"ពាក្យសម្ងាត់"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"ចូល"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"ឈ្មោះអ្នកប្រើ ឬពាក្យសម្ងាត់មិនត្រឹមត្រូវ។"</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ភ្លេចឈ្មោះអ្នកប្រើ ឬពាក្យសម្ងាត់របស់អ្នក?\nមើល "<b>"google.com/accounts/recovery"</b>" ។"</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"កំពុងពិនិត្យមើលគណនី..."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"អ្នកបានបញ្ចូលកូដ PIN របស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។\n\n ព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_1">%d</xliff:g> វិនាទី។"</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"អ្នកបានបញ្ចូលពាក្យសម្ងាត់មិនត្រឹមត្រូវ <xliff:g id="NUMBER_0">%d</xliff:g> ដង។\n\nព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_1">%d</xliff:g> វិនាទី។"</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។\n\nព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_1">%d</xliff:g> វិនាទី។"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"អ្នកបានព្យាយាមដោះសោកុំព្យូទ័របន្ទះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាមមិនជោគជ័យច្រើនជាង <xliff:g id="NUMBER_1">%d</xliff:g> ដង កុំព្យូទ័របន្ទះនឹងត្រូវបានកំណត់ទៅលំនាំដើមដូចចេញពីរោងចក្រ ហើយទិន្នន័យអ្នកប្រើនឹងបាត់បង់។"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"អ្នកបានព្យាយាមដោះសោទូរស័ព្ទមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាមមិនជោគជ័យច្រើនជាង <xliff:g id="NUMBER_1">%d</xliff:g> ដង ទូរស័ព្ទនឹងត្រូវបានកំណត់ទៅលំនាំដើមដូចចេញពីរោងចក្រ ហើយទិន្នន័យអ្នកប្រើនឹងបាត់បង់។"</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"អ្នកបានព្យាយាមដោះសោកុំព្យូទ័របន្ទះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង។ កុំព្យូទ័របន្ទះនឹងត្រូវបានកំណត់ទៅលំនាំដើមដូចចេញពីរោងចក្រ"</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"អ្នកបានព្យាយាមដោះសោទូរស័ព្ទមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង។ ឥឡូវទូរស័ព្ទនឹងកំណត់ទៅលំនាំដើមដូចចេញពីរោងចក្រ។"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"អ្នកបានគូរលំនាំដោះសោមិនត្រឹមត្រូវ <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងមិនជោគជ័យ អ្នកនឹងត្រូវបានស្នើឲ្យដោះសោកុំព្យូទ័របន្ទះរបស់អ្នក ដោយប្រើគណនីអ៊ីមែល។\n\n ព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_2">%d</xliff:g> វិនាទី។"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាមមិនជោគជ័យច្រើនជាង <xliff:g id="NUMBER_1">%d</xliff:g> ដង អ្នកនឹងត្រូវបានស្នើឲ្យដោះសោទូរស័ព្ទរបស់អ្នកដោយប្រើគណនីអ៊ីមែល។\n\n ព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_2">%d</xliff:g> វិនាទី។"</string>
+ <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"លុបចេញ"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"ប៊ូតុងបទមុន"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"ប៊ូតុងបទបន្ទាប់"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"ប៊ូតុងផ្អាក"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"ប៊ូតុងចាក់"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"ប៊ូតុងបញ្ឈប់"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"គ្មានសេវា។"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-lo-rLA/strings.xml b/packages/Keyguard/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..0dcb7d1
--- /dev/null
+++ b/packages/Keyguard/res/values-lo-rLA/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"ພິມລະຫັດ PIN"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"ພິມລະຫັດ PUK ແລະລະຫັດ PIN ອັນໃໝ່"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"ລະຫັດ PUK"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"ລະຫັດ PIN ໃໝ່"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"ແຕະເພື່ອພິມລະຫັດຜ່ານ"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"ພິມລະຫັດເພື່ອປົດລັອກ"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"ພິມລະຫັດ PIN ເພື່ອປົດລັອກ"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ລະຫັດ PIN ບໍ່ຖືກຕ້ອງ."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"ເພື່ອປົດລັອກ, ໃຫ້ກົດເມນູ ແລ້ວກົດ 0."</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"ຄວາມພະຍາຍາມປົດລັອກດ້ວຍໜ້ານັ້ນ ເກີນຈຳນວນທີ່ກຳນົດແລ້ວ"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"ສາກເຕັມແລ້ວ"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"ກຳລັງສາກ, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"ເຊື່ອມຕໍ່ອຸປະກອນສາກຂອງທ່ານ."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"ກົດເມນູເພື່ອປົດລັອກ."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"ເຄືອຂ່າຍຖືກລັອກ"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"ບໍ່ມີຊິມກາດ"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"ບໍ່ມີຊິມກາດໃນແທັບເລັດ."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"ບໍ່ມີຊິມກາດຢູ່ໃນໂທລະສັບ."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"ໃສ່ SIM card."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"ບໍ່ພົບເຫັນຊິມກາດ ຫຼືບໍ່ສາມາດອ່ານຊິມກາດໄດ້. ກະລຸນາໃສ່ຊິມກາດໃໝ່."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM card ບໍ່ສາມາດໃຊ້ໄດ້."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM card ຂອງທ່ານຖືກປິດການນຳໃຊ້ຢ່າງຖາວອນແລ້ວ.\n ຕິດຕໍ່ຜູ່ໃຫ້ບໍລິການລະບົບຂອງທ່ານເພື່ອຂໍ SIM card ໃໝ່."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"ຊິມກາດຖືກລັອກ."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"ຊິມກາດຖືກລັອກດ້ວຍລະຫັດ PUK."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"ກຳລັງປົດລັອກຊິມກາດ..."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. ວິດເຈັດ %2$d ຈາກທັງໝົດ %3$d."</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ເພີ່ມວິດເຈັດ"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ຫວ່າງເປົ່າ"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"ຂະຫຍາຍພື້ນທີ່ປົດລັອກແລ້ວ."</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"ຫຍໍ້ພື້ນທີ່ປົດລັອກແລ້ວ."</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ວິດເຈັດ."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ໂຕເລືອກຂອງຜູ່ໃຊ້"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"ສະຖານະ"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"ກ້ອງ"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"ການຄວບຄຸມສື່"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"ການຈັດຮຽງວິເຈັດໃໝ່ເລີ່ມຕົ້ນແລ້ວ."</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"ການຈັດຮຽງວິດເຈັດຄືນໃໝ່ສຳເລັດແລ້ວ."</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"ລຶບວິດເຈັດ <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ແລ້ວ."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ຂະຫຍາຍຂອບເຂດປົດລັອກ."</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"ການປົດລັອກດ້ວຍການເລື່ອນ."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"ປົດລັອກດ້ວຍຮູບແບບ."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ປົດລັອກດ້ວຍໜ້າ."</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"ປົດລັອກດ້ວຍ PIN."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"ການປົດລັອກດ້ວຍລະຫັດຜ່ານ."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"ພື້ນທີ່ຮູບແບບ."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"ເລື່ອນພື້ນທີ່."</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"ປຸ່ມເພງກ່ອນໜ້າ"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"ປຸ່ມເພງຕໍ່ໄປ"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"ປຸ່ມຢຸດຊົ່ວຄາວ"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"ປຸ່ມຫຼິ້ນ"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"ປຸ່ມຢຸດ"</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ຍົກເລີກ"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ລຶບ"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"ແລ້ວໆ"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ປ່ຽນຮູບແບບ"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"ປົດລັອກ"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"ກ້ອງ"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"ປິດສຽງ"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"ເປີດສຽງ"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"ຊອກຫາ"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"ເລື່ອນຂຶ້ນເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"ເລື່ອນລົງເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"ເລື່ອນໄປທາງຊ້າຍເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"ເລື່ອນໄປທາງຂວາເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="user_switched" msgid="3768006783166984410">"ຜູ່ໃຊ້ປັດຈຸບັນ <xliff:g id="NAME">%1$s</xliff:g> ."</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"ການໂທສຸກເສີນ"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ລືມຮູບແບບປົດລັອກ?"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"ຮູບແບບຜິດ"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"ລະຫັດຜ່ານບໍ່ຖືກຕ້ອງ"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"ລະຫັດ PIN ຜິດ"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"ລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER">%d</xliff:g> ວິນາທີ."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"ແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານ"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"ໃສ່ລະຫັດ PIN ຂອງຊິມ"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"ໃສ່ລະຫັດ PIN"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"ໃສ່ລະຫັດຜ່ານ"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"ຊິມຖືກປິດການນຳໃຊ້ແລ້ວ. ປ້ອນລະຫັດ PUK ເພື່ອດຳເນີນການຕໍ່. ຕິດຕໍ່ຜູ່ໃຫ້ບໍລິການສຳລັບລາຍລະອຽດ."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"ໃສ່ລະຫັດ PIN ທີ່ຕ້ອງການ."</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"ຢືນຢັນລະຫັດ PIN ທີ່ຕ້ອງການ"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"ປົດລັອກ SIM card..."</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"ລະຫັດ PIN ບໍ່ຖືກຕ້ອງ."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"ພິມລະຫັດ PIN ຄວາມຍາວ 4 ເຖິງ 8 ໂຕເລກ."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"ລະຫັດ PUK ຄວນມີຢ່າງໜ້ອຍ 8 ໂຕເລກ."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"ປ້ອນລະຫັດ PUK ທີ່ຖືກຕ້ອງຄືນໃໝ່. ການພະຍາຍາມໃສ່ຫຼາຍເທື່ອຈະເຮັດໃຫ້ຊິມກາດໃຊ້ບໍ່ໄດ້ຖາວອນ."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ລະຫັດ PIN ບໍ່ກົງກັນ"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ແຕ້ມຮູບແບບປົດລັອກຫຼາຍເກີນໄປ"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"ເພື່ອປົດລັອກ, ເຂົ້າສູ່ລະບົບດ້ວຍບັນຊີ Google ຂອງທ່ານ."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"ຊື່ຜູ່ໃຊ້ (ອີເມວ)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"ລະຫັດຜ່ານ"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"ເຂົ້າສູ່ລະບົບ"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"ຊື່ຜູ່ໃຊ້ ຫຼືລະຫັດຜ່ານບໍ່ຖືກຕ້ອງ."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ລືມຊື່ຜູ່ໃຊ້ ຫຼືລະຫັດຜ່ານຂອງທ່ານບໍ່?\nໄປທີ່ "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"ກຳລັງກວດສອບບັນຊີ..."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ທ່ານພິມລະຫັດ PIN ຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. \n\nກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ວິນາທີ."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"ທ່ານພິມລະຫັດຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. \n\nລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ວິນາທີ."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. \n\nກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ວິນາທີ."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"ທ່ານໄດ້ພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ສຳເລັດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກຄວາມພະຍາຍາມອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອ ແທັບເລັດຂອງທ່ານຈະຖືກຕັ້ງ ໃຫ້ກັບໄປໃຊ້ຄ່າເລີ່ມຕົ້ນຈາກໂຮງງານຄືນໃໝ່ ແລະຂໍ້ມູນຜູ່ໃຊ້ທັງໝົດຈະສູນຫາຍໄປ."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"ທ່ານໄດ້ພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ສຳເລັດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກຄວາມພະຍາຍາມອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອ ໂທລະສັບຂອງທ່ານຈະຖືກຕັ້ງ ໃຫ້ກັບໄປໃຊ້ຄ່າເລີ່ມຕົ້ນຈາກໂຮງງານຄືນໃໝ່ ແລະຂໍ້ມູນຜູ່ໃຊ້ທັງໝົດຈະສູນຫາຍໄປ."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"ທ່ານໄດ້ພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ສຳເລັດ <xliff:g id="NUMBER">%d</xliff:g> ເທື່ອແລ້ວ. ຕອນນີ້ແທັບເລັດຈະຖືກຕັ້ງໃຫ້ກັບໄປໃຊ້ຄ່າເລີ່ມຕົ້ນຈາກໂຮງງານ."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"ທ່ານໄດ້ພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກ <xliff:g id="NUMBER">%d</xliff:g> ເທື່ອແລ້ວ. ຕອນນີ້ໂທລະສັບຈະຖືກຣີເຊັດເປັນຄ່າຈາກໂຮງງານ."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກແທັບເລັດຂອງທ່ານ ດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ອີເມວຂອງທ່ານ.\n\n ກະລຸນາລອງໃໝ່ອີກຄັ້ງໃນອີກ <xliff:g id="NUMBER_2">%d</xliff:g> ວິນາທີ."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກຄວາມພະຍາຍາມອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອ ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກໂທລະສັບຂອງທ່ານດ້ວຍບັນຊີອີເມວ.\n\n ລອງໃໝ່ອີກຄັ້ງໃນ <xliff:g id="NUMBER_2">%d</xliff:g> ວິນາທີ."</string>
+ <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ລຶບອອກ"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"ປຸ່ມເພງກ່ອນໜ້າ"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"ປຸ່ມເພງຕໍ່ໄປ"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"ປຸ່ມຢຸດຊົ່ວຄາວ"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"ປຸ່ມຫຼິ້ນ"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"ປຸ່ມຢຸດ"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"ບໍ່ມີບໍລິການ"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-mn-rMN/strings.xml b/packages/Keyguard/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..4ae7220
--- /dev/null
+++ b/packages/Keyguard/res/values-mn-rMN/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN кодыг бичнэ үү"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK-г бичээд шинэ PIN код оруулна уу"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK код"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Шинэ PIN код"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Нууц үг бичих бол хүрнэ үү"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Тайлах нууц үгийг бичнэ үү"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Тайлах PIN-г оруулна уу"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Буруу PIN код."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"Тайлах бол Цэсийг дараад 0."</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Нүүрээр түгжээ тайлах оролдлогын тоо дээд хэмжээнээс хэтэрсэн"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Цэнэглэгдэв"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"Цэнэглэж байна, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"Цэнэглэгчээ холбоно уу."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Тайлх бол цэсийг дарна уу."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Сүлжээ түгжигдсэн"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"SIM карт байхгүй"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Таблет SIM картгүй."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Утсанд SIM карт байхгүй."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"SIM картыг оруулна уу."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM карт байхгүй эсвэл унших боломжгүй. SIM карт оруулна уу."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Ашиглаж болохгүй SIM карт."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Таны SIM карт бүрмөсөн идэвхгүй болов.\n Өөр SIM карт авах бол өөрийн утасгүй үйлчилгээний нийлүүлэгчтэй холбогдоно уу."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM карт түгжигдсэн."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM картны PUK-түгжигдсэн."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM картны түгжээг гаргаж байна…"</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d. -н %2$d виджет"</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Виджет нэмэх."</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Хоосон"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Тайлах хэсэг нээгдсэн."</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Тайлах хэсэг хаагдсан."</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> виджет."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Хэрэглэгч сонгоч"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Статус"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камер"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Медиа контрол"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Виджет дахин эрэмбэлж эхлэв."</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Виджетийг дахин эрэмбэлж дуусав."</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> виджет устсан."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Түгжээгүй хэсгийг өргөсгөх."</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Тайлах гулсуулалт."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Тайлах хээ."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Нүүрээр тайлах"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Тайлах пин."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Тайлах нууц үг."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Хээний хэсэг."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Гулсуулах хэсэг."</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Өмнөх бичлэг товч"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Дараагийн бичлэг товч"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Түр зогсоох товч"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Тоглуулах товч"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Зогсоох товч"</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"АБВ"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Цуцлах"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Устгах"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Дуусгах"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Горим өөрчлөх"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Шифт"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Оруулах"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"Тайлах"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"Камер"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"Чимээгүй"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"Дуунууд идэвхтэй"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Хайх"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-г гулсуулах."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> хийх бол доош гулсуулах."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> хийх зүүнлүү гулсуулах."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> хийх бол баруунлуу гулсуулах."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Одоогийн хэрэглэгч <xliff:g id="NAME">%1$s</xliff:g>."</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"Яаралтай дуудлага"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Хээг мартсан"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Буруу хээ"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Нууц үг буруу"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN буруу"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Хээг зурах"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN оруулна уу"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN оруулна уу"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Нууц үгээ оруулна уу"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM идэвхгүй байна. Үргэлжлүүлэх бол PUK кодыг оруулна уу. Дэлгэрэнгүй мэдээллийг оператороос асууна ууу"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Хүссэн PIN кодоо оруулна уу"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Хүссэн PIN кодоо дахин оруулна уу"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM картны түгжээг гаргаж байна…"</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Буруу PIN код."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4-8 тооноос бүтэх PIN-г бичнэ үү."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK код 8-с цөөнгүй тооноос бүтнэ."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Зөв PUK кодыг дахин оруулна уу. Давтан оролдвол SIM нь бүрмөсөн идэвхгүй болгоно."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодууд таарахгүй байна"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Хээ оруулах оролдлого хэт олон"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"Түгжээг тайлах бол Google акаунтаараа нэвтэрнэ үү."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Хэрэглэгчийн нэр (имэйл)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"Нууц үг"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Нэвтрэх"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"Хэрэглэгчийн нэр эсвэл нууц үг буруу."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Хэрэглэгчийн нэр нууц үгээ мартсан уу?\n"<b>"google.com/accounts/recovery"</b>"-д зочилно уу."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"Акаунт шалгаж байна…"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Та PIN кодоо <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Та PIN кодоо <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Та тайлах хээг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу зурлаа. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Та таблетыг тайлах гэж <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу оролдлоо. <xliff:g id="NUMBER_1">%d</xliff:g> удаа дахин буруу оролдвол таблет үйлдвэрийн үндсэн утгаараа тохируулагдах ба хэрэглэгчийн дата бүхэлдээ устана."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Та утсыг тайлах гэж <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу оролдлоо. <xliff:g id="NUMBER_1">%d</xliff:g> удаа дахин буруу оролдвол утас үйлдвэрийн үндсэн утгаараа тохируулагдах ба хэрэглэгчийн дата бүхэлдээ устана."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Та таблетыг тайлах гэж <xliff:g id="NUMBER">%d</xliff:g> удаа буруу оролдлоо. Таблет одоо үйлдвэрийн үндсэн утгаараа тохируулагдах болно."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Та утсыг тайлах гэж <xliff:g id="NUMBER">%d</xliff:g> удаа буруу оролдлоо. Утас одоо үйлдвэрийн үндсэн утгаараа тохируулагдах болно."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Та тайлах хээг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%d</xliff:g> удаа дахин буруу оруулбал, та таблетаа тайлахын тулд имэйл акаунт шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Та тайлах хээг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%d</xliff:g> удаа дахин буруу оруулбал, та утсаа тайлахын тулд имэйл акаунтаа ашиглах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+ <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Устгах"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Өмнөх дуу товч"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Дараагийн дуу товч"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Түр зогсох товч"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Тоглуулах товч"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Зогсоох товч"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"Үйлчилгээ байхгүй."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ms-rMY/strings.xml b/packages/Keyguard/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..0aeeeb5
--- /dev/null
+++ b/packages/Keyguard/res/values-ms-rMY/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Taip kod PIN"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Taip PUK dan kod PIN baharu"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Kod PUK"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Kod PIN Baharu"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Sentuh untuk menaip kata laluan"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Taip kata laluan untuk membuka kunci"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Taip PIN untuk membuka kunci"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Kod PIN salah."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"Untuk membuka kunci, tekan Menu, kemudian 0."</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Telah melepasi had cubaan Buka Kunci Wajah"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Sudah dicas"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"Mengecas, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"Sambungkan pengecas anda."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Tekan Menu untuk membuka kunci."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Rangkaian dikunci"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Tiada kad SIM"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Tiada kad SIM dalam tablet."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Tiada kad SIM dalam telefon."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Masukkan kad SIM."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Kad SIM tiada atau tidak boleh dibaca. Sila masukkan kad SIM."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Kad SIM tidak boleh digunakan."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Kad SIM anda telah dilumpuhkan secara kekal.\n Hubungi pembekal perkhidmatan wayarles anda untuk mendapatkan kad SIM lain."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Kad SIM dikunci."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Kad SIM dikunci dengan PUK."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Membuka kunci kad SIM..."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d dari %3$d."</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Tambah widget."</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Kosong"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Bahagian buka kunci dikembangkan."</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Bahagian buka kunci diruntuhkan."</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Pemilih pengguna"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Kawalan media"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Penyusunan semula widget dimulakan."</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Penyusunan semula widget tamat."</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> dipadamkan."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Kembangkan bahagian buka kunci."</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Buka kunci luncur."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Buka kunci corak."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Wajah Buka Kunci"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Buka kunci pin."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Buka kunci kata laluan."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Kawasan corak."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Kawasan luncur."</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Butang lagu sebelumnya"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Butang lagu seterusnya"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Butang jeda"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Butang main"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Butang berhenti"</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Batal"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Padam"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Selesai"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Perubahan mod"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Masuk"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"Buka kunci"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"Senyap"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"Bunyi dihidupkan"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Carian"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"Luncurkan ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Luncurkan ke bawah untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Luncurkan ke kiri untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Luncurkan ke kanan untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Pengguna semasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"Panggilan kecemasan"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Lupa Corak"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Corak Salah"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Kata Laluan Salah"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN salah"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Cuba lagi dalam <xliff:g id="NUMBER">%d</xliff:g> saat."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Lukiskan corak anda"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Masukkan PIN SIM"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"Masukkan PIN"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Masukkan Kata Laluan"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Kini SIM dilumpuhkan. Masukkan kod PUK untuk meneruskan. Hubungi pembawa untuk butiran."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Masukkan kod PIN yang diingini"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Sahkan kod PIN yang diingini"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Membuka kunci kad SIM..."</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Kod PIN salah."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Taipkan PIN yang mengandungi 4 hingga 8 nombor."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Kod PUK mestilah 8 nombor atau lebih."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan semula kod PIN yang betul. Percubaan berulang akan melumpuhkan SIM secara kekal."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kod PIN tidak sepadan"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak percubaan melukis corak"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"Untuk membuka kunci, log masuk dengan akaun Google anda."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Nama Pengguna (E-mel)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"Kata laluan"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Log masuk"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nama pengguna atau kata laluan tidak sah."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau kata laluan anda?\nLawati"<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"Menyemak akaun…"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah menaip PIN anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah menaip kata laluan anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah tersilap melukis corak buka kunci anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Anda telah mencuba untuk membuka kunci tablet dengan salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, tablet akan ditetapkan semula kepada tetapan lalai kilang dan semua data pengguna akan hilang."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Anda telah mencuba untuk membuka kunci telefon dengan salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, telefon akan ditetapkan semula kepada tetapan lalai kilang dan semua data pengguna akan hilang."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Anda telah mencuba untuk membuka kunci tablet secara salah sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Tablet kini akan ditetapkan semula ke tetapan lalai kilang."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Anda telah mencuba untuk membuka kunci telefon secara salah sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Telefon kini akan ditetapkan semula ke tetapan lalai kilang."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
+ <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alih keluar"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Butang lagu sebelumnya"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Butang lagu seterusnya"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Butang jeda"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Butang main"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Butang berhenti"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"Tiada perkhidmatan."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
index 664b85e..937d029 100644
--- a/packages/Keyguard/res/values-sr/strings.xml
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -134,5 +134,5 @@
<string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Дугме за паузу"</string>
<string name="keyguard_transport_play_description" msgid="2924628863741150956">"Дугме за репродукцију"</string>
<string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Дугме за заустављање"</string>
- <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ван мреже сте."</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"Офлајн сте."</string>
</resources>
diff --git a/packages/Keyguard/res/values-zh-rHK/strings.xml b/packages/Keyguard/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..49953c0
--- /dev/null
+++ b/packages/Keyguard/res/values-zh-rHK/strings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"輸入 PIN 碼"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"輸入 PUK 碼和新 PIN 碼"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK 碼"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"新 PIN 碼"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"輕觸即可輸入密碼"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"輸入密碼即可解鎖"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"輸入 PIN 碼即可解鎖"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN 碼不正確。"</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"如要解鎖,請按選單鍵,然後按 0。"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"已超過臉容解鎖嘗試次數上限"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"充電完成"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"充電中 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"請連接充電器。"</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"按選單鍵解鎖。"</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"網絡已鎖定"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"找不到 SIM 卡"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"平板電腦中沒有 SIM 卡。"</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"手機中沒有 SIM 卡。"</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"請插入 SIM 卡。"</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"找不到 SIM 卡或無法讀取 SIM 卡,請插入 SIM 卡。"</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM 卡無法使用。"</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"您的 SIM 卡已被永久停用。\n請與您的無線服務供應商聯絡,以取得另一張 SIM 卡。"</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM 卡處於鎖定狀態。"</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM 卡處於 PUK 鎖定狀態。"</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"正在解開上鎖的 SIM 卡..."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。第 %2$d 個小工具,共 %3$d 個。"</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"新增小工具。"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"空白"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"解鎖區域已展開。"</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"解鎖區域已收合。"</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小工具。"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"用戶選取工具"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"狀態"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"相機"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"媒體控制"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"已開始為小工具重新排列次序。"</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"已完成為小工具重新排列次序。"</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小工具已刪除。"</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"展開解鎖區域。"</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"滑動解鎖。"</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"圖案解鎖。"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"臉容解鎖。"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN 解鎖。"</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"密碼解鎖。"</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"圖案區域。"</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"滑動區域。"</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"[上一首曲目] 按鈕"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"[下一首曲目] 按鈕"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"[暫停] 按鈕"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"[播放] 按鈕"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"[停止] 按鈕"</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"取消"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"刪除"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"完成"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"模式更改"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift 鍵"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter 鍵"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"解鎖"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"相機"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"靜音"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"音效已開啟"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"搜尋"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"向下滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"向左滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"向右滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+ <string name="user_switched" msgid="3768006783166984410">"目前的用戶是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"緊急電話"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘記圖案"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"圖案錯誤"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"密碼錯誤"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN 錯誤"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"請在 <xliff:g id="NUMBER">%d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"畫出圖案"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"輸入 SIM 卡 PIN 碼"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"輸入 PIN 碼"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"輸入密碼"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM 卡現已停用,請輸入 PUK 碼以繼續。詳情請與流動網絡供應商聯絡。"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"輸入所需的 PIN 碼"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"確認所需的 PIN 碼"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解開上鎖的 SIM 卡..."</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 碼不正確。"</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"請輸入一個 4 至 8 位數的 PIN 碼。"</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK 碼應由 8 個或以上數字組成。"</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"請重新輸入正確的 PUK 碼。如果嘗試輸入的次數過多,SIM 卡將永久停用。"</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 碼不符"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"圖案嘗試次數過多"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"如要解鎖,請以 Google 帳戶登入。"</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"用戶名稱 (電子郵件)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"密碼"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"登入"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"無效的用戶名稱或密碼。"</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘記用戶名稱或密碼?\n請瀏覽 "<b>"google.com/accounts/recovery"</b>"。"</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"正在檢查帳戶…"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已輸入錯誤的 PIN 碼 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"您已輸入錯誤的密碼 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"您嘗試了 <xliff:g id="NUMBER_0">%d</xliff:g> 次仍未能成功解開這部上鎖的平板電腦。如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,平板電腦將回復原廠設定,所有用戶資料均會失去。"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"您嘗試了 <xliff:g id="NUMBER_0">%d</xliff:g> 次仍未能成功解開這部上鎖的手機。如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,手機將回復原廠設定,所有用戶資料均會失去。"</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"您嘗試了 <xliff:g id="NUMBER">%d</xliff:g> 次仍未能成功解開這部上鎖的平板電腦。平板電腦現在將回復原廠設定。"</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"您嘗試了 <xliff:g id="NUMBER">%d</xliff:g> 次仍未能成功解開這部上鎖的手機。手機現在將回復原廠設定。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的手機。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"移除"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"[上一首曲目] 按鈕"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"[下一首曲目] 按鈕"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"[暫停] 按鈕"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"[播放] 按鈕"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"[停止] 按鈕"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"沒有服務。"</string>
+</resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 6badaaf..8cdcb7a 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -102,6 +102,8 @@
== TelephonyManager.CALL_STATE_OFFHOOK) {
mLockPatternUtils.resumeCall();
} else {
+ final boolean bypassHandler = true;
+ KeyguardUpdateMonitor.getInstance(mContext).reportEmergencyCallAction(bypassHandler);
Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
index 3e499b2..c2cd32f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
@@ -295,6 +295,13 @@
}
}
}
+
+ @Override
+ public void onEmergencyCallAction() {
+ if (mBiometricUnlock != null) {
+ mBiometricUnlock.stop();
+ }
+ }
};
@Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index 40a1af6..fbe3a9c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -49,9 +49,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.speech.hotword.HotwordRecognitionListener;
-import android.speech.hotword.HotwordRecognitionService;
-import android.speech.hotword.HotwordRecognizer;
import android.telephony.TelephonyManager;
import android.util.AttributeSet;
import android.util.Log;
@@ -69,10 +66,6 @@
public class KeyguardHostView extends KeyguardViewBase {
private static final String TAG = "KeyguardHostView";
- // Don't enable hotword on limited-memory devices.
- private static final boolean ENABLE_HOTWORD = !ActivityManager.isLowRamDeviceStatic();
- // Indicates if hotword is enabled, should it also be available on secure keyguard(s).
- private static final boolean ENABLE_HOTWORD_SECURE = false;
// Transport control states.
static final int TRANSPORT_GONE = 0;
@@ -88,13 +81,6 @@
// Found in KeyguardAppWidgetPickActivity.java
static final int APPWIDGET_HOST_ID = 0x4B455947;
- // TODO: Fix this to be non-static.
- // We need to be careful here to make stopRecognition calls on the same instance
- // that started it. Since KeyguardHostView is a view, it keeps getting
- // recreated every now and then, and unless we figure out a better way,
- // this needs to be a static field.
- private static HotwordRecognizer sHotwordClient;
-
private final int MAX_WIDGETS = 5;
private AppWidgetHost mAppWidgetHost;
@@ -218,11 +204,6 @@
if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0) {
Log.v(TAG, "Keyguard secure camera disabled by DPM");
}
-
- // Create Hotword recognizer, for the first time.
- if (ENABLE_HOTWORD && sHotwordClient == null) {
- sHotwordClient = HotwordRecognizer.createHotwordRecognizer(getContext());
- }
}
private void getInitialTransportState() {
@@ -320,21 +301,6 @@
}
}
}
- @Override
- public void onPhoneStateChanged(int phoneState) {
- // We need to stop hotword detection when a call state is not idle anymore.
- if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)
- && TelephonyManager.CALL_STATE_IDLE != phoneState) {
- if (DEBUG) Log.d(TAG, "Stopping due to call state not being idle");
- maybeStopHotwordDetector();
- }
- }
- @Override
- public void onUserSwitching(int userId) {
- if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) {
- maybeStopHotwordDetector();
- }
- }
};
private static final boolean isMusicPlaying(int playbackState) {
@@ -818,9 +784,6 @@
// If the alternate unlock was suppressed, it can now be safely
// enabled because the user has left keyguard.
KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
- if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)){
- maybeStopHotwordDetector();
- }
// If there's a pending runnable because the user interacted with a widget
// and we're leaving keyguard, then run it.
@@ -985,9 +948,6 @@
// Emulate Activity life cycle
if (oldView != null) {
- if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) {
- maybeStopHotwordDetector();
- }
oldView.onPause();
oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
}
@@ -1041,11 +1001,6 @@
mViewStateManager.showUsabilityHints();
}
- // Start hotword detection on insecure Keyguard.
- if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) {
- maybeStartHotwordDetector();
- }
-
requestFocus();
}
@@ -1068,11 +1023,6 @@
cameraPage.onScreenTurnedOff();
}
- // Stop hotword detection on insecure Keyguard.
- if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) {
- maybeStopHotwordDetector();
- }
-
clearFocus();
}
@@ -1157,9 +1107,6 @@
new CameraWidgetFrame.Callbacks() {
@Override
public void onLaunchingCamera() {
- if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) {
- maybeStopHotwordDetector();
- }
setSliderHandleAlpha(0);
}
@@ -1689,9 +1636,6 @@
}
public void showAssistant() {
- if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) {
- maybeStopHotwordDetector();
- }
final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
.getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
@@ -1706,125 +1650,4 @@
mActivityLauncher.launchActivityWithAnimation(
intent, false, opts.toBundle(), null, null);
}
-
-
- /**
- * Start the hotword detector if:
- * <li> ENABLE_HOTWORD is true and
- * <li> Hotword detection is not already running and
- * <li> TelephonyManager is in CALL_STATE_IDLE
- * <li> and Screen is turned on.
- */
- private void maybeStartHotwordDetector() {
- if (!ENABLE_HOTWORD) return;
-
- if (sHotwordClient != null) {
- if (DEBUG) Log.d(TAG, "maybeStartHotwordDetector()");
- // Don't start hotword detection if the screen is off.
- if (!mIsScreenOn) {
- if (DEBUG) Log.d(TAG, "screen was off, not starting");
- return;
- }
-
- KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(getContext());
- if (monitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE) {
- if (DEBUG) Log.d(TAG, "Call underway, not starting");
- return;
- }
-
- try {
- sHotwordClient.startRecognition(mHotwordCallback);
- } catch(Exception ex) {
- // Don't allow hotword errors to make the keyguard unusable
- Log.e(TAG, "Failed to start hotword recognition", ex);
- sHotwordClient = null;
- }
- }
- }
-
- /**
- * Stop hotword detector if:
- * <li> ENABLE_HOTWORD is true
- * <li> and hotword is running.
- */
- private void maybeStopHotwordDetector() {
- if (!ENABLE_HOTWORD) return;
-
- if (sHotwordClient != null) {
- if (DEBUG) Log.d(TAG, "maybeStopHotwordDetector()");
- try {
- sHotwordClient.stopRecognition();
- } catch(Exception ex) {
- // Don't allow hotword errors to make the keyguard unusable
- Log.e(TAG, "Failed to start hotword recognition", ex);
- } finally {
- sHotwordClient = null;
- }
- }
- }
-
- private final HotwordRecognitionListener mHotwordCallback = new HotwordRecognitionListener() {
- private static final String TAG = "HotwordRecognitionListener";
-
- public void onHotwordRecognitionStarted() {
- if (DEBUG) Log.d(TAG, "onHotwordRecognitionStarted()");
- }
-
- public void onHotwordRecognitionStopped() {
- if (DEBUG) Log.d(TAG, "onHotwordRecognitionStopped()");
- }
-
- public void onHotwordEvent(int eventType, Bundle eventBundle) {
- if (DEBUG) Log.d(TAG, "onHotwordEvent: " + eventType);
- if (eventType == HotwordRecognitionService.EVENT_TYPE_PROMPT_CHANGED) {
- if (eventBundle != null
- && eventBundle.containsKey(HotwordRecognitionService.KEY_PROMPT_TEXT)) {
- new KeyguardMessageArea
- .Helper((View) getSecurityView(mCurrentSecuritySelection))
- .setMessage(eventBundle.getString(
- HotwordRecognitionService.KEY_PROMPT_TEXT),true);
- }
- }
- }
-
- public void onHotwordRecognized(final Intent intent) {
- if (DEBUG) Log.d(TAG, "onHotwordRecognized");
- maybeStopHotwordDetector();
- // See if an activity can handle this intent.
- if (getContext().getPackageManager().resolveActivity(intent, 0) == null)
- return;
- if (SecurityMode.None == mCurrentSecuritySelection) {
- if (intent != null) {
- mActivityLauncher.launchActivity(intent, true, true, null, null);
- }
- mCallback.userActivity(0);
- } else if (ENABLE_HOTWORD_SECURE && mLockPatternUtils.isSecure()) {
- setOnDismissAction(new OnDismissAction() {
- @Override
- public boolean onDismiss() {
- if (intent != null) {
- mActivityLauncher.launchActivity(intent, true, true, null, null);
- }
- return false;
- }
- });
- getSecurityView(mCurrentSecuritySelection).showBouncer(0);
- }
- }
-
- public void onHotwordError(int errorCode) {
- if (DEBUG) Log.d(TAG, "onHotwordError: " + errorCode);
- // TODO: Inspect the error code and handle the errors appropriately
- // instead of blindly failing.
- maybeStopHotwordDetector();
- }
- };
-
- private boolean shouldRunHotwordInSecurityMode(SecurityMode mode) {
- // Enable hotoword for insecure keyguard,
- // and for pattern unlock if ENABLE_HOTWORD_SECURE is true.
- return ENABLE_HOTWORD
- && ((SecurityMode.None == mode)
- || (ENABLE_HOTWORD_SECURE && mLockPatternUtils.isSecure()));
- }
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index dcec654..f4bbf9a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -91,6 +91,7 @@
private static final int MSG_SET_CURRENT_CLIENT_ID = 315;
protected static final int MSG_SET_PLAYBACK_STATE = 316;
protected static final int MSG_USER_INFO_CHANGED = 317;
+ protected static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318;
private static KeyguardUpdateMonitor sInstance;
@@ -181,6 +182,9 @@
case MSG_USER_INFO_CHANGED:
handleUserInfoChanged(msg.arg1);
break;
+ case MSG_REPORT_EMERGENCY_CALL_ACTION:
+ handleReportEmergencyCallAction();
+ break;
}
}
};
@@ -758,6 +762,18 @@
}
}
+ /**
+ * Handle {@link #MSG_REPORT_EMERGENCY_CALL_ACTION}
+ */
+ private void handleReportEmergencyCallAction() {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onEmergencyCallAction();
+ }
+ }
+ }
+
public boolean isKeyguardVisible() {
return mKeyguardIsVisible;
}
@@ -902,6 +918,22 @@
handleSimStateChange(new SimArgs(IccCardConstants.State.READY));
}
+ /**
+ * Report that the emergency call button has been pressed and the emergency dialer is
+ * about to be displayed.
+ *
+ * @param bypassHandler runs immediately.
+ *
+ * NOTE: Must be called from UI thread if bypassHandler == true.
+ */
+ public void reportEmergencyCallAction(boolean bypassHandler) {
+ if (!bypassHandler) {
+ mHandler.obtainMessage(MSG_REPORT_EMERGENCY_CALL_ACTION).sendToTarget();
+ } else {
+ handleReportEmergencyCallAction();
+ }
+ }
+
public CharSequence getTelephonyPlmn() {
return mTelephonyPlmn;
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 30b43f5..b0511e5 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -131,4 +131,8 @@
*/
public void onMusicPlaybackStateChanged(int playbackState, long eventTime) { }
+ /**
+ * Called when the emergency call button is pressed.
+ */
+ void onEmergencyCallAction() { }
}
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 83ec1ad..1e6954e 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -22,22 +22,29 @@
android:versionCode="1">
<!-- Allows an application to call APIs that give it access to all print jobs
- on the device. Usually an app can access only the print jobs it created.
- -->
+ on the device. Usually an app can access only the print jobs it created. -->
<permission
android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"
android:label="@string/permlab_accessAllPrintJobs"
android:description="@string/permdesc_accessAllPrintJobs"
android:protectionLevel="signature" />
+ <!-- May be required by the settings and add printer activities of a
+ print service if the developer wants only trusted system code to
+ be able to launch these activities. -->
+ <permission android:name="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
+ android:label="@string/permlab_startPrintServiceConfigActivity"
+ android:description="@string/permdesc_startPrintServiceConfigActivity"
+ android:protectionLevel="signature" />
+
<uses-permission android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"/>
- <uses-permission android:name="android.permission.ACCESS_ALL_PRINT_JOBS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
+ <uses-permission android:name="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"/>
<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="18"/>
<application
- android:allowClearUserData="false"
+ android:allowClearUserData="true"
android:label="@string/app_label"
android:allowBackup= "false"
android:supportsRtl="true">
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 235a7a1..543c425 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -139,10 +139,20 @@
<!-- Title of an application permission, listed so the user can choose whether they want
to allow the application to do this. -->
- <string name="permlab_accessAllPrintJobs">access all print jobs</string>
+ <string name="permlab_accessAllPrintJobs" translatable="false">access all print jobs</string>
<!-- Description of an application permission, listed so the user can choose whether
they want to allow the application to do this. -->
- <string name="permdesc_accessAllPrintJobs">Allows the holder to access print jobs
- created by another app. Should never be needed for normal apps.</string>
+ <string name="permdesc_accessAllPrintJobs" translatable="false">Allows the holder to access
+ print jobs created by another app. Should never be needed for normal apps.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want
+ to allow the application to do this. -->
+ <string name="permlab_startPrintServiceConfigActivity" translatable="false">start print
+ service configuration activities</string>
+ <!-- Description of an application permission, listed so the user can choose whether they
+ want to allow the application to do this. -->
+ <string name="permdesc_startPrintServiceConfigActivity" translatable="false">Allows the
+ holder to start the configuration activities of a print service. Should never be needed
+ for normal apps.</string>
</resources>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
index 7d6ca56..0431b94 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
@@ -57,7 +57,7 @@
public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
private static final String LOG_TAG = "FusedPrintersProvider";
- private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+ private static final boolean DEBUG = false;
private static final double WEIGHT_DECAY_COEFFICIENT = 0.95f;
@@ -455,7 +455,7 @@
PrinterInfo.Builder builder = new PrinterInfo.Builder(printerId, name, status);
builder.setDescription(description);
- PrinterInfo printer = builder.create();
+ PrinterInfo printer = builder.build();
outPrinters.add(printer);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
index 43a751c..829fb06 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
@@ -23,13 +23,13 @@
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.print.IPrintManager;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.text.TextUtils;
@@ -40,12 +40,13 @@
* based on print job state transitions.
*/
public class NotificationController {
- public static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+ public static final boolean DEBUG = false;
public static final String LOG_TAG = "NotificationController";
private static final String INTENT_ACTION_CANCEL_PRINTJOB = "INTENT_ACTION_CANCEL_PRINTJOB";
private static final String INTENT_ACTION_RESTART_PRINTJOB = "INTENT_ACTION_RESTART_PRINTJOB";
+
private static final String INTENT_EXTRA_PRINTJOB_ID = "INTENT_EXTRA_PRINTJOB_ID";
private static final String INTENT_EXTRA_PRINTJOB_LABEL = "INTENT_EXTRA_PRINTJOB_LABEL";
private static final String INTENT_EXTRA_PRINTER_NAME = "INTENT_EXTRA_PRINTER_NAME";
@@ -61,8 +62,9 @@
public void onPrintJobStateChanged(PrintJobInfo printJob) {
if (DEBUG) {
- Log.i(LOG_TAG, "onPrintJobStateChanged() printJobId: " + printJob.getId()
- + " state:" + PrintJobInfo.stateToString(printJob.getState()));
+ Log.i(LOG_TAG, "onPrintJobStateChanged() printJobId: "
+ + printJob.getId().flattenToString() + " state:"
+ + PrintJobInfo.stateToString(printJob.getState()));
}
switch (printJob.getState()) {
case PrintJobInfo.STATE_QUEUED:
@@ -96,7 +98,7 @@
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- mNotificationManager.notify(printJob.getId(), builder.build());
+ mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
}
private void createFailedNotification(PrintJobInfo printJob) {
@@ -115,7 +117,7 @@
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- mNotificationManager.notify(printJob.getId(), builder.build());
+ mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
}
private void createBlockedNotification(PrintJobInfo printJob) {
@@ -132,25 +134,25 @@
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- mNotificationManager.notify(printJob.getId(), builder.build());
+ mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
}
- private void removeNotification(int printJobId) {
- mNotificationManager.cancel(printJobId);
+ private void removeNotification(PrintJobId printJobId) {
+ mNotificationManager.cancel(printJobId.flattenToString(), 0);
}
private PendingIntent createCancelIntent(PrintJobInfo printJob) {
Intent intent = new Intent(mContext, NotificationBroadcastReceiver.class);
- intent.setAction(INTENT_ACTION_CANCEL_PRINTJOB + "_" + String.valueOf(printJob.getId()));
+ intent.setAction(INTENT_ACTION_CANCEL_PRINTJOB + "_" + printJob.getId().flattenToString());
intent.putExtra(INTENT_EXTRA_PRINTJOB_ID, printJob.getId());
intent.putExtra(INTENT_EXTRA_PRINTJOB_LABEL, printJob.getLabel());
intent.putExtra(INTENT_EXTRA_PRINTER_NAME, printJob.getPrinterName());
return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
}
- private PendingIntent createRestartIntent(int printJobId) {
+ private PendingIntent createRestartIntent(PrintJobId printJobId) {
Intent intent = new Intent(mContext, NotificationBroadcastReceiver.class);
- intent.setAction(INTENT_ACTION_RESTART_PRINTJOB + "_" + String.valueOf(printJobId));
+ intent.setAction(INTENT_ACTION_RESTART_PRINTJOB + "_" + printJobId.flattenToString());
intent.putExtra(INTENT_EXTRA_PRINTJOB_ID, printJobId);
return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
}
@@ -162,17 +164,17 @@
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null && action.startsWith(INTENT_ACTION_CANCEL_PRINTJOB)) {
- final int printJobId = intent.getExtras().getInt(INTENT_EXTRA_PRINTJOB_ID);
+ PrintJobId printJobId = intent.getExtras().getParcelable(INTENT_EXTRA_PRINTJOB_ID);
String printJobLabel = intent.getExtras().getString(INTENT_EXTRA_PRINTJOB_LABEL);
String printerName = intent.getExtras().getString(INTENT_EXTRA_PRINTER_NAME);
handleCancelPrintJob(context, printJobId, printJobLabel, printerName);
} else if (action != null && action.startsWith(INTENT_ACTION_RESTART_PRINTJOB)) {
- final int printJobId = intent.getExtras().getInt(INTENT_EXTRA_PRINTJOB_ID);
+ PrintJobId printJobId = intent.getExtras().getParcelable(INTENT_EXTRA_PRINTJOB_ID);
handleRestartPrintJob(context, printJobId);
}
}
- private void handleCancelPrintJob(final Context context, final int printJobId,
+ private void handleCancelPrintJob(final Context context, final PrintJobId printJobId,
final String printJobLabel, final String printerName) {
if (DEBUG) {
Log.i(LOG_TAG, "handleCancelPrintJob() printJobId:" + printJobId);
@@ -190,7 +192,7 @@
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- notificationManager.notify(printJobId, builder.build());
+ notificationManager.notify(printJobId.flattenToString(), 0, builder.build());
// Call into the print manager service off the main thread since
// the print manager service may end up binding to the print spooler
@@ -226,7 +228,7 @@
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
}
- private void handleRestartPrintJob(final Context context, final int printJobId) {
+ private void handleRestartPrintJob(final Context context, final PrintJobId printJobId) {
if (DEBUG) {
Log.i(LOG_TAG, "handleRestartPrintJob() printJobId:" + printJobId);
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 1040edf..8ab4645 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -42,10 +42,12 @@
import android.print.IWriteResultCallback;
import android.print.PageRange;
import android.print.PrintAttributes;
+import android.print.PrintAttributes.Margins;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
import android.print.PrintDocumentAdapter;
import android.print.PrintDocumentInfo;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrinterCapabilitiesInfo;
@@ -61,9 +63,11 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
+import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
@@ -101,8 +105,7 @@
private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
public static final String EXTRA_PRINT_DOCUMENT_ADAPTER = "printDocumentAdapter";
- public static final String EXTRA_PRINT_ATTRIBUTES = "printAttributes";
- public static final String EXTRA_PRINT_JOB_ID = "printJobId";
+ public static final String EXTRA_PRINT_JOB = "printJob";
public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
@@ -146,9 +149,8 @@
public static final PageRange[] ALL_PAGES_ARRAY = new PageRange[] {PageRange.ALL_PAGES};
- private final PrintAttributes mOldPrintAttributes = new PrintAttributes.Builder().create();
- private final PrintAttributes mCurrPrintAttributes = new PrintAttributes.Builder().create();
- private final PrintAttributes mTempPrintAttributes = new PrintAttributes.Builder().create();
+ private final PrintAttributes mOldPrintAttributes = new PrintAttributes.Builder().build();
+ private final PrintAttributes mCurrPrintAttributes = new PrintAttributes.Builder().build();
private final DeathRecipient mDeathRecipient = new DeathRecipient() {
@Override
@@ -161,7 +163,7 @@
private Document mDocument;
private PrintController mController;
- private int mPrintJobId;
+ private PrintJobId mPrintJobId;
private IBinder mIPrintDocumentAdapter;
@@ -173,17 +175,18 @@
Bundle extras = getIntent().getExtras();
- mPrintJobId = extras.getInt(EXTRA_PRINT_JOB_ID, -1);
- if (mPrintJobId < 0) {
- throw new IllegalArgumentException("Invalid print job id: " + mPrintJobId);
+ PrintJobInfo printJob = extras.getParcelable(EXTRA_PRINT_JOB);
+ if (printJob == null) {
+ throw new IllegalArgumentException("printJob cannot be null");
}
+ mPrintJobId = printJob.getId();
mIPrintDocumentAdapter = extras.getBinder(EXTRA_PRINT_DOCUMENT_ADAPTER);
if (mIPrintDocumentAdapter == null) {
throw new IllegalArgumentException("PrintDocumentAdapter cannot be null");
}
- PrintAttributes attributes = getIntent().getParcelableExtra(EXTRA_PRINT_ATTRIBUTES);
+ PrintAttributes attributes = printJob.getAttributes();
if (attributes != null) {
mCurrPrintAttributes.copyFrom(attributes);
}
@@ -341,7 +344,11 @@
if (!mController.hasStarted()) {
mController.start();
}
- if (!printAttributesChanged() && mDocument.info != null) {
+ if (!printAttributesChanged()) {
+ if (mDocument.info == null) {
+ // We are waiting for the result of a layout, so do nothing.
+ return;
+ }
// If the attributes didn't change and we have done a layout, then
// we do not do a layout but may have to ask the app to write some
// pages. Hence, pretend layout completed and nothing changed, so
@@ -407,12 +414,25 @@
// write anything and wait for the user to fix the range which will
// trigger an update.
mRequestedPages = mEditor.getRequestedPages();
- if (mRequestedPages == null) {
+ if (mRequestedPages == null || mRequestedPages.length == 0) {
mEditor.updateUi();
if (mEditor.isDone()) {
PrintJobConfigActivity.this.finish();
}
return;
+ } else {
+ // If print is not confirmed we just ask for the first of the
+ // selected pages to emulate a behavior that shows preview
+ // increasing the chances that apps will implement the APIs
+ // correctly.
+ if (!mEditor.isPrintConfirmed()) {
+ if (ALL_PAGES_ARRAY.equals(mRequestedPages)) {
+ mRequestedPages = new PageRange[] {new PageRange(0, 0)};
+ } else {
+ final int firstPage = mRequestedPages[0].getStart();
+ mRequestedPages = new PageRange[] {new PageRange(firstPage, firstPage)};
+ }
+ }
}
// If the info and the layout did not change and we already have
@@ -738,6 +758,8 @@
private PrinterInfo mCurrentPrinter;
+ private boolean mRequestedCurrentPrinterRefresh;
+
private final OnItemSelectedListener mOnItemSelectedListener =
new AdapterView.OnItemSelectedListener() {
@Override
@@ -757,34 +779,34 @@
return;
}
- mCurrPrintAttributes.clear();
+ mRequestedCurrentPrinterRefresh = false;
- PrinterInfo printer = (PrinterInfo) mDestinationSpinnerAdapter
+ mCurrentPrinter = (PrinterInfo) mDestinationSpinnerAdapter
.getItem(position);
PrintSpoolerService.peekInstance().setPrintJobPrinterNoPersistence(
- mPrintJobId, printer);
+ mPrintJobId, mCurrentPrinter);
- if (printer != null) {
- PrinterCapabilitiesInfo capabilities = printer.getCapabilities();
- if (capabilities == null) {
- //TODO: We need a timeout for the update.
- mEditor.refreshCurrentPrinter();
- } else {
- capabilities.getDefaults(mCurrPrintAttributes);
- if (!mController.hasStarted()) {
- mController.start();
- }
- mController.update();
- }
+ if (mCurrentPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE) {
+ updateUi();
+ return;
}
- mCurrentPrinter = printer;
-
- updateUiForNewPrinterCapabilities();
+ PrinterCapabilitiesInfo capabilities = mCurrentPrinter.getCapabilities();
+ if (capabilities == null) {
+ // TODO: We need a timeout for the update.
+ mRequestedCurrentPrinterRefresh = true;
+ updateUi();
+ refreshCurrentPrinter();
+ } else {
+ updatePrintAttributes(capabilities);
+ updateUi();
+ mController.update();
+ }
} else if (spinner == mMediaSizeSpinner) {
- if (mIgnoreNextMediaSizeChange) {
- mIgnoreNextMediaSizeChange = false;
+ if (mOldMediaSizeSelectionIndex
+ == mMediaSizeSpinner.getSelectedItemPosition()) {
+ mOldMediaSizeSelectionIndex = AdapterView.INVALID_POSITION;
return;
}
SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position);
@@ -793,8 +815,9 @@
mController.update();
}
} else if (spinner == mColorModeSpinner) {
- if (mIgnoreNextColorModeChange) {
- mIgnoreNextColorModeChange = false;
+ if (mOldColorModeSelectionIndex
+ == mColorModeSpinner.getSelectedItemPosition()) {
+ mOldColorModeSelectionIndex = AdapterView.INVALID_POSITION;
return;
}
SpinnerItem<Integer> colorModeItem =
@@ -810,16 +833,7 @@
}
SpinnerItem<Integer> orientationItem =
mOrientationSpinnerAdapter.getItem(position);
- MediaSize mediaSize = mCurrPrintAttributes.getMediaSize();
- if (orientationItem.value == ORIENTATION_PORTRAIT) {
- if (!mediaSize.isPortrait()) {
- mCurrPrintAttributes.setMediaSize(mediaSize.asPortrait());
- }
- } else {
- if (mediaSize.isPortrait()) {
- mCurrPrintAttributes.setMediaSize(mediaSize.asLandscape());
- }
- }
+ setCurrentPrintAttributesOrientation(orientationItem.value);
if (!hasErrors()) {
mController.update();
}
@@ -841,6 +855,104 @@
}
};
+ private void setCurrentPrintAttributesOrientation(int orientation) {
+ MediaSize mediaSize = mCurrPrintAttributes.getMediaSize();
+ if (orientation == ORIENTATION_PORTRAIT) {
+ if (!mediaSize.isPortrait()) {
+ // Rotate the media size.
+ mCurrPrintAttributes.setMediaSize(mediaSize.asPortrait());
+
+ // Rotate the resolution.
+ Resolution oldResolution = mCurrPrintAttributes.getResolution();
+ Resolution newResolution = new Resolution(
+ oldResolution.getId(),
+ oldResolution.getLabel(),
+ oldResolution.getVerticalDpi(),
+ oldResolution.getHorizontalDpi());
+ mCurrPrintAttributes.setResolution(newResolution);
+
+ // Rotate the physical margins.
+ Margins oldMinMargins = mCurrPrintAttributes.getMinMargins();
+ Margins newMinMargins = new Margins(
+ oldMinMargins.getBottomMils(),
+ oldMinMargins.getLeftMils(),
+ oldMinMargins.getTopMils(),
+ oldMinMargins.getRightMils());
+ mCurrPrintAttributes.setMinMargins(newMinMargins);
+ }
+ } else {
+ if (mediaSize.isPortrait()) {
+ // Rotate the media size.
+ mCurrPrintAttributes.setMediaSize(mediaSize.asLandscape());
+
+ // Rotate the resolution.
+ Resolution oldResolution = mCurrPrintAttributes.getResolution();
+ Resolution newResolution = new Resolution(
+ oldResolution.getId(),
+ oldResolution.getLabel(),
+ oldResolution.getVerticalDpi(),
+ oldResolution.getHorizontalDpi());
+ mCurrPrintAttributes.setResolution(newResolution);
+
+ // Rotate the physical margins.
+ Margins oldMinMargins = mCurrPrintAttributes.getMinMargins();
+ Margins newMargins = new Margins(
+ oldMinMargins.getTopMils(),
+ oldMinMargins.getRightMils(),
+ oldMinMargins.getBottomMils(),
+ oldMinMargins.getLeftMils());
+ mCurrPrintAttributes.setMinMargins(newMargins);
+ }
+ }
+ }
+
+ private void updatePrintAttributes(PrinterCapabilitiesInfo capabilities) {
+ PrintAttributes defaults = capabilities.getDefaults();
+
+ // Media size.
+ MediaSize currMediaSize = mCurrPrintAttributes.getMediaSize();
+ if (currMediaSize == null) {
+ mCurrPrintAttributes.setMediaSize(defaults.getMediaSize());
+ } else {
+ MediaSize currMediaSizePortrait = currMediaSize.asPortrait();
+ List<MediaSize> mediaSizes = capabilities.getMediaSizes();
+ final int mediaSizeCount = mediaSizes.size();
+ for (int i = 0; i < mediaSizeCount; i++) {
+ MediaSize mediaSize = mediaSizes.get(i);
+ if (currMediaSizePortrait.equals(mediaSize.asPortrait())) {
+ mCurrPrintAttributes.setMediaSize(mediaSize);
+ break;
+ }
+ }
+ }
+
+ // Color mode.
+ final int colorMode = mCurrPrintAttributes.getColorMode();
+ if ((capabilities.getColorModes() & colorMode) == 0) {
+ mCurrPrintAttributes.setColorMode(colorMode);
+ }
+
+ // Resolution
+ Resolution resolution = mCurrPrintAttributes.getResolution();
+ if (resolution == null || !capabilities.getResolutions().contains(resolution)) {
+ mCurrPrintAttributes.setResolution(defaults.getResolution());
+ }
+
+ // Margins.
+ Margins margins = mCurrPrintAttributes.getMinMargins();
+ if (margins == null) {
+ mCurrPrintAttributes.setMinMargins(defaults.getMinMargins());
+ } else {
+ Margins minMargins = capabilities.getMinMargins();
+ if (margins.getLeftMils() < minMargins.getLeftMils()
+ || margins.getTopMils() < minMargins.getTopMils()
+ || margins.getRightMils() > minMargins.getRightMils()
+ || margins.getBottomMils() > minMargins.getBottomMils()) {
+ mCurrPrintAttributes.setMinMargins(defaults.getMinMargins());
+ }
+ }
+ }
+
private final TextWatcher mCopiesTextWatcher = new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
@@ -952,8 +1064,8 @@
private int mEditorState;
private boolean mIgnoreNextDestinationChange;
- private boolean mIgnoreNextMediaSizeChange;
- private boolean mIgnoreNextColorModeChange;
+ private int mOldMediaSizeSelectionIndex;
+ private int mOldColorModeSelectionIndex;
private boolean mIgnoreNextOrientationChange;
private boolean mIgnoreNextRangeOptionChange;
private boolean mIgnoreNextCopiesChange;
@@ -993,11 +1105,22 @@
// capabilities, we refresh it.
if (mCurrentPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE
&& printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE
- && printer.getCapabilities() == null) {
+ && printer.getCapabilities() == null
+ && !mRequestedCurrentPrinterRefresh) {
+ mRequestedCurrentPrinterRefresh = true;
refreshCurrentPrinter();
return;
}
+ // We just refreshed the current printer.
+ if (printer.getCapabilities() != null
+ && mRequestedCurrentPrinterRefresh) {
+ mRequestedCurrentPrinterRefresh = false;
+ updatePrintAttributes(printer.getCapabilities());
+ updateUi();
+ mController.update();
+ }
+
// Update the UI if capabilities changed.
boolean capabilitiesChanged = false;
@@ -1010,14 +1133,18 @@
capabilitiesChanged = true;
}
- if (capabilitiesChanged) {
- // Update the current printer.
- mCurrentPrinter.copyFrom(printer);
+ // Update the UI if the status changed.
+ final boolean statusChanged = mCurrentPrinter.getStatus()
+ != printer.getStatus();
- // If something changed during UI update...
+ // Update the printer with the latest info.
+ if (!mCurrentPrinter.equals(printer)) {
+ mCurrentPrinter.copyFrom(printer);
+ }
+
+ if (capabilitiesChanged || statusChanged) {
+ // If something changed during update...
if (updateUi()) {
- // Update current attributes.
- printer.getCapabilities().getDefaults(mCurrPrintAttributes);
// Update the document.
mController.update();
}
@@ -1031,7 +1158,7 @@
@Override
public void onInvalidated() {
- updateUiForNewPrinterCapabilities();
+ /* do nothing - we always have one fake PDF printer */
}
});
@@ -1072,6 +1199,10 @@
showUi(UI_EDITING_PRINT_JOB, null);
bindUi();
+
+ mCurrentPrinter = mDestinationSpinnerAdapter.mFakePdfPrinter;
+ updatePrintAttributes(mCurrentPrinter.getCapabilities());
+
updateUi();
}
@@ -1256,7 +1387,8 @@
null, false);
// First animation - fade out the old content.
- hidingView.animate().alpha(0.0f).withLayer().withEndAction(new Runnable() {
+ AutoCancellingAnimator.animate(hidingView).alpha(0.0f)
+ .withLayer().withEndAction(new Runnable() {
@Override
public void run() {
hidingView.setVisibility(View.INVISIBLE);
@@ -1275,8 +1407,8 @@
/ (float) contentContainer.getHeight();
// Second animation - resize the container.
- contentContainer.animate().scaleY(scaleY).withLayer().withEndAction(
- new Runnable() {
+ AutoCancellingAnimator.animate(contentContainer).scaleY(scaleY).withLayer()
+ .withEndAction(new Runnable() {
@Override
public void run() {
// Swap the old and the new content.
@@ -1285,8 +1417,8 @@
contentContainer.addView(showingView);
// Third animation - show the new content.
- showingView.animate().withLayer().alpha(1.0f).withEndAction(
- new Runnable() {
+ AutoCancellingAnimator.animate(showingView).withLayer().alpha(1.0f)
+ .withEndAction(new Runnable() {
@Override
public void run() {
postAnimateCommand.run();
@@ -1342,8 +1474,12 @@
if (dashIndex > 0) {
fromIndex = Integer.parseInt(range.substring(0, dashIndex)) - 1;
- toIndex = Integer.parseInt(range.substring(
- dashIndex + 1, range.length())) - 1;
+ // It is possible that the dash is at the end since the input
+ // verification can has to allow the user to keep entering if
+ // this would lead to a valid input. So we handle this.
+ toIndex = (dashIndex < range.length() - 1)
+ ? Integer.parseInt(range.substring(dashIndex + 1,
+ range.length())) - 1 : fromIndex;
} else {
fromIndex = toIndex = Integer.parseInt(range) - 1;
}
@@ -1393,7 +1529,7 @@
mMediaSizeSpinner.setAdapter(mMediaSizeSpinnerAdapter);
mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
if (mMediaSizeSpinnerAdapter.getCount() > 0) {
- mIgnoreNextMediaSizeChange = true;
+ mOldMediaSizeSelectionIndex = 0;
}
// Color mode.
@@ -1401,7 +1537,7 @@
mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter);
mColorModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
if (mColorModeSpinnerAdapter.getCount() > 0) {
- mIgnoreNextColorModeChange = true;
+ mOldColorModeSelectionIndex = 0;
}
// Orientation
@@ -1454,7 +1590,8 @@
Object item = mDestinationSpinnerAdapter.getItem(selectedIndex);
if (item instanceof PrinterInfo) {
PrinterInfo printer = (PrinterInfo) item;
- if (printer.getCapabilities() != null) {
+ if (printer.getCapabilities() != null
+ && printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE) {
allOptionsEnabled = true;
}
}
@@ -1470,14 +1607,14 @@
// Media size
if (mMediaSizeSpinner.getSelectedItemPosition() != AdapterView.INVALID_POSITION) {
- mIgnoreNextMediaSizeChange = true;
+ mOldMediaSizeSelectionIndex = AdapterView.INVALID_POSITION;
mMediaSizeSpinner.setSelection(AdapterView.INVALID_POSITION);
}
mMediaSizeSpinner.setEnabled(false);
// Color mode
if (mColorModeSpinner.getSelectedItemPosition() != AdapterView.INVALID_POSITION) {
- mIgnoreNextColorModeChange = true;
+ mOldColorModeSelectionIndex = AdapterView.INVALID_POSITION;
mColorModeSpinner.setSelection(AdapterView.INVALID_POSITION);
}
mColorModeSpinner.setEnabled(false);
@@ -1513,10 +1650,9 @@
} else {
boolean someAttributeSelectionChanged = false;
- PrintAttributes defaultAttributes = mTempPrintAttributes;
PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem();
PrinterCapabilitiesInfo capabilities = printer.getCapabilities();
- printer.getCapabilities().getDefaults(defaultAttributes);
+ PrintAttributes defaultAttributes = printer.getCapabilities().getDefaults();
// Media size.
List<MediaSize> mediaSizes = capabilities.getMediaSizes();
@@ -1551,25 +1687,19 @@
mediaSize, mediaSize.getLabel(getPackageManager())));
}
- if (mediaSizeCount <= 0) {
- // No media sizes - clear the selection.
- mMediaSizeSpinner.setEnabled(false);
- // Clear selection and mark if selection changed.
- someAttributeSelectionChanged = setMediaSizeSpinnerSelectionNoCallback(
- AdapterView.INVALID_POSITION);
- } else {
- mMediaSizeSpinner.setEnabled(true);
+ mMediaSizeSpinner.setEnabled(true);
- if (oldMediaSizeNewIndex != AdapterView.INVALID_POSITION) {
- // Select the old media size - nothing really changed.
- setMediaSizeSpinnerSelectionNoCallback(oldMediaSizeNewIndex);
- } else {
- // Select the first or the default and mark if selection changed.
- final int mediaSizeIndex = Math.max(mediaSizes.indexOf(
- defaultAttributes.getMediaSize()), 0);
- someAttributeSelectionChanged = setMediaSizeSpinnerSelectionNoCallback(
- mediaSizeIndex);
- }
+ if (oldMediaSizeNewIndex != AdapterView.INVALID_POSITION) {
+ // Select the old media size - nothing really changed.
+ setMediaSizeSpinnerSelectionNoCallback(oldMediaSizeNewIndex);
+ } else {
+ // Select the first or the default and mark if selection changed.
+ final int mediaSizeIndex = Math.max(mediaSizes.indexOf(
+ defaultAttributes.getMediaSize()), 0);
+ setMediaSizeSpinnerSelectionNoCallback(mediaSizeIndex);
+ mCurrPrintAttributes.setMediaSize(mMediaSizeSpinnerAdapter
+ .getItem(mediaSizeIndex).value);
+ someAttributeSelectionChanged = true;
}
}
mMediaSizeSpinner.setEnabled(true);
@@ -1618,26 +1748,32 @@
mColorModeSpinnerAdapter.add(new SpinnerItem<Integer>(colorMode,
colorModeLabels[colorBitOffset]));
}
- final int colorModeCount = Integer.bitCount(colorModes);
- if (colorModeCount <= 0) {
- mColorModeSpinner.setEnabled(false);
- mColorModeSpinner.setSelection(AdapterView.INVALID_POSITION);
+ mColorModeSpinner.setEnabled(true);
+ if (oldColorModeNewIndex != AdapterView.INVALID_POSITION) {
+ // Select the old color mode - nothing really changed.
+ setColorModeSpinnerSelectionNoCallback(oldColorModeNewIndex);
} else {
- mColorModeSpinner.setEnabled(true);
- if (oldColorModeNewIndex != AdapterView.INVALID_POSITION) {
- // Select the old color mode - nothing really changed.
- setColorModeSpinnerSelectionNoCallback(oldColorModeNewIndex);
- } else {
- final int selectedColorModeIndex = Integer.numberOfTrailingZeros(
+ final int selectedColorModeIndex = Integer.numberOfTrailingZeros(
(colorModes & defaultAttributes.getColorMode()));
- someAttributeSelectionChanged = setColorModeSpinnerSelectionNoCallback(
- selectedColorModeIndex);
- }
+ setColorModeSpinnerSelectionNoCallback(selectedColorModeIndex);
+ mCurrPrintAttributes.setColorMode(mColorModeSpinnerAdapter
+ .getItem(selectedColorModeIndex).value);
+ someAttributeSelectionChanged = true;
}
}
mColorModeSpinner.setEnabled(true);
// Orientation
+ MediaSize mediaSize = mCurrPrintAttributes.getMediaSize();
+ if (mediaSize.isPortrait()
+ && mOrientationSpinner.getSelectedItemPosition() != 0) {
+ mIgnoreNextOrientationChange = true;
+ mOrientationSpinner.setSelection(0);
+ } else if (!mediaSize.isPortrait()
+ && mOrientationSpinner.getSelectedItemPosition() != 1) {
+ mIgnoreNextOrientationChange = true;
+ mOrientationSpinner.setSelection(1);
+ }
mOrientationSpinner.setEnabled(true);
// Range options
@@ -1723,50 +1859,18 @@
}
}
- private boolean setMediaSizeSpinnerSelectionNoCallback(int position) {
+ private void setMediaSizeSpinnerSelectionNoCallback(int position) {
if (mMediaSizeSpinner.getSelectedItemPosition() != position) {
- mIgnoreNextMediaSizeChange = true;
+ mOldMediaSizeSelectionIndex = position;
mMediaSizeSpinner.setSelection(position);
- return true;
}
- return false;
}
- private boolean setColorModeSpinnerSelectionNoCallback(int position) {
+ private void setColorModeSpinnerSelectionNoCallback(int position) {
if (mColorModeSpinner.getSelectedItemPosition() != position) {
- mIgnoreNextColorModeChange = true;
+ mOldColorModeSelectionIndex = position;
mColorModeSpinner.setSelection(position);
- return true;
}
- return false;
- }
-
- private void updateUiForNewPrinterCapabilities() {
- // The printer changed so we want to start with a clean slate
- // for the print options and let them be populated from the
- // printer capabilities and use the printer defaults.
- if (!mMediaSizeSpinnerAdapter.isEmpty()) {
- mIgnoreNextMediaSizeChange = true;
- mMediaSizeSpinnerAdapter.clear();
- }
- if (!mColorModeSpinnerAdapter.isEmpty()) {
- mIgnoreNextColorModeChange = true;
- mColorModeSpinnerAdapter.clear();
- }
- if (mOrientationSpinner.getSelectedItemPosition() != 0) {
- mIgnoreNextOrientationChange = true;
- mOrientationSpinner.setSelection(0);
- }
- if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
- mIgnoreNextRangeOptionChange = true;
- mRangeOptionsSpinner.setSelection(0);
- }
- if (!TextUtils.isEmpty(mCopiesEditText.getText())) {
- mIgnoreNextCopiesChange = true;
- mCopiesEditText.setText(MIN_COPIES_STRING);
- }
-
- updateUi();
}
private void startSelectPrinterActivity() {
@@ -1983,12 +2087,12 @@
.setColorModes(PrintAttributes.COLOR_MODE_COLOR
| PrintAttributes.COLOR_MODE_MONOCHROME,
PrintAttributes.COLOR_MODE_COLOR)
- .create();
+ .build();
return new PrinterInfo.Builder(printerId, getString(R.string.save_as_pdf),
PrinterInfo.STATUS_IDLE)
.setCapabilities(capabilities)
- .create();
+ .build();
}
}
}
@@ -2129,4 +2233,67 @@
}
}
}
+
+ private static final class AutoCancellingAnimator
+ implements OnAttachStateChangeListener, Runnable {
+
+ private ViewPropertyAnimator mAnimator;
+
+ private boolean mCancelled;
+ private Runnable mEndCallback;
+
+ public static AutoCancellingAnimator animate(View view) {
+ ViewPropertyAnimator animator = view.animate();
+ AutoCancellingAnimator cancellingWrapper =
+ new AutoCancellingAnimator(animator);
+ view.addOnAttachStateChangeListener(cancellingWrapper);
+ return cancellingWrapper;
+ }
+
+ private AutoCancellingAnimator(ViewPropertyAnimator animator) {
+ mAnimator = animator;
+ }
+
+ public AutoCancellingAnimator alpha(float alpha) {
+ mAnimator = mAnimator.alpha(alpha);
+ return this;
+ }
+
+ public void cancel() {
+ mAnimator.cancel();
+ }
+
+ public AutoCancellingAnimator withLayer() {
+ mAnimator = mAnimator.withLayer();
+ return this;
+ }
+
+ public AutoCancellingAnimator withEndAction(Runnable callback) {
+ mEndCallback = callback;
+ mAnimator = mAnimator.withEndAction(this);
+ return this;
+ }
+
+ public AutoCancellingAnimator scaleY(float scale) {
+ mAnimator = mAnimator.scaleY(scale);
+ return this;
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ cancel();
+ }
+
+ @Override
+ public void run() {
+ if (!mCancelled) {
+ mEndCallback.run();
+ }
+ }
+ }
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
index 7266af8..a6353f7 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
@@ -37,6 +37,7 @@
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
import android.print.PrintDocumentInfo;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrinterId;
@@ -51,6 +52,8 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.util.FastXmlSerializer;
+import libcore.io.IoUtils;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -63,8 +66,6 @@
import java.util.ArrayList;
import java.util.List;
-import libcore.io.IoUtils;
-
/**
* Service for exposing some of the {@link PrintSpooler} functionality to
* another process.
@@ -75,7 +76,7 @@
private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = true;
- private static final boolean DEBUG_PERSISTENCE = true;
+ private static final boolean DEBUG_PERSISTENCE = false;
private static final boolean PERSISTNECE_MANAGER_ENABLED = true;
@@ -91,10 +92,6 @@
private static PrintSpoolerService sInstance;
- private static int sPrintJobIdCounter;
-
- private Intent mStartPrintJobConfigActivityIntent;
-
private IPrintSpoolerClient mClient;
private HandlerCaller mHandlerCaller;
@@ -112,8 +109,6 @@
@Override
public void onCreate() {
super.onCreate();
- mStartPrintJobConfigActivityIntent = new Intent(PrintSpoolerService.this,
- PrintJobConfigActivity.class);
mHandlerCaller = new HandlerCaller(this, getMainLooper(),
new HandlerCallerCallback(), false);
@@ -147,7 +142,7 @@
}
@Override
- public void getPrintJobInfo(int printJobId, IPrintSpoolerCallbacks callback,
+ public void getPrintJobInfo(PrintJobId printJobId, IPrintSpoolerCallbacks callback,
int appId, int sequence) throws RemoteException {
PrintJobInfo printJob = null;
try {
@@ -159,38 +154,28 @@
@SuppressWarnings("deprecation")
@Override
- public void createPrintJob(String printJobName, IPrintClient client,
- IPrintDocumentAdapter printAdapter, PrintAttributes attributes,
- IPrintSpoolerCallbacks callback, int appId, int sequence)
- throws RemoteException {
- PrintJobInfo printJob = null;
- try {
- printJob = PrintSpoolerService.this.createPrintJob(
- printJobName, client, attributes, appId);
- if (printJob != null) {
- Intent intent = mStartPrintJobConfigActivityIntent;
- intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_DOCUMENT_ADAPTER,
- printAdapter.asBinder());
- intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_JOB_ID,
- printJob.getId());
- intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_ATTRIBUTES, attributes);
+ public void createPrintJob(PrintJobInfo printJob, IPrintClient client,
+ IPrintDocumentAdapter printAdapter) throws RemoteException {
+ PrintSpoolerService.this.createPrintJob(printJob);
- IntentSender sender = PendingIntent.getActivity(
- PrintSpoolerService.this, 0, intent, PendingIntent.FLAG_ONE_SHOT
- | PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
+ Intent intent = new Intent(printJob.getId().flattenToString());
+ intent.setClass(PrintSpoolerService.this, PrintJobConfigActivity.class);
+ intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_DOCUMENT_ADAPTER,
+ printAdapter.asBinder());
+ intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_JOB, printJob);
- Message message = mHandlerCaller.obtainMessageOO(
- HandlerCallerCallback.MSG_START_PRINT_JOB_CONFIG_ACTIVITY,
- client, sender);
- mHandlerCaller.executeOrSendMessage(message);
- }
- } finally {
- callback.onCreatePrintJobResult(printJob, sequence);
- }
+ IntentSender sender = PendingIntent.getActivity(
+ PrintSpoolerService.this, 0, intent, PendingIntent.FLAG_ONE_SHOT
+ | PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
+
+ Message message = mHandlerCaller.obtainMessageOO(
+ HandlerCallerCallback.MSG_START_PRINT_JOB_CONFIG_ACTIVITY,
+ client, sender);
+ mHandlerCaller.executeOrSendMessage(message);
}
@Override
- public void setPrintJobState(int printJobId, int state, String error,
+ public void setPrintJobState(PrintJobId printJobId, int state, String error,
IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
boolean success = false;
try {
@@ -202,7 +187,7 @@
}
@Override
- public void setPrintJobTag(int printJobId, String tag,
+ public void setPrintJobTag(PrintJobId printJobId, String tag,
IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
boolean success = false;
try {
@@ -213,7 +198,7 @@
}
@Override
- public void writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
+ public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
PrintSpoolerService.this.writePrintJobData(fd, printJobId);
}
@@ -223,6 +208,16 @@
HandlerCallerCallback.MSG_SET_CLIENT, client);
mHandlerCaller.executeOrSendMessage(message);
}
+
+ @Override
+ public void removeObsoletePrintJobs() {
+ PrintSpoolerService.this.removeObsoletePrintJobs();
+ }
+
+ @Override
+ public void forgetPrintJobs(List<PrintJobId> printJobIds) {
+ PrintSpoolerService.this.forgetPrintJobs(printJobIds);
+ }
};
}
@@ -351,15 +346,16 @@
private boolean isStateVisibleToUser(int state) {
return (isActiveState(state) && (state == PrintJobInfo.STATE_FAILED
- || state == PrintJobInfo.STATE_COMPLETED|| state == PrintJobInfo.STATE_CANCELED));
+ || state == PrintJobInfo.STATE_COMPLETED || state == PrintJobInfo.STATE_CANCELED
+ || state == PrintJobInfo.STATE_BLOCKED));
}
- public PrintJobInfo getPrintJobInfo(int printJobId, int appId) {
+ public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
synchronized (mLock) {
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
- if (printJob.getId() == printJobId
+ if (printJob.getId().equals(printJobId)
&& (appId == PrintManager.APP_ID_ANY
|| appId == printJob.getAppId())) {
return printJob;
@@ -369,20 +365,9 @@
}
}
- public PrintJobInfo createPrintJob(String label, IPrintClient client,
- PrintAttributes attributes, int appId) {
+ public void createPrintJob(PrintJobInfo printJob) {
synchronized (mLock) {
- final int printJobId = generatePrintJobIdLocked();
- PrintJobInfo printJob = new PrintJobInfo();
- printJob.setId(printJobId);
- printJob.setAppId(appId);
- printJob.setLabel(label);
- printJob.setAttributes(attributes);
- printJob.setState(PrintJobInfo.STATE_CREATED);
-
addPrintJobLocked(printJob);
-
- return printJob;
}
}
@@ -404,8 +389,7 @@
// decide whether to restart the job or just cancel it.
setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
getString(R.string.no_connection_to_printer));
- }
- break;
+ } break;
}
}
}
@@ -418,26 +402,7 @@
}
}
- private int generatePrintJobIdLocked() {
- int printJobId = sPrintJobIdCounter++;
- while (isDuplicatePrintJobId(printJobId)) {
- printJobId = sPrintJobIdCounter++;
- }
- return printJobId;
- }
-
- private boolean isDuplicatePrintJobId(int printJobId) {
- final int printJobCount = mPrintJobs.size();
- for (int j = 0; j < printJobCount; j++) {
- PrintJobInfo printJob = mPrintJobs.get(j);
- if (printJob.getId() == printJobId) {
- return true;
- }
- }
- return false;
- }
-
- public void writePrintJobData(final ParcelFileDescriptor fd, final int printJobId) {
+ public void writePrintJobData(final ParcelFileDescriptor fd, final PrintJobId printJobId) {
final PrintJobInfo printJob;
synchronized (mLock) {
printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
@@ -476,9 +441,9 @@
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
}
- public File generateFileForPrintJob(int printJobId) {
+ public File generateFileForPrintJob(PrintJobId printJobId) {
return new File(getFilesDir(), "print_job_"
- + printJobId + "." + PRINT_FILE_EXTENSION);
+ + printJobId.flattenToString() + "." + PRINT_FILE_EXTENSION);
}
private void addPrintJobLocked(PrintJobInfo printJob) {
@@ -488,16 +453,59 @@
}
}
- private void removePrintJobLocked(PrintJobInfo printJob) {
- if (mPrintJobs.remove(printJob)) {
- generateFileForPrintJob(printJob.getId()).delete();
- if (DEBUG_PRINT_JOB_LIFECYCLE) {
- Slog.i(LOG_TAG, "[REMOVE] " + printJob);
+ private void forgetPrintJobs(List<PrintJobId> printJobIds) {
+ synchronized (mLock) {
+ boolean printJobsRemoved = false;
+ final int removedPrintJobCount = printJobIds.size();
+ for (int i = 0; i < removedPrintJobCount; i++) {
+ PrintJobId removedPrintJobId = printJobIds.get(i);
+ final int printJobCount = mPrintJobs.size();
+ for (int j = printJobCount - 1; j >= 0; j--) {
+ PrintJobInfo printJob = mPrintJobs.get(j);
+ if (removedPrintJobId.equals(printJob.getId())) {
+ mPrintJobs.remove(j);
+ printJobsRemoved = true;
+ if (DEBUG_PRINT_JOB_LIFECYCLE) {
+ Slog.i(LOG_TAG, "[FORGOT] " + printJob.getId().flattenToString());
+ }
+ removePrintJobFileLocked(printJob.getId());
+ }
+ }
+ }
+ if (printJobsRemoved) {
+ mPersistanceManager.writeStateLocked();
}
}
}
- public boolean setPrintJobState(int printJobId, int state, String error) {
+ private void removeObsoletePrintJobs() {
+ synchronized (mLock) {
+ final int printJobCount = mPrintJobs.size();
+ for (int i = printJobCount - 1; i >= 0; i--) {
+ PrintJobInfo printJob = mPrintJobs.get(i);
+ if (isObsoleteState(printJob.getState())) {
+ mPrintJobs.remove(i);
+ if (DEBUG_PRINT_JOB_LIFECYCLE) {
+ Slog.i(LOG_TAG, "[REMOVE] " + printJob.getId().flattenToString());
+ }
+ removePrintJobFileLocked(printJob.getId());
+ }
+ }
+ mPersistanceManager.writeStateLocked();
+ }
+ }
+
+ private void removePrintJobFileLocked(PrintJobId printJobId) {
+ File file = generateFileForPrintJob(printJobId);
+ if (file.exists()) {
+ file.delete();
+ if (DEBUG_PRINT_JOB_LIFECYCLE) {
+ Slog.i(LOG_TAG, "[REMOVE FILE FOR] " + printJobId.flattenToString());
+ }
+ }
+ }
+
+ public boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
boolean success = false;
synchronized (mLock) {
@@ -516,7 +524,11 @@
switch (state) {
case PrintJobInfo.STATE_COMPLETED:
case PrintJobInfo.STATE_CANCELED:
- removePrintJobLocked(printJob);
+ // Just remove the file but keep the print job info since
+ // the app that created it may be holding onto the PrintJob
+ // instance and query it for its most recent state. We will
+ // remove the info for this job when told so by the system.
+ removePrintJobFileLocked(printJob.getId());
// $fall-through$
case PrintJobInfo.STATE_FAILED: {
@@ -570,6 +582,11 @@
return false;
}
+ private boolean isObsoleteState(int printJobState) {
+ return (isTeminalState(printJobState)
+ || printJobState == PrintJobInfo.STATE_QUEUED);
+ }
+
private boolean isActiveState(int printJobState) {
return printJobState == PrintJobInfo.STATE_CREATED
|| printJobState == PrintJobInfo.STATE_QUEUED
@@ -577,7 +594,12 @@
|| printJobState == PrintJobInfo.STATE_BLOCKED;
}
- public boolean setPrintJobTag(int printJobId, String tag) {
+ private boolean isTeminalState(int printJobState) {
+ return printJobState == PrintJobInfo.STATE_COMPLETED
+ || printJobState == PrintJobInfo.STATE_CANCELED;
+ }
+
+ public boolean setPrintJobTag(PrintJobId printJobId, String tag) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -599,7 +621,7 @@
return false;
}
- public void setPrintJobCopiesNoPersistence(int printJobId, int copies) {
+ public void setPrintJobCopiesNoPersistence(PrintJobId printJobId, int copies) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -608,7 +630,8 @@
}
}
- public void setPrintJobPrintDocumentInfoNoPersistence(int printJobId, PrintDocumentInfo info) {
+ public void setPrintJobPrintDocumentInfoNoPersistence(PrintJobId printJobId,
+ PrintDocumentInfo info) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -617,7 +640,8 @@
}
}
- public void setPrintJobAttributesNoPersistence(int printJobId, PrintAttributes attributes) {
+ public void setPrintJobAttributesNoPersistence(PrintJobId printJobId,
+ PrintAttributes attributes) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -626,7 +650,7 @@
}
}
- public void setPrintJobPrinterNoPersistence(int printJobId, PrinterInfo printer) {
+ public void setPrintJobPrinterNoPersistence(PrintJobId printJobId, PrinterInfo printer) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -636,7 +660,7 @@
}
}
- public void setPrintJobPagesNoPersistence(int printJobId, PageRange[] pages) {
+ public void setPrintJobPagesNoPersistence(PrintJobId printJobId, PageRange[] pages) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -759,15 +783,9 @@
for (int j = 0; j < printJobCount; j++) {
PrintJobInfo printJob = printJobs.get(j);
- final int state = printJob.getState();
- if (state < PrintJobInfo.STATE_QUEUED
- || state > PrintJobInfo.STATE_CANCELED) {
- continue;
- }
-
serializer.startTag(null, TAG_JOB);
- serializer.attribute(null, ATTR_ID, String.valueOf(printJob.getId()));
+ serializer.attribute(null, ATTR_ID, printJob.getId().flattenToString());
serializer.attribute(null, ATTR_LABEL, printJob.getLabel().toString());
serializer.attribute(null, ATTR_STATE, String.valueOf(printJob.getState()));
serializer.attribute(null, ATTR_APP_ID, String.valueOf(printJob.getAppId()));
@@ -838,22 +856,12 @@
resolution.getHorizontalDpi()));
serializer.attribute(null, ATTR_VERTICAL_DPI, String.valueOf(
resolution.getVerticalDpi()));
- // We prefer to store only the package name and
- // resource id and fallback to the label.
- if (!TextUtils.isEmpty(mediaSize.mPackageName)
- && resolution.mLabelResId > 0) {
- serializer.attribute(null, ATTR_PACKAGE_NAME,
- resolution.mPackageName);
- serializer.attribute(null, ATTR_LABEL_RES_ID,
- String.valueOf(resolution.mLabelResId));
- } else {
- serializer.attribute(null, ATTR_LABEL,
- resolution.getLabel(getPackageManager()));
- }
+ serializer.attribute(null, ATTR_LABEL,
+ resolution.getLabel());
serializer.endTag(null, TAG_RESOLUTION);
}
- Margins margins = attributes.getMargins();
+ Margins margins = attributes.getMinMargins();
if (margins != null) {
serializer.startTag(null, TAG_MARGINS);
serializer.attribute(null, ATTR_LEFT_MILS, String.valueOf(
@@ -958,7 +966,8 @@
PrintJobInfo printJob = new PrintJobInfo();
- final int printJobId = Integer.parseInt(parser.getAttributeValue(null, ATTR_ID));
+ PrintJobId printJobId = PrintJobId.unflattenFromString(
+ parser.getAttributeValue(null, ATTR_ID));
printJob.setId(printJobId);
String label = parser.getAttributeValue(null, ATTR_LABEL);
printJob.setLabel(label);
@@ -1047,11 +1056,7 @@
ATTR_HORIZONTAL_DPI));
final int verticalDpi = Integer.parseInt(parser.getAttributeValue(null,
ATTR_VERTICAL_DPI));
- String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
- final int labelResId = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_LABEL_RES_ID));
- Resolution resolution = new Resolution(id, label, packageName, labelResId,
- horizontalDpi, verticalDpi);
+ Resolution resolution = new Resolution(id, label, horizontalDpi, verticalDpi);
builder.setResolution(resolution);
parser.next();
skipEmptyTextTags(parser);
@@ -1070,14 +1075,14 @@
final int bottomMils = Integer.parseInt(parser.getAttributeValue(null,
ATTR_BOTTOM_MILS));
Margins margins = new Margins(leftMils, topMils, rightMils, bottomMils);
- builder.setMargins(margins);
+ builder.setMinMargins(margins);
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.END_TAG, TAG_MARGINS);
parser.next();
}
- printJob.setAttributes(builder.create());
+ printJob.setAttributes(builder.build());
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.END_TAG, TAG_ATTRIBUTES);
@@ -1093,7 +1098,7 @@
ATTR_CONTENT_TYPE));
PrintDocumentInfo info = new PrintDocumentInfo.Builder(name)
.setPageCount(pageCount)
- .setContentType(contentType).create();
+ .setContentType(contentType).build();
printJob.setDocumentInfo(info);
parser.next();
skipEmptyTextTags(parser);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
index 4006a5a..fd14af9 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
@@ -17,7 +17,6 @@
package com.android.printspooler;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -43,7 +42,7 @@
final class RemotePrintDocumentAdapter {
private static final String LOG_TAG = "RemotePrintDocumentAdapter";
- private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+ private static final boolean DEBUG = false;
private final IPrintDocumentAdapter mRemoteInterface;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
index 9ca3a86..c397c40 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
@@ -24,20 +24,26 @@
import android.app.FragmentTransaction;
import android.app.ListFragment;
import android.app.LoaderManager;
+import android.content.ActivityNotFoundException;
import android.content.ComponentName;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.Loader;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.Bundle;
+import android.print.PrintManager;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.printservice.PrintServiceInfo;
import android.text.TextUtils;
+import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -59,6 +65,8 @@
*/
public final class SelectPrinterFragment extends ListFragment {
+ private static final String LOG_TAG = "SelectPrinterFragment";
+
private static final int LOADER_ID_PRINTERS_LOADER = 1;
private static final String FRAGMRNT_TAG_ADD_PRINTER_DIALOG =
@@ -142,40 +150,45 @@
private void updateAddPrintersAdapter() {
mAddPrinterServices.clear();
- // Get all print services.
- List<ResolveInfo> resolveInfos = getActivity().getPackageManager().queryIntentServices(
- new Intent(android.printservice.PrintService.SERVICE_INTERFACE),
- PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+ // Get all enabled print services.
+ PrintManager printManager = (PrintManager) getActivity()
+ .getSystemService(Context.PRINT_SERVICE);
+ List<PrintServiceInfo> enabledServices = printManager.getEnabledPrintServices();
- // No print services - done.
- if (resolveInfos.isEmpty()) {
+ // No enabled print services - done.
+ if (enabledServices.isEmpty()) {
return;
}
// Find the services with valid add printers activities.
- final int resolveInfoCount = resolveInfos.size();
- for (int i = 0; i < resolveInfoCount; i++) {
- ResolveInfo resolveInfo = resolveInfos.get(i);
-
- PrintServiceInfo printServiceInfo = PrintServiceInfo.create(
- resolveInfo, getActivity());
- String addPrintersActivity = printServiceInfo.getAddPrintersActivityName();
+ final int enabledServiceCount = enabledServices.size();
+ for (int i = 0; i < enabledServiceCount; i++) {
+ PrintServiceInfo enabledService = enabledServices.get(i);
// No add printers activity declared - done.
- if (TextUtils.isEmpty(addPrintersActivity)) {
+ if (TextUtils.isEmpty(enabledService.getAddPrintersActivityName())) {
continue;
}
+ ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo;
ComponentName addPrintersComponentName = new ComponentName(
- resolveInfo.serviceInfo.packageName,
- addPrintersActivity);
- Intent addPritnersIntent = new Intent(Intent.ACTION_MAIN)
+ serviceInfo.packageName, enabledService.getAddPrintersActivityName());
+ Intent addPritnersIntent = new Intent()
.setComponent(addPrintersComponentName);
// The add printers activity is valid - add it.
- if (!getActivity().getPackageManager().queryIntentActivities(
- addPritnersIntent, 0).isEmpty()) {
- mAddPrinterServices.add(printServiceInfo);
+ PackageManager pm = getActivity().getPackageManager();
+ List<ResolveInfo> resolvedActivities = pm.queryIntentActivities(addPritnersIntent, 0);
+ if (!resolvedActivities.isEmpty()) {
+ // The activity is a component name, therefore it is one or none.
+ ActivityInfo activityInfo = resolvedActivities.get(0).activityInfo;
+ if (activityInfo.exported
+ && (activityInfo.permission == null
+ || pm.checkPermission(activityInfo.permission,
+ getActivity().getPackageName())
+ == PackageManager.PERMISSION_GRANTED)) {
+ mAddPrinterServices.add(enabledService);
+ }
}
}
}
@@ -228,7 +241,11 @@
printService.getAddPrintersActivityName());
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(componentName);
- startActivity(intent);
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException anfe) {
+ Log.w(LOG_TAG, "Couldn't start settings activity", anfe);
+ }
}
});
@@ -238,7 +255,11 @@
builder.setPositiveButton(R.string.search_play_store,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
- startActivity(marketIntent);
+ try {
+ startActivity(marketIntent);
+ } catch (ActivityNotFoundException anfe) {
+ Log.w(LOG_TAG, "Couldn't start add printer activity", anfe);
+ }
}
});
}
diff --git a/packages/SettingsProvider/res/values-en-rIN/strings.xml b/packages/SettingsProvider/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..c19fdd7
--- /dev/null
+++ b/packages/SettingsProvider/res/values-en-rIN/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">"Settings Storage"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-et-rEE/strings.xml b/packages/SettingsProvider/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..30b7293
--- /dev/null
+++ b/packages/SettingsProvider/res/values-et-rEE/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">"Seadete talletusruum"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-fr-rCA/strings.xml b/packages/SettingsProvider/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..c90eb09
--- /dev/null
+++ b/packages/SettingsProvider/res/values-fr-rCA/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">"Stockage des paramètres"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-hy-rAM/strings.xml b/packages/SettingsProvider/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..b1f1afb
--- /dev/null
+++ b/packages/SettingsProvider/res/values-hy-rAM/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">"Կարգավորումների պահուստ"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-ka-rGE/strings.xml b/packages/SettingsProvider/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..691a2e9
--- /dev/null
+++ b/packages/SettingsProvider/res/values-ka-rGE/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">"პარამეტრების საცავი"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-km-rKH/strings.xml b/packages/SettingsProvider/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..7be62427
--- /dev/null
+++ b/packages/SettingsProvider/res/values-km-rKH/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">"កំណត់ការផ្ទុក"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-lo-rLA/strings.xml b/packages/SettingsProvider/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..4e57936
--- /dev/null
+++ b/packages/SettingsProvider/res/values-lo-rLA/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">"ບ່ອນເກັບຂໍ້ມູນການຕັ້ງຄ່າ"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-mn-rMN/strings.xml b/packages/SettingsProvider/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..9452145
--- /dev/null
+++ b/packages/SettingsProvider/res/values-mn-rMN/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">"Тохиргооны Сан"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-ms-rMY/strings.xml b/packages/SettingsProvider/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..9108b07
--- /dev/null
+++ b/packages/SettingsProvider/res/values-ms-rMY/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">"Storan Tetapan"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-zh-rHK/strings.xml b/packages/SettingsProvider/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..977c9b9
--- /dev/null
+++ b/packages/SettingsProvider/res/values-zh-rHK/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">"設定儲存空間"</string>
+</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 3f04470..7b09092 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -137,6 +137,7 @@
static class Network {
String ssid = ""; // equals() and hashCode() need these to be non-null
String key_mgmt = "";
+ boolean certUsed = false;
final ArrayList<String> rawLines = new ArrayList<String>();
public static Network readFromStream(BufferedReader in) {
@@ -167,6 +168,12 @@
ssid = line;
} else if (line.startsWith("key_mgmt")) {
key_mgmt = line;
+ } else if (line.startsWith("client_cert=")) {
+ certUsed = true;
+ } else if (line.startsWith("ca_cert=")) {
+ certUsed = true;
+ } else if (line.startsWith("ca_path=")) {
+ certUsed = true;
}
}
@@ -246,6 +253,13 @@
public void write(Writer w) throws IOException {
for (Network net : mNetworks) {
+ if (net.certUsed) {
+ // Networks that use certificates for authentication can't be restored
+ // because the certificates they need don't get restored (because they
+ // are stored in keystore, and can't be restored)
+ continue;
+ }
+
net.write(w);
}
}
@@ -738,10 +752,12 @@
}
}
+ // Intercept the keys and see if they need special handling
+ value = mSettingsHelper.onBackupValue(key, value);
+
if (value == null) {
continue;
}
-
// Write the key and value in the intermediary array.
byte[] keyBytes = key.getBytes();
totalSize += INTEGER_BYTE_COUNT + keyBytes.length;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index a446e40..dd7a828 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -23,6 +23,8 @@
import android.content.res.Configuration;
import android.location.LocationManager;
import android.media.AudioManager;
+import android.media.RingtoneManager;
+import android.net.Uri;
import android.os.IPowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -33,6 +35,7 @@
import java.util.Locale;
public class SettingsHelper {
+ private static final String SILENT_RINGTONE = "_silent";
private Context mContext;
private AudioManager mAudioManager;
@@ -63,10 +66,60 @@
setAutoRestore(Integer.parseInt(value) == 1);
} else if (isAlreadyConfiguredCriticalAccessibilitySetting(name)) {
return false;
+ } else if (Settings.System.RINGTONE.equals(name)
+ || Settings.System.NOTIFICATION_SOUND.equals(name)) {
+ setRingtone(name, value);
+ return false;
}
return true;
}
+ public String onBackupValue(String name, String value) {
+ // Special processing for backing up ringtones
+ if (Settings.System.RINGTONE.equals(name)
+ || Settings.System.NOTIFICATION_SOUND.equals(name)) {
+ if (value == null) {
+ // Silent ringtone
+ return SILENT_RINGTONE;
+ } else {
+ return getCanonicalRingtoneValue(value);
+ }
+ }
+ // Return the original value
+ return value;
+ }
+
+ /**
+ * Sets the ringtone of type specified by the name.
+ *
+ * @param name should be Settings.System.RINGTONE or Settings.System.NOTIFICATION_SOUND.
+ * @param value can be a canonicalized uri or "_silent" to indicate a silent (null) ringtone.
+ */
+ private void setRingtone(String name, String value) {
+ // If it's null, don't change the default
+ if (value == null) return;
+ Uri ringtoneUri = null;
+ if (SILENT_RINGTONE.equals(value)) {
+ ringtoneUri = null;
+ } else {
+ Uri canonicalUri = Uri.parse(value);
+ ringtoneUri = mContext.getContentResolver().uncanonicalize(canonicalUri);
+ if (ringtoneUri == null) {
+ // Unrecognized or invalid Uri, don't restore
+ return;
+ }
+ }
+ final int ringtoneType = Settings.System.RINGTONE.equals(name)
+ ? RingtoneManager.TYPE_RINGTONE : RingtoneManager.TYPE_NOTIFICATION;
+ RingtoneManager.setActualDefaultRingtoneUri(mContext, ringtoneType, ringtoneUri);
+ }
+
+ private String getCanonicalRingtoneValue(String value) {
+ final Uri ringtoneUri = Uri.parse(value);
+ final Uri canonicalUri = mContext.getContentResolver().canonicalize(ringtoneUri);
+ return canonicalUri == null ? null : canonicalUri.toString();
+ }
+
private boolean isAlreadyConfiguredCriticalAccessibilitySetting(String name) {
// These are the critical accessibility settings that are required for a
// blind user to be able to interact with the device. If these settings are
diff --git a/packages/Shell/res/values-cs/strings.xml b/packages/Shell/res/values-cs/strings.xml
index effdcb9..577f69c 100644
--- a/packages/Shell/res/values-cs/strings.xml
+++ b/packages/Shell/res/values-cs/strings.xml
@@ -19,6 +19,6 @@
<string name="app_label" msgid="3701846017049540910">"Prostředí"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Byla vytvořena zpráva o chybě"</string>
<string name="bugreport_finished_text" msgid="3559904746859400732">"Zprávu o chybě můžete sdílet klepnutím."</string>
- <string name="bugreport_confirm" msgid="5130698467795669780">"Zprávy o chybách obsahují data z různých souborů protokolů systému včetně osobních a soukromých informací. Zprávy o chybách sdílejte pouze s aplikacemi a uživateli, kterým důvěřujete."</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Chybová hlášení obsahují data z různých souborů protokolů systému včetně osobních a soukromých informací. Chybová hlášení sdílejte pouze s aplikacemi a uživateli, kterým důvěřujete."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobrazit tuto zprávu příště"</string>
</resources>
diff --git a/packages/Shell/res/values-en-rIN/strings.xml b/packages/Shell/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..68708e0
--- /dev/null
+++ b/packages/Shell/res/values-en-rIN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"Bug report captured"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"Touch to share your bug report"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
+</resources>
diff --git a/packages/Shell/res/values-et-rEE/strings.xml b/packages/Shell/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..7788158
--- /dev/null
+++ b/packages/Shell/res/values-et-rEE/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3701846017049540910">"Kest"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"Veaaruanne jäädvustati"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"Veaaruande jagamiseks puudutage"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Veaaruanded sisaldavad andmeid erinevatest süsteemi logifailidest, sh isiklikku ja privaatset teavet. Jagage veaaruandeid ainult usaldusväärsete rakenduste ja inimestega."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Kuva see sõnum järgmisel korral"</string>
+</resources>
diff --git a/packages/Shell/res/values-fr-rCA/strings.xml b/packages/Shell/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..c672f23
--- /dev/null
+++ b/packages/Shell/res/values-fr-rCA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"Rapport de bogue enregistré"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"Appuyer ici pour partager votre rapport de bogue"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Les rapports de bogue contiennent des données des fichiers journaux du système, y compris des informations personnelles et privées. Ne partagez les rapports de bogue qu\'avec les applications et les personnes que vous estimez fiables."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afficher ce message la prochaine fois"</string>
+</resources>
diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml
index 4ea0664..7e73c79 100644
--- a/packages/Shell/res/values-hi/strings.xml
+++ b/packages/Shell/res/values-hi/strings.xml
@@ -19,6 +19,6 @@
<string name="app_label" msgid="3701846017049540910">"शेल"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"बग रिपोर्ट कैप्चर कर ली गई"</string>
<string name="bugreport_finished_text" msgid="3559904746859400732">"अपनी बग रिपोर्ट साझा करने के लिए स्पर्श करें"</string>
- <string name="bugreport_confirm" msgid="5130698467795669780">"बग रिपोर्ट में व्यक्तिगत और निजी जानकारी सहित, सिस्टम की विभिन्न लॉग फ़ाइलों का डेटा होता है. बग रिपोर्ट केवल विश्वसनीय एप्लिकेशन और व्यक्तियों से ही साझा करें."</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"बग रिपोर्ट में व्यक्तिगत और निजी जानकारी सहित, सिस्टम की विभिन्न लॉग फ़ाइलों का डेटा होता है. बग रिपोर्ट केवल विश्वसनीय एप्स और व्यक्तियों से ही साझा करें."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"यह संदेश अगली बार दिखाएं"</string>
</resources>
diff --git a/packages/Shell/res/values-hy-rAM/strings.xml b/packages/Shell/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..ea7fa9f
--- /dev/null
+++ b/packages/Shell/res/values-hy-rAM/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3701846017049540910">"Խեցի"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"Վրիպակի զեկույց ստացվեց"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"Հպեք` ձեր վրիպակի մասին զեկույցը տարածելու համար"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Վրիպակի զեկույցները պարունակում են տվյալներ համակարգի տարբեր մուտքի ֆայլերից, այդ թվում նաև անհատական և գաղտնի տեղեկություններ: Վրիպակի զեկույցները կիսեք միայն այն հավելվածների և մարդկանց հետ, որոնց վստահում եք:"</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Այս հաղորդագրությունը ցույց տալ հաջորդ անգամ"</string>
+</resources>
diff --git a/packages/Shell/res/values-ka-rGE/strings.xml b/packages/Shell/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..7d9c72a
--- /dev/null
+++ b/packages/Shell/res/values-ka-rGE/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3701846017049540910">"გარეკანი"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"ანგარიში ხარვეზების შესახებ შექმნილია"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"შეეხეთ თქვენი ხარვეზების ანგარიშის გასაზიარებლად"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"ხარვეზის ანგარიშები მოიცავს მონაცემებს სხვადასხვა სისტემური ჟურნალის ფაილებიდან, მათ შორის პირად და კონფიდენციალურ ინფორმაციას."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"შემდგომში აჩვენე ეს შეტყობინება"</string>
+</resources>
diff --git a/packages/Shell/res/values-km-rKH/strings.xml b/packages/Shell/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..efb345c
--- /dev/null
+++ b/packages/Shell/res/values-km-rKH/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3701846017049540910">"សែល"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"បានចាប់យករបាយការណ៍កំហុស"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"ប៉ះ ដើម្បីចែករំលែករបាយការណ៍កំហុសរបស់អ្នក"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"របាយការណ៍កំហុសរួមមានឯកសារកំណត់ហេតុផ្សេងៗរបស់ប្រព័ន្ធ រួមមានព័ត៌មានផ្ទាល់ខ្លួន និងឯកជន។ ចែករំលែករបាយការណ៍កំហុសជាមួយកម្មវិធី និងមនុស្សដែលអ្នកទុកចិត្ត។"</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"បង្ហាញសារនេះពេលក្រោយ"</string>
+</resources>
diff --git a/packages/Shell/res/values-lo-rLA/strings.xml b/packages/Shell/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..a237d48
--- /dev/null
+++ b/packages/Shell/res/values-lo-rLA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"ລາຍງານຈຸດບົກພ່ອງຖືກເກັບກຳແລ້ວ"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"ແຕະເພື່ອສົ່ງການລາຍງານປັນຫາຂອງທ່ານ"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"ການລາຍງານຂໍ້ຜິດພາດປະກອບມີ ຂໍ້ມູນຈາກໄຟລ໌ບັນທຶກຂອງລະບົບຫຼາຍໄຟລ໌, ຮວມທັງຂໍ້ມູນສ່ວນໂຕນຳ. ທ່ານຕ້ອງແບ່ງປັນລາຍງານຂໍ້ຜິດພາດໃຫ້ແອັບຯ ແລະຄົນທີ່ທ່ານເຊື່ອຖືໄດ້ເທົ່ານັ້ນ."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ສະແດງຂໍ້ຄວາມນີ້ອີກໃນເທື່ອຕໍ່ໄປ"</string>
+</resources>
diff --git a/packages/Shell/res/values-mn-rMN/strings.xml b/packages/Shell/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..f74298d
--- /dev/null
+++ b/packages/Shell/res/values-mn-rMN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3701846017049540910">"Шел"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"Алдааны мэдээлэл хүлээн авав"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"Та алдааны мэдэгдлийг хуваалцах бол хүрнэ үү"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Алдааны репорт нь хувийн болон нууц мэдээлэл зэргийг агуулсан системийн төрөл бүрийн лог файлын датаг агуулна. Алдааны репортыг зөвхөн итгэлтэй апп болон хүмүүст хуваалцана уу."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Энэ мессежийг дараагийн удаа харуулах"</string>
+</resources>
diff --git a/packages/Shell/res/values-ms-rMY/strings.xml b/packages/Shell/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..8d1e4a2
--- /dev/null
+++ b/packages/Shell/res/values-ms-rMY/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"Laporan pepijat telah ditangkap"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"Sentuh untuk berkongsi laporan pepijat anda"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Laporan pepijat mengandungi data dari pelbagai fail log sistem, termasuk maklumat peribadi dan sulit. Kongsikan laporan pepijat hanya dengan apl dan orang yang anda percayai."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tunjukkan mesej ini pada masa akan datang"</string>
+</resources>
diff --git a/packages/Shell/res/values-zh-rHK/strings.xml b/packages/Shell/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..b5f1935
--- /dev/null
+++ b/packages/Shell/res/values-zh-rHK/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3701846017049540910">"命令介面"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"已擷取錯誤報告"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"輕觸即可分享您的錯誤報告"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"錯誤報告中有來自系統各個記錄檔案的資料,包括個人和私人資料。請只與您信任的應用程式和用戶分享錯誤報告。"</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"下次再顯示這則訊息"</string>
+</resources>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 5e198a2..fa5c769 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -189,6 +189,35 @@
android:taskAffinity="com.android.systemui.net"
android:excludeFromRecents="true" />
+ <!-- platform logo easter egg activity -->
+ <activity
+ android:name=".DessertCase"
+ android:exported="true"
+ android:label="@string/dessert_case"
+ android:theme="@android:style/Theme.Wallpaper.NoTitleBar.Fullscreen"
+ android:hardwareAccelerated="true"
+ android:launchMode="singleInstance"
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="com.android.internal.category.PLATLOGO" />
+ </intent-filter>
+ </activity>
+
+ <!-- a gallery of delicious treats -->
+ <service
+ android:name=".DessertCaseDream"
+ android:exported="true"
+ android:label="@string/dessert_case"
+ android:enabled="false"
+ >
+ <intent-filter>
+ <action android:name="android.service.dreams.DreamService" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </service>
+
<activity android:name=".Somnambulator"
android:label="@string/start_dreams"
android:icon="@mipmap/ic_launcher_dreams"
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
index 3ed7418..2d8d074 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_0.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_0.png
index df727e5..beb0e05 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_15.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_15.png
index 228f59a..603fff1 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_15.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_15.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_15.png
index 3965162..0d01eb5 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_15.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_battery_charge_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1.png
index 645ee4a..b226694 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1x.png
index 933a6a31..cbabd61 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1x.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_2.png
index 24d26c3..1e9fbfd 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3.png
index b1cd0e3..0676919 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3g.png
index 4497b2c..12569d1 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3g.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4.png
index def0e23..3ad9e76 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4g.png
index ddba025..7d5f6d0 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4g.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_e.png
index 6fba6a9..2102263 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_lte.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_lte.png
index 1fcf26a..9dfde67 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_lte.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_r.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_r.png
index 5f38821..4fea255 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_r.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_full_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_g.png
index e4c17d1..fa905cc 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_g.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_h.png
index 4757856..5b5b5d2 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_h.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_in.png
new file mode 100644
index 0000000..6ff215b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_inout.png
new file mode 100644
index 0000000..cf5e825
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_lte.png
index 452c875..5128c0d 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_lte.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_out.png
new file mode 100644
index 0000000..5d8fd07
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_r.png
index 7c86303..da77a35 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_r.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_1.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_1.png
index ac66075..c500691 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_2.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_2.png
index 0a49702..ae87896 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_3.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_3.png
index 380b1eb..e47ef7a 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_4.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_4.png
index 756ff1f..9fd1ae6 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_4.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_in.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_in.png
new file mode 100644
index 0000000..ebd2001
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_inout.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_inout.png
new file mode 100644
index 0000000..cf5e825
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_out.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_out.png
new file mode 100644
index 0000000..5d8fd07
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
index 8907055..873ca7e 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
index 02fd1043..288d36a 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.png
index 2e5dc3c..1233fca 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_small.png
index a8f4daa..6768c1f 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_small.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_small.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/search_light.png b/packages/SystemUI/res/drawable-hdpi/search_light.png
index c8b5a2e..9a8f771 100644
--- a/packages/SystemUI/res/drawable-hdpi/search_light.png
+++ b/packages/SystemUI/res/drawable-hdpi/search_light.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_15.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_15.png
index c779e7e..c971443 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_15.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index 073f285..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index 83759be..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png
deleted file mode 100644
index bec5e3b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index cbf2cc7..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index 90cb8c3..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index 24d0606..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_lte.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_lte.png
deleted file mode 100644
index 1b1ac75..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_lte.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_roam.png
deleted file mode 100644
index 1e66cb9..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..be38df8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
deleted file mode 100644
index cf07aae..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
deleted file mode 100644
index 50aa77f..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
deleted file mode 100644
index 045182c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
deleted file mode 100644
index 5232169..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
deleted file mode 100644
index 2b0da2c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
deleted file mode 100644
index 24755d9..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
deleted file mode 100644
index 3f30896..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
deleted file mode 100644
index 87da72b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
index eeee60f..42c773d 100644
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1.png
index 77a19d3..b6388e1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1x.png
index 22c5c28..969bff4 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1x.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_2.png
index a326de5..610a018 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_2.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3.png
index 38f9800..badebf5 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3g.png
index 53bb5d9..ff96e40 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4.png
index 12a803a..52c9a74 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4g.png
index f9ade7dc..312a384 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_e.png
index f1c5a39..1211e0d 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_e.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_g.png
index cba3eb6..b65abc6 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_h.png
index e850f9e..08e21d2 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_h.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_lte.png
index 8d17c77..464ebbc 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_lte.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_r.png
index 79e1bdf..37da1f4 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_r.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
index 8966a10..3f7c4b0 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
index 950b136..956bb7c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index 60a7341..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index 23b47b6..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_4g.png
deleted file mode 100644
index 6601913..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index 2334bfc..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index b410ee1..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index 91810f8..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_lte.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_lte.png
deleted file mode 100644
index 6a7eb08..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_lte.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_roam.png
deleted file mode 100644
index 1c69293..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..ffb58ca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_1.png
deleted file mode 100644
index 395adad..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_2.png
deleted file mode 100644
index 4ded9239..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_3.png
deleted file mode 100644
index 568c296..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_4.png
deleted file mode 100644
index 000f93d..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1.png
index dcb1883..7116084 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1x.png
index a28924b..8596aa6 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1x.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_2.png
index c5c57ea..1b81c42 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_2.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3.png
index 31c8d23..03591c2a 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3g.png
index 72329b9..ee72967 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4.png
index a39bdd2..162315c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4g.png
index 3639c5a..c472f2b 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_e.png
index 4faaadb..e4bf4e2 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_e.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_g.png
index 345f84d..98b0104 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_h.png
index ac51151..fc19c7a 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_h.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_lte.png
index e176db4..2250282 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_lte.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_r.png
index e69d5c2..8290e1b 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_r.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
index 2abd625..a53aef1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
index d79612a..e1b2145 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index 7f0e705..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index b4ee3ff..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_4g.png
deleted file mode 100644
index 38e009f..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index 8cb3f6a..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index bc68ae6..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index 65bc672..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_lte.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_lte.png
deleted file mode 100644
index a3c5aca..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_lte.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_roam.png
deleted file mode 100644
index 7234f40..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..c54ceba
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_1.png
deleted file mode 100644
index 33a35d0..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_3.png
deleted file mode 100644
index b61b1e0..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_4.png
deleted file mode 100644
index 7121abb..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
index 7a84631..2d8f81d 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
index 4be4846..61c6d11 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
index d8fac96..90eece6 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
index 1024af9..382cf23 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
index 3db8fdec..a4b3b37 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
index 8e797e1..ee5f623 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
index f6fc8cc..3d21350 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
index 7bf7104..40fbaec 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1.png
index 132578d..a5d68e1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1x.png
index 2120f88..69d0461 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1x.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_2.png
index 0b2ea16..df0948b 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_2.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3.png
index d25059d..4409267 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3g.png
index 31a0e35..de0181b 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4.png
index f892855..c3e4181 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4g.png
index bb34c49..69a950d 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_e.png
index 116113c..04948ae 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_e.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_g.png
index b8d8b57..a6b0393 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_h.png
index e2bbd8f..ede64f1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_h.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_lte.png
index 7711b18..e82ba13 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_lte.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_r.png
index fcec4f1..83e7206 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_r.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
index d295762..61b4569 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
index 9f47cc0..1a0312b 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index fe0bb54..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index d9f6f33..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_4g.png
deleted file mode 100644
index 75bb86a..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index 0318f1a..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index ef2f061..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index 6fbcc0e..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_lte.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_lte.png
deleted file mode 100644
index 1b6f7f5..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_lte.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_roam.png
deleted file mode 100644
index 2ccb681..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..d8db235
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_1.png
deleted file mode 100644
index ef91328..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_2.png
deleted file mode 100644
index ffb3b55..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_3.png
deleted file mode 100644
index 85eef22..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_4.png
deleted file mode 100644
index 5aeb913..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_1.png
index 1ff23af..19809c2 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_1.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_1x.png
index d882f50..cd34141 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_1x.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_2.png
index 4e385f3..5691f96 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_2.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_3.png
index bbcaebb..56768dd 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_3.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_3g.png
index dce2662..094d4ca 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_3g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_4.png
index c00d65c..55ec5b8 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_4.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_4g.png
index 3aba174..f92aac2 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_4g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_e.png
index e38507a..4329b67 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_e.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_g.png
index 21fbc0b..3577fbb 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_g.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_h.png
index d9d395f..0aae48b 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_h.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_lte.png
index 5b428a0..2d2b106 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_lte.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_r.png
index f29a478..a2003fc 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_r.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
index b680ddb..8715a11 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
index f969d05..487a0b1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index 6ba908b..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index c4de9e5..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_4g.png
deleted file mode 100644
index c5b5ec3..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index 80d8b40..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index 03377e2..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index 4dca8f2..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_lte.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_lte.png
deleted file mode 100644
index 9d3346fb..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_lte.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_roam.png
deleted file mode 100644
index dd0d6b5..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..cc6155f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_1.png
deleted file mode 100644
index dc4a01e..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_2.png
deleted file mode 100644
index bb6fd30..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_3.png
deleted file mode 100644
index b77c833..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_4.png
deleted file mode 100644
index 448d79b..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png
index 44cfc5b..399db00 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_0.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_0.png
index b6bfbdb..8dd3d4d 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_15.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_15.png
index 2a1637c..f59ba48 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_15.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_15.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_15.png
index cee2a44..86d1158 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_15.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_battery_charge_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1.png
index ae51eca..2994632 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1x.png
index 172c2dc..a89191f 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_2.png
index 77dcdce..b111939 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_2.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3.png
index aff279c..98c8e25 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3g.png
index 645652a..8a8e323 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4.png
index e64d314..625dbd9 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4g.png
index a871458..c1063a9 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4g.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_e.png
index e9ae1f1..f145410 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_lte.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_lte.png
index 7d156fe..da8ebce 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_lte.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_r.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_r.png
index 739fe7c..776210b 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_r.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_full_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_g.png
index d0fedcc..a5de26f 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_h.png
index f717dc8..b3d4524 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_in.png
new file mode 100644
index 0000000..da4ffa2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_inout.png
new file mode 100644
index 0000000..e1c7972
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_lte.png
index 3e8637b..0555eed 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_lte.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_out.png
new file mode 100644
index 0000000..b8c8b4e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_r.png
index 17a9ddb..f1753d6 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_r.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_1.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_1.png
index cafb93d..60e38ad 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_1.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_2.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_2.png
index 55eccf0..8983380 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_2.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_3.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_3.png
index 989427b..ff652df 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_3.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_4.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_4.png
index f2d7963..8dd9c43 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_4.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_in.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_in.png
new file mode 100644
index 0000000..5d0ad7c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_inout.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_inout.png
new file mode 100644
index 0000000..e1c7972
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_out.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_out.png
new file mode 100644
index 0000000..b8c8b4e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
index 457be69..225d924 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
index d232bf4..37d17d2 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.png
index 45183b0..4d9c21c 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_small.png
index 8169fba..9f0570a 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_small.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_small.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/search_light.png b/packages/SystemUI/res/drawable-mdpi/search_light.png
index 4b5b2a4..c355b6a 100644
--- a/packages/SystemUI/res/drawable-mdpi/search_light.png
+++ b/packages/SystemUI/res/drawable-mdpi/search_light.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_15.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_15.png
index 62807cd..b1b675b 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_15.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index a4c7ed0e..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index 11e4762f..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png
deleted file mode 100644
index 503e155..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index 2be8a4f..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index 8efc4ed..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index e691780..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_lte.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_lte.png
deleted file mode 100644
index df01445..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_lte.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_roam.png
deleted file mode 100644
index 0bc6e31..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..fb2a6b6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
deleted file mode 100644
index c3c6b93..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
deleted file mode 100644
index bb2e9ba..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
deleted file mode 100644
index 6583922..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
deleted file mode 100644
index 9b1cbcc..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
deleted file mode 100644
index 3fb4427..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
deleted file mode 100644
index abcc317..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
deleted file mode 100644
index a3b2678..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
deleted file mode 100644
index b4278f2..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png
index c73ff35..20c8785 100644
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
index 6a9e91d3..3361e34 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
index 4174a04..b380327 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight.png
index 202c8bc..8014b70 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight_land.png
index 31bc09c..41a34e2 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.png
index 5e8e7f6..11e3b65 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_small.png
index 3529974..afcc487 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_small.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_small.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
index 7928440..0ec4d23 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
index 878bead..e55f2bf 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight.png
index bef6de3..9c623e5 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight_land.png
index 406eeab..a011aa1 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.png
index 1849a53a..24442343 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_small.png
index c5fe4df..a3e32f4c 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_small.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_small.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
index 18d10c7..8aa6e3a 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
index 3baf867..bf68b22 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight.png
index 75b5fbb..61a36e3 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight_land.png
index a7a4ce3..52bf290 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.png
index f079b85..298b62f 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_small.png
index fa5f001..41f4b42 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_small.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_small.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
index c78258a..7e96395e 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
index 5c15315..382ef39 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight.png
new file mode 100644
index 0000000..e5d4273
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight_land.png
new file mode 100644
index 0000000..1cc5009
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_large.png
new file mode 100644
index 0000000..5ef7798
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_small.png
new file mode 100644
index 0000000..4a98e31
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_small.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png
index 80fdb79..c0032e2 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_0.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_0.png
index b6e7a3f..ff3bdf0 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_0.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_15.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_15.png
index 9895f71..39fccc8 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_15.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_15.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_15.png
index e3c6920..1a595ed 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_15.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_battery_charge_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1.png
index 3bbfb4e..abc9358 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1x.png
index 91bbde6..f88e3a4 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1x.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_2.png
index 7fc9bd4..0419144 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_2.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3.png
index 56a9a13..515ffe7 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3g.png
index 7443e63..9aff8aa 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3g.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4.png
index ad06e62..118de2d 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4g.png
index 747fa74..2e00303 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4g.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_e.png
index 823fe8a..33ae551 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_e.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_lte.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_lte.png
index 41c1577..4212e49 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_lte.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_r.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_r.png
index 2baa0f3..2176a88 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_r.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_full_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_g.png
index f38a0a9..fb09a26 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_g.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_h.png
index 5c2bc16..b52aec7 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_h.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_in.png
new file mode 100644
index 0000000..46fd826
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_inout.png
new file mode 100644
index 0000000..c824b97
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_lte.png
index f6359fc..9942e7a 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_lte.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_out.png
new file mode 100644
index 0000000..fb9ecd0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_r.png
index cc426bb..1efdebf 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_r.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_1.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_1.png
index 94666a1..715e60a 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_1.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_2.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_2.png
index 8e19afd..ed7f5b9 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_2.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_3.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_3.png
index 62933b0..8f1464b 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_3.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_4.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_4.png
index e93292b..b32c676 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_4.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_in.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_in.png
new file mode 100644
index 0000000..6cf0a4b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_inout.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_inout.png
new file mode 100644
index 0000000..c824b97
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_out.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_out.png
new file mode 100644
index 0000000..fb9ecd0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
index 4c40ff2..a2bb50a 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
index 337a347b..aaeeb1b 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.png
index ee5eed8..e62dece 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_small.png
index b434fc4..958b2fe 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_small.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_small.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/search_light.png b/packages/SystemUI/res/drawable-xhdpi/search_light.png
index 3aa890f..68b70eb 100644
--- a/packages/SystemUI/res/drawable-xhdpi/search_light.png
+++ b/packages/SystemUI/res/drawable-xhdpi/search_light.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_15.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_15.png
index 1e68ac7..94605c9 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_15.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index 33c2b82..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index 7a1d8d6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_4g.png
deleted file mode 100644
index 554953a..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index b9e3b88..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index 137f76e4..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index e8b6d40..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_lte.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_lte.png
deleted file mode 100644
index 227a105..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_lte.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_roam.png
deleted file mode 100644
index bdaafc9..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..5228c29
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1.png
deleted file mode 100644
index 23288de..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2.png
deleted file mode 100644
index 32e05fe..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3.png
deleted file mode 100644
index f2f88a1..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4.png
deleted file mode 100644
index 7a38994..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_1.png
deleted file mode 100644
index a93e3a8..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_2.png
deleted file mode 100644
index 24b47b2..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_3.png
deleted file mode 100644
index b4b3f02..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_4.png
deleted file mode 100644
index 758ebe7..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png
index e931314..b4e129c 100644
--- a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png
+++ b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png
new file mode 100644
index 0000000..a3cc08d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_0.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_0.png
index ef177a6..6ddf734 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_0.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_15.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_15.png
index 0a46dde..e1e1b2e 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_15.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_15.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_15.png
index 96d39db..3b36bb9 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_15.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_1.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_1.png
index 4a243ca..746b9ea 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_1.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_1x.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_1x.png
index ad82980..6706ae2 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_1x.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_2.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_2.png
index 37841af..55ba5ab 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_2.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_3.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_3.png
index 39be463..547f875 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_3.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_3g.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_3g.png
index 61ebf83..4d1dc75 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_3g.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_4.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_4.png
index 5b9b7af..1f65ad5 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_4.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_4g.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_4g.png
index b7e29a9..aab9d27 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_4g.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_e.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_e.png
index b7c1c01..cd92c5f 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_e.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_lte.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_lte.png
index 058fca8..0dc66b4 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_lte.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_r.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_r.png
index 0d61683..b60cda6 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_r.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_full_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_g.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_g.png
index dfeafd5..b686376 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_g.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_h.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_h.png
index 031dd86..bfe2271 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_h.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_in.png
new file mode 100644
index 0000000..1094bc3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_inout.png
new file mode 100644
index 0000000..1037b02
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_lte.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_lte.png
index 468c8ee..b5def3e 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_lte.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_lte.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_out.png
new file mode 100644
index 0000000..f5595e3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_r.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_r.png
index bf459e8..60e2bd3 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_r.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_r.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_1.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_1.png
index 10818ba..01274a6 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_1.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_2.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_2.png
index 752fee1..a02832d 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_2.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_3.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_3.png
index 684372a..7e55bbb 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_3.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_4.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_4.png
index 9b4b8c7..eeb8989 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_4.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_in.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_in.png
new file mode 100644
index 0000000..7183a07
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_inout.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_inout.png
new file mode 100644
index 0000000..3746328
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_out.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_out.png
new file mode 100644
index 0000000..dbf54ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
index 03aa648..79cfcee 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
index f9ba76f..c3bfcfb 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_large.png
new file mode 100644
index 0000000..55a266f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_large.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_small.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_small.png
new file mode 100644
index 0000000..97d1fbc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_small.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg.9.png
new file mode 100644
index 0000000..a446448
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/search_light.png b/packages/SystemUI/res/drawable-xxhdpi/search_light.png
new file mode 100644
index 0000000..faa97f8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/search_light.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_15.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_15.png
index d026936..a2bab6d 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_15.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_battery_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_1x.png
deleted file mode 100644
index 9baa623..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_1x.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_3g.png
deleted file mode 100644
index af3a0d9..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_3g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_4g.png
deleted file mode 100644
index 717895b..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_4g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_e.png
deleted file mode 100644
index 989b236..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_e.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_g.png
deleted file mode 100644
index 49cce0d..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_g.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_h.png
deleted file mode 100644
index caa5552..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_h.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_lte.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_lte.png
deleted file mode 100644
index a0beb07..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_lte.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_roam.png
deleted file mode 100644
index 9cc3184..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_connected_roam.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_roam.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_roam.png
new file mode 100644
index 0000000..1f8549e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_data_fully_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_1.png
deleted file mode 100644
index afacef5..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_2.png
deleted file mode 100644
index 1b1c863..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_3.png
deleted file mode 100644
index 99094e3..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_4.png
deleted file mode 100644
index 8aff999..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_1.png
deleted file mode 100644
index 3fe77d0..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_2.png
deleted file mode 100644
index dec522d..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_3.png
deleted file mode 100644
index 9e679c2..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_3.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_4.png
deleted file mode 100644
index f4c7250..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_wifi_signal_4.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml b/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
index 34506b1..cabfaa5 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
@@ -13,32 +13,49 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout
+<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_gravity="top"
- android:orientation="vertical">
+ android:layout_gravity="top">
<FrameLayout
+ android:id="@+id/rssi_images"
android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
android:layout_width="@dimen/qs_tile_icon_size"
android:layout_height="@dimen/qs_tile_icon_size"
android:layout_gravity="top|center_horizontal"
+ android:layout_centerHorizontal="true"
>
<ImageView
android:id="@+id/rssi_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
+ android:layout_centerInParent="true"
/>
<ImageView
android:id="@+id/rssi_overlay_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
+ android:layout_centerInParent="true"
/>
</FrameLayout>
+ <ImageView
+ android:id="@+id/activity_in"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_qs_signal_in"
+ android:layout_toRightOf="@id/rssi_images"
+ android:layout_alignBottom="@id/rssi_images"
+ />
+ <ImageView
+ android:id="@+id/activity_out"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_qs_signal_out"
+ android:layout_toRightOf="@id/rssi_images"
+ android:layout_alignBottom="@id/rssi_images"
+ />
<TextView
style="@style/TextAppearance.QuickSettings.TileView"
android:id="@+id/rssi_textview"
@@ -47,5 +64,7 @@
android:layout_gravity="top|center_horizontal"
android:gravity="top|center_horizontal"
android:text="@string/quick_settings_rssi_label"
+ android:layout_centerHorizontal="true"
+ android:layout_below="@id/rssi_images"
/>
-</LinearLayout>
\ No newline at end of file
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
new file mode 100644
index 0000000..e61c595
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="top">
+ <ImageView
+ android:id="@+id/image"
+ android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
+ android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
+ android:layout_width="@dimen/qs_tile_icon_size"
+ android:layout_height="@dimen/qs_tile_icon_size"
+ android:layout_gravity="top|center_horizontal"
+ android:layout_centerHorizontal="true"
+ android:scaleType="centerInside"
+ />
+ <ImageView
+ android:id="@+id/activity_in"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_qs_wifi_in"
+ android:layout_toRightOf="@id/image"
+ android:layout_alignBottom="@id/image"
+ />
+ <ImageView
+ android:id="@+id/activity_out"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_qs_wifi_out"
+ android:layout_toRightOf="@id/image"
+ android:layout_alignBottom="@id/image"
+ />
+ <TextView
+ style="@style/TextAppearance.QuickSettings.TileView"
+ android:id="@+id/text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center_horizontal"
+ android:gravity="top|center_horizontal"
+ android:layout_centerHorizontal="true"
+ android:layout_below="@id/image"
+ />
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 28128da..a1a2ee5 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netwerk kan dalk gemonitor word"</string>
- <string name="done_button" msgid="1759387181766603361">"Klaar"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Netwerkmonitering"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Hierdie toestel word bestuur deur: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nJou administrateur kan jou netwerkaktiwiteit monitor, insluitend e-pos, programme en veilige webwerwe.\n\nKontak jou administrateur vir meer inligting."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"\'n Derdeparty kan jou netwerk\n-aktiwiteit monitor, insluitend e-pos, programme en veilige webwerwe.\n\n\'n Vertroude eiebewys wat op jou toestel geïnstalleer is, maak dit moontlik."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Gaan vertroude eiebewyse na"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 40479b5..f56d200 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ብሩህነት"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ራስ-ሰር"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"አውታረ መረብ በክትትል ውስጥ ሊሆን ይችላል"</string>
- <string name="done_button" msgid="1759387181766603361">"ተከናውኗል"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"የአውታረ መረብ ክትትል"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"መሳሪያው የሚተዳደረው፦ በ<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>። \n\nአስተዳዳሪዎ ኢሜይሎችዎን፣ መተግበሪያዎችዎን እና ደህንነታቸው አስተማማኝ የሆኑ ድር ጣቢያዎችን ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ይችላል።\n\nለተጨማሪ መረጃ አስተዳዳሪዎን ያግኙ።"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"ሶስተኛ ወገን ኢሜይሎችዎን፣ መተግበሪያዎችዎን እና ደህንነታቸው አስተማማኝ የሆኑ\nድር ጣቢያዎችን ጨምሮ አውታረ መረብ እንቅስቃሴዎን መከታተል ይችላል።\n\nበመሳሪያዎ ላይ የተጫነ የታመነ ምስክርነት ይህን የሚቻል አድርጎታል።"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"የታመኑ ምስክርነቶችን ይፈትሹ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 93a9164..3c709e4 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"السطوع"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"تلقائي"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"قد تكون الشبكة مراقبة"</string>
- <string name="done_button" msgid="1759387181766603361">"تم"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"مراقبة الشبكات"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"هذا الجهاز يديره: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nيستطيع مشرفك مراقبة أنشطة الشبكة بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب الآمنة.\n\nللمزيد من المعلومات، اتصل بالمشرف."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"بإمكان الطرف الثالث مراقبة أنشطة\nالشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب الآمنة.\n\nوتجعل بيانات الاعتماد الموثوق فيها والمثبتة على جهازك حدوث هذا ممكنًا."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"التحقق من بيانات الاعتماد الموثوق فيها"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az-rAZ-land/strings.xml b/packages/SystemUI/res/values-az-rAZ-land/strings.xml
new file mode 100644
index 0000000..8eb6978
--- /dev/null
+++ b/packages/SystemUI/res/values-az-rAZ-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"Hazırda ekran landşaft orientasiyasında kilidlənib."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index eb455c1..b379bab 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -204,14 +204,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АЎТА"</string>
<!-- no translation found for ssl_ca_cert_warning (5848402127455021714) -->
<skip />
- <!-- no translation found for done_button (1759387181766603361) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_dialog_title (1273796967092027291) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_info_message (5430320539555358452) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_warning_message (2033091656129963669) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_settings_button (7946956977377166709) -->
- <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index e839143..5d2f249 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркост"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТ."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежата може да се наблюдава"</string>
- <string name="done_button" msgid="1759387181766603361">"Готово"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Наблюдение на мрежата"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Това устройство се управлява от: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nАдминистраторът ви може да наблюдава активността ви в мрежата, включително имейлите, приложенията и сигурните уебсайтове.\n\nЗа повече информация се свържете с него."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Трета страна може да наблюдава активността ви в\nмрежата, включително имейлите, приложенията и сигурните уебсайтове.\n\nТова е възможно благодарение на инсталирани на устройството ви надеждни идентификационни данни."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Проверка на надеждните идентификационни данни"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index f3b7714..e0ed9fb 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillantor"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÀTICA"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Pot ser que la xarxa se supervisi."</string>
- <string name="done_button" msgid="1759387181766603361">"Fet"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Supervisió de xarxes"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g> administra aquest dispositiu.\n\nEl teu administrador té capacitat per supervisar la teva activitat de xarxa, inclosos els correus electrònics, les aplicacions i els llocs web segurs.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Un tercer té la capacitat per supervisar la teva activitat de\nxarxa, inclosos els correus electrònics, les aplicacions i els llocs web segurs.\n\nHi ha una credencial de confiança instal·lada que fa que això sigui possible."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Comprova les credencials de confiança"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 5977c35..0b0597a 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jas"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Síť může být monitorována"</string>
- <string name="done_button" msgid="1759387181766603361">"Hotovo"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Monitorování sítě"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Toto zařízení je spravováno doménou <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nSprávce může monitorovat aktivitu v síti, včetně e-mailů, aplikací a zabezpečených webů.\n\nChcete-li získat další informace, kontaktujte svého správce."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Vaše aktivita v síti, včetně e-mailů, aplikací a zabezpečených\nwebových stránek může být monitorována třetí stranou.\n\nUmožňují to důvěryhodné identifikační údaje nainstalované ve vašem zařízení."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Zkontrolovat důvěryhodné identifikační údaje"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 08c42d0..e502b26 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netværket kan være overvåget"</string>
- <string name="done_button" msgid="1759387181766603361">"Udfør"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Overvågning af netværk"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Denne enhed er administreret af: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nDin administrator kan overvåge dine netværksaktiviteter, f.eks. e-mails, apps og sikre websites.\n\nFå flere oplysninger ved at kontakte din administrator."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"En tredjepart kan overvåge dine netværksaktiviteter, \nf.eks.e-mails, apps og sikre websites.\n\nBetroede loginoplysninger, der er installeret på din enhed, gør dette muligt."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Kontrollér betroede loginoplysninger"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 8b52a11..17b425b 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helligkeit"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Das Netzwerk wird möglicherweise überwacht."</string>
- <string name="done_button" msgid="1759387181766603361">"Fertig"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Netzwerküberwachung"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Dieses Gerät wird von <xliff:g id="MANAGING_DOMAIN">%s</xliff:g> verwaltet.\n\nIhr Administrator kann Ihre Netzwerkaktivitäten überwachen, einschließlich E-Mails, Apps und sicheren Websites.\n\nWenden Sie sich für weitere Informationen an Ihren Administrator."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Dritte können Ihre Netzwerkaktivitäten\nüberwachen, einschließlich E-Mails, Apps und sicheren Websites.\n\nDies wird durch vertrauenswürdige Anmeldedaten ermöglicht, die auf Ihrem Gerät installiert sind."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Vertrauenswürdige Anmeldedaten überprüfen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index c437eb6..43b9cbc 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Φωτεινότητα"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ΑΥΤΟΜΑΤΗ"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
- <string name="done_button" msgid="1759387181766603361">"Τέλος"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Παρακολούθηση δικτύου"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Η συσκευή αυτή διαχειρίζεται από: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nΟ διαχειριστής σας έχει τη δυνατότητα παρακολούθησης της δραστηριότητας δικτύου, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ασφαλών ιστότοπων.\n\nΓια περισσότερες πληροφορίες επικοινωνήστε με το διαχειριστή σας."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Ένα τρίτο μέρος έχει δυνατότητα παρακολούθησης της δραστηριότητας\nδικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ασφαλών ιστότοπων.\n\nΈνα αξιόπιστο διαπιστευτήριο που έχει εγκατασταθεί στη συσκευή σας επιτρέπει κάτι τέτοιο."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Ελέγξτε τα αξιόπιστα διαπιστευτήρια"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 5255c44..8a16d7c 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Network may be monitored"</string>
- <string name="done_button" msgid="1759387181766603361">"Finished"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Network Monitoring"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"This device is managed by: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"A third party is capable of monitoring your network\nactivity, including emails, apps and secure websites.\n\nA trusted credential installed on your device is making this possible."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Check trusted credentials"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN-land/strings.xml b/packages/SystemUI/res/values-en-rIN-land/strings.xml
new file mode 100644
index 0000000..ba773b8
--- /dev/null
+++ b/packages/SystemUI/res/values-en-rIN-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"Screen is now locked in landscape orientation."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 5255c44..8a16d7c 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Network may be monitored"</string>
- <string name="done_button" msgid="1759387181766603361">"Finished"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Network Monitoring"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"This device is managed by: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"A third party is capable of monitoring your network\nactivity, including emails, apps and secure websites.\n\nA trusted credential installed on your device is making this possible."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Check trusted credentials"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index f5b2df7..1aed7dc 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Es posible que la red esté supervisada."</string>
- <string name="done_button" msgid="1759387181766603361">"Listo"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Supervisión de red"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Este dispositivo es administrado por: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nEl administrador puede supervisar la actividad de la red, incluidos los mensajes de correo electrónico, las aplicaciones y los sitios web seguros.\n\nPara obtener más información, comunícate con el administrador."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Un tercero puede supervisar la actividad de la red,\nincluidos los mensajes de correo electrónico, las aplicaciones y los sitios web seguros.\n\nEsto es posible debido a que hay una credencial de confianza instalada en el dispositivo."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Comprobar credenciales de confianza"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index b81b487..5386842 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Es posible que la red esté supervisada"</string>
- <string name="done_button" msgid="1759387181766603361">"Listo"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Supervisión de red"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Este dispositivo está administrado por: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nTu administrador puede supervisar la actividad de la red, incluidos los mensajes de correo electrónico, las aplicaciones y los sitios web seguros.\n\nPara obtener más información, ponte en contacto con tu administrador."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Un tercero puede supervisar la actividad de la\nred, incluidos los mensajes de correo electrónico, las aplicaciones y los sitios web seguros.\n\nEsto es posible por una credencial de confianza instalada en tu dispositivo."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Comprobar credenciales de confianza"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et-rEE-land/strings.xml b/packages/SystemUI/res/values-et-rEE-land/strings.xml
new file mode 100644
index 0000000..77b0ce1
--- /dev/null
+++ b/packages/SystemUI/res/values-et-rEE-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"Ekraan on nüüd lukustatud horisontaalasendisse."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 69da334..335feaa 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Heledus"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAATNE"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Võrku võidakse jälgida"</string>
- <string name="done_button" msgid="1759387181766603361">"Valmis"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Võrgu jälgimine"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Seadet haldab: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nVõrguadministraator saab jälgida teie võrgutoiminguid, sh meile, rakendusi ja turvalisi veebisaite.\n\nLisateabe saamiseks võtke ühendust administraatoriga."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Kolmas osapool saab jälgida teie\nvõrgutoiminguid, sh meile, rakendusi ja turvalisi veebisaite.\n\nSeda võimaldab teie seadmesse installitud usaldusväärne mandaat."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Kontrolli usaldusväärseid mandaate"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 412e749..489b654 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"روشنایی"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"خودکار"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ممکن است شبکه نظارت شده باشد"</string>
- <string name="done_button" msgid="1759387181766603361">"انجام شد"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"پایش شبکه"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"این دستگاه توسط: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g> مدیریت میشود.\n\nسرپرست شما میتواند فعالیتتان را در شبکه نظارت کند، از جمله ایمیلها، برنامهها، و وبسایتهای ایمن.\n\nبرای کسب اطلاعات بیشتر، با سرپرستتان تماس بگیرید."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"یک شخص ثالث قادر به نظارت بر فعالیت\nشبکه شما، از جمله ایمیلها، برنامهها، و وبسایتهای ایمن است.\n\nیک اعتبارنامه قابل اعتماد نصب شده بر روی دستگاهتان این کار را امکانپذیر میکند."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"بررسی اعتبارنامههای قابل اعتماد"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index dbd228e..852ec08 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kirkkaus"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Verkkoa saatetaan valvoa"</string>
- <string name="done_button" msgid="1759387181766603361">"Valmis"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Verkon valvonta"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Tämän laitteen hallinnoija: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nJärjestelmänvalvoja pystyy valvomaan toimiasi verkossa, esimerkiksi sähköpostin, sovellusten ja turvallisten verkkosivustojen käyttöä.\n\nSaat lisätietoja järjestelmänvalvojalta."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Kolmas osapuoli pystyy valvomaan toimiasi verkossa,\n esimerkiksi sähköpostin, sovellusten ja turvallisten verkkosivustojen käyttöä.\n\nLaitteeseesi asennetut luotetut käyttöoikeustiedot tekevät tämän mahdolliseksi."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Tarkista luotetut käyttöoikeustiedot"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA-land/strings.xml b/packages/SystemUI/res/values-fr-rCA-land/strings.xml
new file mode 100644
index 0000000..4775fc6
--- /dev/null
+++ b/packages/SystemUI/res/values-fr-rCA-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"L\'écran est désormais verrouillé au format paysage."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 6071659..48f62d3 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Le réseau peut être surveillé"</string>
- <string name="done_button" msgid="1759387181766603361">"Terminé"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Surveillance réseau"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Cet appareil est géré par : <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nVotre administrateur est en mesure de surveiller l\'activité de votre réseau, y compris les courriels, les applications et les sites Web sécurisés.\n\nPour obtenir plus d\'information à ce sujet, communiquez avec votre administrateur."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Un tiers peut surveiller votre activité réseau,\n y compris les courriels, les applications et les sites Web sécurisés.\n\nUn certificat de confiance installé sur votre appareil rend cela possible."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Vérifier les certificats de confiance"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 4982ed3..2af370b 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Il est possible que le réseau soit surveillé."</string>
- <string name="done_button" msgid="1759387181766603361">"OK"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Surveillance du réseau"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Cet appareil est géré par <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nVotre administrateur a la possibilité de surveiller votre activité sur le réseau, y compris les e-mails, les applications et les sites Web sécurisés.\n\nPour en savoir plus, veuillez contacter votre administrateur."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Il est possible qu\'un tiers surveille votre activité sur le réseau,\ny compris les e-mails, les applications et les sites Web sécurisés.\n\nCela est dû à la présence d\'un certificat de confiance installé sur votre appareil."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Vérifier les certificats de confiance"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 91d4a96..5256ff0 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -22,12 +22,12 @@
<string name="app_label" msgid="7164937344850004466">"सिस्टम UI"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"साफ़ करें"</string>
<string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"सूची से निकालें"</string>
- <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"एप्लिकेशन जानकारी"</string>
- <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"कोई हाल ही के एप्लिकेशन नहीं"</string>
- <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"हाल ही के एप्लिकेशन खारिज करें"</string>
+ <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"एप्स जानकारी"</string>
+ <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"कोई हाल ही के एप्स नहीं"</string>
+ <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"हाल ही के एप्स खारिज करें"</string>
<plurals name="status_bar_accessibility_recent_apps">
- <item quantity="one" msgid="5854176083865845541">"1 हाल ही का एप्लिकेशन"</item>
- <item quantity="other" msgid="1040784359794890744">"%d हाल ही के एप्लिकेशन"</item>
+ <item quantity="one" msgid="5854176083865845541">"1 हाल ही का एप्स"</item>
+ <item quantity="other" msgid="1040784359794890744">"%d हाल ही के एप्स"</item>
</plurals>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"कोई सूचना नहीं"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ऑनगोइंग"</string>
@@ -40,18 +40,18 @@
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिंग"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"हवाई जहाज मोड"</string>
- <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्क्रीन स्वत: घुमाएं"</string>
+ <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्क्रीन अपनेआप घुमाएं"</string>
<string name="status_bar_settings_mute_label" msgid="554682549917429396">"म्यूट करें"</string>
<string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"स्वत:"</string>
<string name="status_bar_settings_notifications" msgid="397146176280905137">"सूचनाएं"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth टीदर किया गया"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"इनपुट पद्धति सेट करें"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"भौतिक कीबोर्ड"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"एप्लिकेशन <xliff:g id="APPLICATION">%1$s</xliff:g> को USB उपकरण तक पहुंचने दें?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"एप्लिकेशन <xliff:g id="APPLICATION">%1$s</xliff:g> को USB सहायक उपकरण तक पहुंचने दें?"</string>
+ <string name="usb_device_permission_prompt" msgid="834698001271562057">"एप्स <xliff:g id="APPLICATION">%1$s</xliff:g> को USB उपकरण तक पहुंचने दें?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"एप्स <xliff:g id="APPLICATION">%1$s</xliff:g> को USB सहायक उपकरण तक पहुंचने दें?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"जब यह USB उपकरण कनेक्ट किया जाए, तब <xliff:g id="ACTIVITY">%1$s</xliff:g> को खोलें?"</string>
<string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"जब यह USB एसेसरी कनेक्ट की जाए, तब <xliff:g id="ACTIVITY">%1$s</xliff:g> को खोलें?"</string>
- <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"इस USB सहायक उपकरण के साथ कोई भी इंस्टॉल एप्लिकेशन काम नहीं करता. इस सहायक उपकरण के बारे में यहां अधिक जानें: <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"इस USB सहायक उपकरण के साथ कोई भी इंस्टॉल एप्स काम नहीं करता. इस सहायक उपकरण के बारे में यहां अधिक जानें: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB सहायक साधन"</string>
<string name="label_view" msgid="6304565553218192990">"देखें"</string>
<string name="always_use_device" msgid="1450287437017315906">"इस USB उपकरण के लिए डिफ़ॉल्ट रूप से उपयोग करें"</string>
@@ -75,7 +75,7 @@
<string name="accessibility_back" msgid="567011538994429120">"वापस जाएं"</string>
<string name="accessibility_home" msgid="8217216074895377641">"होम"</string>
<string name="accessibility_menu" msgid="316839303324695949">"मेनू"</string>
- <string name="accessibility_recent" msgid="8571350598987952883">"हाल ही के एप्लिकेशन"</string>
+ <string name="accessibility_recent" msgid="8571350598987952883">"हाल ही के एप्स"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धति बटन स्विच करें."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"संगतता ज़ूम बटन."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"छोटी से बड़ी स्क्रीन पर ज़ूम करें."</string>
@@ -144,7 +144,7 @@
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना खारिज की गई."</string>
<string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"सूचना शेड."</string>
<string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"त्वरित सेटिंग."</string>
- <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"हाल ही के एप्लिकेशन."</string>
+ <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"हाल ही के एप्स."</string>
<string name="accessibility_quick_settings_user" msgid="1104846699869476855">"उपयोगकर्ता <xliff:g id="USER">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"मोबाइल <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
@@ -164,7 +164,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारा सेट किया गया स्थान"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"स्थान अनुरोध सक्रिय"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"सभी सूचनाएं साफ़ करें."</string>
- <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"एप्लिकेशन जानकारी"</string>
+ <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"एप्स जानकारी"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"स्क्रीन स्वचालित रूप से घूमेगी."</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"स्क्रीन लैंडस्केप अभिविन्यास में लॉक है."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"स्क्रीन पोर्ट्रेट अभिविन्यास में लॉक है."</string>
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"चमक"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वत:"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"नेटवर्क को मॉनिटर किया जा सकता है"</string>
- <string name="done_button" msgid="1759387181766603361">"पूर्ण"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"नेटवर्क मॉनिटरिंग"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"यह उपकरण <xliff:g id="MANAGING_DOMAIN">%s</xliff:g> के द्वारा प्रबंधित किया जाता है.\n\nआपका व्यवस्थापक आपकी नेटवर्क गतिविधि को, साथ ही ईमेल, एप्लिकेशन, और सुरक्षित वेबसाइटों को मॉनिटर करने में सक्षम है.\n\nअधिक जानकारी के लिए, अपने व्यवस्थापक से संपर्क करें."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"एक तृतीय पक्ष आपकी नेटवर्क\nगतिविधि को, साथ ही ईमेल, एप्लिकेशन, और सुरक्षित वेबसाइटों को मॉनिटर करने में सक्षम है.\n\nआपके उपकरण पर इंस्टॉल किए गए एक विश्वसनीय क्रेडेंशियल के कारण ऐसा हो रहा है."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"विश्वसनीय क्रेडेंशियल की जांच करें"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 92e1b21..84d4111 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Svjetlina"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATSKI"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mreža se možda nadzire"</string>
- <string name="done_button" msgid="1759387181766603361">"Završeno"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Nadzor mreže"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Ovim uređajem upravlja: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nVaš administrator može nadzirati vašu mrežnu aktivnost, uključujući e-poštu, aplikacije i sigurne web-lokacije.\n\nza više informacija kontaktirajte svojeg administratora."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Treća strana može nadzirati vaše mrežne\naktivnosti, uključujući e-poštu, aplikacije i sigurne web-lokacije.\n\nTo omogućuje pouzdana vjerodajnica instalirana na vašem uređaju."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Provjeri pouzdane vjerodajnice"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index ad9c7b7..55a135f 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Fényerő"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"automatikus"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Lehet, hogy a hálózat felügyelt"</string>
- <string name="done_button" msgid="1759387181766603361">"Kész"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Hálózatfelügyelet"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Az eszköz kezelője: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nRendszergazdája képes az Ön hálózati tevékenységének, köztük az e-maileknek, az alkalmazásoknak és a biztonságos webhelyeknek a megfigyelésére.\n\nTovábbi információért forduljon rendszergazdájához."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Egy harmadik fél képes az Ön hálózati\ntevékenységének a megfigyelésére, beleértve az e-maileket, alkalmazásokat és biztonságos webhelyeket.\n\nEgy, az eszközre telepített megbízható tanúsítvány teszi ezt lehetővé."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Megbízható tanúsítványok ellenőrzése"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM-land/strings.xml b/packages/SystemUI/res/values-hy-rAM-land/strings.xml
new file mode 100644
index 0000000..7c0535c
--- /dev/null
+++ b/packages/SystemUI/res/values-hy-rAM-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"Էկրանն այժմ կողպված է հորիզոնական դիրքավորման մեջ:"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 06b897a..ce97d01 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Պայծառություն"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"Ինքնաշխատ"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Ցանցը կարող է վերահսկվել"</string>
- <string name="done_button" msgid="1759387181766603361">"Պատրաստ է"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Ցանցի մշտադիտարկում"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Այս սարքը կառավարվում է <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>-ի կողմից:\n\nՁեր կառավարիչն ի վիճակի է մշտադիտարկել ձեր ցանցային գործունեությունը, այդ թվում՝ նամակները, հավելվածները և անվտանգ կայքերը:\n\nԼրացուցիչ տեղեկությունների համար դիմեք ձեր կառավարչին:"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Երրորդ կողմն ի վիճակի է վերահսկել ձեր ցանցային\nգործունեությունը, այդ թվում՝ նամակները, հավելվածները և անվտանգ կայքերը:\n\nՁեր սարքում տեղադրված վստահելի վկայագրերը տալիս են դրա հնարավորությունը:"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Ստուգել վստահելի վկայագրերը"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 3af3a34..6589ae1 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATIS"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Jaringan mungkin dipantau"</string>
- <string name="done_button" msgid="1759387181766603361">"Selesai"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Pemantauan Jaringan"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Perangkat ini dikelola oleh: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nAdministrator Anda dapat memantau aktivitas jaringan Anda, termasuk email, aplikasi, dan situs web aman.\n\nUntuk informasi selengkapnya, hubungi administrator."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Pihak ketiga dapat memantau aktivitas\njaringan Anda, termasuk email, aplikasi, dan situs web aman.\n\nKredensial tepercaya yang terpasang di perangkat Anda membuatnya dapat dilakukan."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Periksa kredensial tepercaya"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index d936e5f..2aaa1e7 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosità"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"La rete potrebbe essere monitorata"</string>
- <string name="done_button" msgid="1759387181766603361">"Fine"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Monitoraggio rete"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Questo dispositivo è gestito da: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nIl tuo amministratore è in grado di monitorare l\'attività della rete, inclusi siti web sicuri, email e app.\n\nPer ulteriori informazioni, contatta il tuo amministratore."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Una terza parte è in grado di monitorare l\'attività della\nrete, inclusi siti web sicuri, email e app.\n\nCiò è reso possibile da una credenziale attendibile installata sul dispositivo."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Verifica credenziali attendibili"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 3b5080e..668c77a 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"בהירות"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"אוטומטי"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ייתכן שהרשת מנוטרת"</string>
- <string name="done_button" msgid="1759387181766603361">"בוצע"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"ניטור רשתות"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"המכשיר הזה מנוהל על ידי: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nמנהל המערכת שלך יכול לנטר את הפעילות ברשת, כולל דוא\"ל, אפליקציות ואתרים מאובטחים.\n\nלמידע נוסף, צור קשר עם מנהל המערכת שלך."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"צד שלישי יכול לנטר את הפעילות שלך\nברשת, כולל דוא\"ל, אפליקציות ואתרים מאובטחים.\n\nפרטי כניסה מהימנים המותקנים במכשיר שלך מאפשרים זאת."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"בדוק פרטי כניסה מהימנים"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index f42dd16..0451117 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"画面の明るさ"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ネットワークが監視される場合があります"</string>
- <string name="done_button" msgid="1759387181766603361">"完了"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"ネットワーク監視"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"この端末は<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>によって管理されています。\n\n管理者はあなたのネットワークアクティビティ(メール、アプリ、保護されたウェブサイトなど)を監視できます。\n\n詳しくは管理者にお問い合わせください。"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"第三者があなたのネットワーク\nアクティビティ(メール、アプリ、保護されたウェブサイトなど)を監視できます。\n\nこれは、信頼できる認証情報が端末にインストールされているためです。"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"信頼できる認証情報を確認"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE-land/strings.xml b/packages/SystemUI/res/values-ka-rGE-land/strings.xml
new file mode 100644
index 0000000..3f20938
--- /dev/null
+++ b/packages/SystemUI/res/values-ka-rGE-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"ეკრანი ამჟამად დაბლოკილია თარაზულ ორიენტაციაში"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index b9963d5..49ed9ba 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"განათება"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ავტომატურად"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"შესაძლოა ქსელი მონიტორინგის ქვეშ იმყოფება"</string>
- <string name="done_button" msgid="1759387181766603361">"დასრულდა"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"ქსელის მონიტორინგი"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"თქვენ მოწყობილობის მმართველი არის: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nთქვენს ადმინისტრატოს შეუძლია განახორციელოს თქვენი ქსელის აქტივობის მონიტორინგი, მათ შორის ელფოსტების, აპების და უსაფრთხო ვებსაიტების მონიტორინგი.\n\nდამატებითი ინფორმაციისათვის, დაუკავშირდით ადმინისტრატორს."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"მესამე მხარეს შეუძლია განახორციელოდს თქვენი ქსელის \nაქტივობა, მათ შორის ელფოსტები, აპები და უსაფრთხო ვებსაიტები.\n\nეს შესაძლებელია თქვენს მოწყობილობაზე დაყენებული სანდო ავთენტიკაციის მონაცემების საშუალებით."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"სანდო ავთენტიკაციის მონაცემების შემოწმება"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km-rKH-land/strings.xml b/packages/SystemUI/res/values-km-rKH-land/strings.xml
new file mode 100644
index 0000000..f148cc3
--- /dev/null
+++ b/packages/SystemUI/res/values-km-rKH-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"ឥឡូវអេក្រង់ជាប់សោក្នុងទិសផ្ដេក។"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 211c286..5e0318d 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ពន្លឺ"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ស្វ័យប្រវត្តិ"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"បណ្ដាញអាចត្រូវបានតាមដាន"</string>
- <string name="done_button" msgid="1759387181766603361">"រួចរាល់"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"ការពិនិត្យបណ្ដាញ"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"ឧបករណ៍នេះត្រូវបានគ្រប់គ្រងដោយ៖ <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>។\n\nអ្នកគ្រប់គ្រងរបស់អ្នកអាចពិនិត្យសកម្មភាពបណ្ដាញរបស់អ្នករួមមាន អ៊ីមែល, កម្មវិធី និងតំបន់បណ្ដាញមានសុវត្ថិភាព។\n\nចំពោះព័ត៌មានបន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រងរបស់អ្នក។"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"ភាគីទីបីអាចពិនិត្យសកម្មភាព \n បណ្ដាញរបស់អ្នករួមមាន អ៊ីមែល, កម្មវិធី និងសុវត្ថិភាពតំបន់បណ្ដាញ។\n\n ព័ត៌មានដែលទុកចិត្តបានដំឡើងក្នុងឧបករណ៍របស់អ្នកអាចធ្វើការងារនេះបាន។"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"ពិនិត្យព័ត៌មានសម្ងាត់ដែលទុកចិត្ត"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 3b37888..7711bd5 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"밝기"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"자동"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"네트워크가 모니터링될 수 있음"</string>
- <string name="done_button" msgid="1759387181766603361">"완료"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"네트워크 모니터링"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"이 기기는 <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>에서 관리합니다.\n\n관리자는 이메일, 앱 및 보안 웹사이트를 포함한 네트워크 활동을 모니터링할 수 있습니다.\n\n자세한 정보는 관리자에게 문의하세요."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">\n\n"기기에 신뢰할 수 있는 자격증명이 설치되어있기 때문에 제3자가 이메일, 앱 및 보안 웹사이트를 포함한 네트워크\n활동을 모니터링할 수 있습니다."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"신뢰할 수 있는 자격증명 확인"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA-land/strings.xml b/packages/SystemUI/res/values-lo-rLA-land/strings.xml
new file mode 100644
index 0000000..a838a15
--- /dev/null
+++ b/packages/SystemUI/res/values-lo-rLA-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"ໜ້າຈໍຕອນນີ້ຖືກລັອກໄວ້ໃນແບບລວງນອນ."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 968fee4..e62c4f3 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ຄວາມແຈ້ງ"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ອັດຕະໂນມັດ"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ການນຳໃຊ້ເຄືອຂ່າຍອາດມີການກວດສອບຕິດຕາມ"</string>
- <string name="done_button" msgid="1759387181766603361">"ແລ້ວໆ"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"ການກວດສອບຕິດຕາມເຄືອຂ່າຍ"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"ອຸປະກອນນີ້ຈັດການໂດຍ: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nຜູ່ເບິ່ງແຍງລະບົບອຸປະກອນຂອງທ່ານ ສາມາດກວດສອບຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍຂອງທ່ານໄດ້ ຮວມທັງ: ອີເມວ, ແອັບຯ ແລະເວັບໄຊທີ່ເຂົ້າລະຫັດຕ່າງໆ.\n\nສຳລັບຂໍ້ມູນເພີ່ມເຕີມ, ໃຫ້ຕິດຕໍ່ຜູ່ເບິ່ງແຍງລະບົບຂອງທ່ານ."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"ບຸກຄົນທີສາມສາມາດກວດສອບຕິດຕາມເຄືອຂ່າຍຂອງທ່ານ\nຮວມທັງ: ອີເມວ, ແອັບຯ ແລະເວັບໄຊທີ່ເຂົ້າລະຫັດຕ່າງໆ.\n\nຂໍ້ມູນພິສູດຢືນຢັນທີ່ເຊື່ອຖືໄດ້ທີ່ມີຕິດຕັ້ງໃນອຸປະກອນຂອງທ່ານ ເຮັດໃຫ້ຂັ້ນຕອນນີ້ດຳເນີນໄປໄດ້."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"ກວດສອບການພິສູດຢືນຢັນທີ່ເຊື່ອຖືໄດ້"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index b0693d5..173fbbf 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Skaistis"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATINIS"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Tinklas gali būti stebimas"</string>
- <string name="done_button" msgid="1759387181766603361">"Atlikta"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Tinklo stebėjimas"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Šį įrenginį tvarko <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nAdministratorius gali stebėti jūsų tinklo veiklą, įskaitant el. paštą, programas ir saugias svetaines.\n\nJei norite gauti daugiau informacijos, susisiekite su administratoriumi."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Trečioji šalis gali stebėti jūsų tinklo\nveiklą, įskaitant el. paštą, programas ir saugias svetaines.\n\nVisa tai įmanoma dėl jūsų įrenginyje įdiegtų patikimų prisijungimo duomenų."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Tikrinti patikimus prisijungimo duomenis"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index b18bd6c..bdb8975 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Spilgtums"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMĀTISKI"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Iespējams, tīklā veiktās darbības tiek pārraudzītas."</string>
- <string name="done_button" msgid="1759387181766603361">"Gatavs"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Tīkla pārraudzība"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Šo ierīci pārvalda domēns <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nJūsu administrators var pārraudzīt darbības, ko veicat tīklā, tostarp e-pasta ziņojumus, lietotnes un drošās vietnes.\n\nLai iegūtu plašāku informāciju, sazinieties ar savu administratoru."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Trešā puse var pārraudzīt darbības, ko veicat tīklā,\ntostarp e-pasta ziņojumus, lietotnes un drošās vietnes.\n\nTas ir iespējams, jo jūsu ierīcē ir instalēti uzticami akreditācijas dati."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Pārbaudīt uzticamos akreditācijas datus"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN-land/strings.xml b/packages/SystemUI/res/values-mn-rMN-land/strings.xml
new file mode 100644
index 0000000..ec4616f
--- /dev/null
+++ b/packages/SystemUI/res/values-mn-rMN-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"Дэлгэц хэвтээ чиглэлд түгжигдсэн."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index e5d2af3..6a548db 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Тодрол"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОМАТ"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Сүлжээ хянагдаж байж болзошгүй"</string>
- <string name="done_button" msgid="1759387181766603361">"Дууссан"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Сүлжээний Хяналт"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Энэ төхөөрөмжийг удирдагч: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nТаны админ имэйл, апп-ууд болон аюулгүй вебсайтуудыг оруулан таны сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээллийг өөрийн админтай холбогдож авна уу."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Гуравдагч талын этгээд таны сүлжээг хянаж байж болзошгүй\nүүнд имэйл, апп-ууд болон аюулгүй вебсайтууд багтана.\n\nТаны төхөөрөмж дээр суулгасан итгэмжлэгдсэн жуух энэ боломжоор хангаж байна."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Итгэмжлэгдсэн жуухуудыг шалгах"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY-land/strings.xml b/packages/SystemUI/res/values-ms-rMY-land/strings.xml
new file mode 100644
index 0000000..175b0fa
--- /dev/null
+++ b/packages/SystemUI/res/values-ms-rMY-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"Skrin kini dikunci dalam orientasi landskap."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 40468f5..bb780fe 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rangkaian mungkin dipantau"</string>
- <string name="done_button" msgid="1759387181766603361">"Selesai"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Pemantauan Rangkaian"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Peranti ini diuruskan oleh: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nPentadbir anda boleh memantau aktiviti rangkaian anda, termasuk e-mel, apl dan tapak web selamat.\n\nUntuk maklumat lanjut, hubungi pentadbir anda."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Pihak ketiga boleh memantau aktiviti \nrangkaian anda, termasuk e-mel, apl dan tapak web selamat.\n\nBukti kelayakan dipercayai yang dipasang pada peranti anda membolehkan perkara ini."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Semak bukti kelayakan dipercayai"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index cd463c8..82c40909 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Nettverket blir muligens overvåket"</string>
- <string name="done_button" msgid="1759387181766603361">"Fullført"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Nettverksovervåking"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Denne enheten administreres av: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nAdministratoren din kan overvåke nettverksaktiviteten din, inkludert e-post, apper og sikre nettsteder.\n\nFor mer informasjon kan du kontakte administratoren din."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"En tredjepart kan overvåke nettverksaktiviteten din\n, inkludert e-poster, apper og sikre nettsteder.\n\nEn installering av pålitelig legitimasjon gjør dette mulig."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Sjekk pålitelig legitimasjon"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP-land/strings.xml b/packages/SystemUI/res/values-ne-rNP-land/strings.xml
new file mode 100644
index 0000000..8d5286e
--- /dev/null
+++ b/packages/SystemUI/res/values-ne-rNP-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"स्क्रिन अहिले ल्यान्डस्केप अवस्थामा बन्द छ।"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 19e2744..9e6605e 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -38,7 +38,7 @@
<string name="invalid_charger" msgid="4549105996740522523">"USB चार्ज गर्न समर्थित छैन।\n आपूर्ति गरिएको चार्जर मात्र प्रयोग गर्नुहोस्।"</string>
<string name="battery_low_why" msgid="7279169609518386372">"ब्याट्रि प्रयोग"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिङहरू"</string>
- <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"वाइ-फाइ"</string>
+ <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"वाइफाइ"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"हवाइजहाज मोड"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्वत:घुम्ने स्क्रिन"</string>
<string name="status_bar_settings_mute_label" msgid="554682549917429396">"म्युट गर्नुहोस्"</string>
@@ -127,9 +127,9 @@
<string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string>
<string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"रोमिङ"</string>
<string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
- <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"वाइ-फाइ"</string>
+ <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"वाइफाइ"</string>
<string name="accessibility_no_sim" msgid="8274017118472455155">"SIM छैन।"</string>
- <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ब्लुटुथ टिथर गर्दै।"</string>
+ <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ब्लुटुथ टेदर गर्दै।"</string>
<string name="accessibility_airplane_mode" msgid="834748999790763092">"हवाइजहाज मोड।"</string>
<string name="accessibility_battery_level" msgid="7451474187113371965">"ब्याट्रि <xliff:g id="NUMBER">%d</xliff:g> प्रतिशत"</string>
<string name="accessibility_settings_button" msgid="799583911231893380">"प्रणाली सेटिङहरू"</string>
@@ -159,7 +159,7 @@
<string name="data_usage_disabled_dialog" msgid="3853117269051806280">"तपाईँ निर्दिष्ट डेटा उपयोग सीमामा पुग्नु भएको छ।\n\nयदि तपाईँले डेटालाई पुनःसक्षम पार्नु भयो भने तपाईँलाई अर्को संचालकबाट शुल्क लगाउन सक्छ।"</string>
<string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"डेटा पुनः सक्षम गर्नुहोस्"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इन्टरनेट जडान छैन"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाइ-फाइ जडित"</string>
+ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाइफाइ जडित"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSको लागि खोजी गर्दै"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारा स्थान सेट गरिएको"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"स्थान अनुरोधहरू सक्रिय"</string>
@@ -189,11 +189,11 @@
<string name="quick_settings_settings_label" msgid="5326556592578065401">"सेटिङहरू"</string>
<string name="quick_settings_time_label" msgid="4635969182239736408">"समय"</string>
<string name="quick_settings_user_label" msgid="5238995632130897840">"मलाई"</string>
- <string name="quick_settings_wifi_label" msgid="9135344704899546041">"वाइ-फाइ"</string>
+ <string name="quick_settings_wifi_label" msgid="9135344704899546041">"वाइफाइ"</string>
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"जोडिएको छैन"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"नेटवर्क छैन"</string>
- <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"वाइ-फाइ बन्द"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"वाइ-फाइ प्रदर्शन"</string>
+ <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"वाइफाइ बन्द"</string>
+ <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"वाइफाइ प्रदर्शन"</string>
<string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"ताररहित प्रदर्शन"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"उज्यालपन"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वतः"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 0996392..46b14a4 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATISCH"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netwerk kan worden gecontroleerd"</string>
- <string name="done_button" msgid="1759387181766603361">"Gereed"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Netwerkcontrole"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Dit apparaat wordt beheerd door: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nUw beheerder kan uw netwerkactiviteit controleren, waaronder e-mails, apps en beveiligde websites.\n\nNeem contact op met uw beheerder voor meer informatie."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Een derde partij kan uw netwerkactiviteit\ncontroleren, waaronder e-mails, apps en beveiligde websites.\n\nDit wordt mogelijk gemaakt door vertrouwde inloggegevens die zijn geïnstalleerd op uw apparaat."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Vertrouwde inloggegevens controleren"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index c3476e5..22bb708 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jasność"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATYCZNA"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Sieć może być monitorowana"</string>
- <string name="done_button" msgid="1759387181766603361">"Gotowe"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Monitorowanie sieci"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"To urządzenie jest zarządzane w domenie <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nAdministrator może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i bezpieczne witryny.\n\nWięcej informacji uzyskasz od administratora."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Firma zewnętrzna może monitorować Twoją aktywność w sieci,\nw tym e-maile, aplikacje i bezpieczne witryny.\n\nPozwalają na to zaufane dane uwierzytelniające zainstalowane na tym urządzeniu."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Sprawdź zaufane dane uwierzytelniające"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index dac070f..42b6a62 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"A rede pode ser monitorizada"</string>
- <string name="done_button" msgid="1759387181766603361">"Concluído"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Monitorização da Rede"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Este dispositivo é gerido por: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nO seu administrador pode monitorizar a sua atividade de rede, incluindo mensagens de email, aplicações e Websites seguros.\n\nPara obter mais informações, contacte o seu administrador."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"A sua atividade\nde rede, incluindo mensagens de email, aplicações e Websites seguros, pode ser monitorizada por terceiros.\n\nEsta situação é possível graças a uma credencial fidedigna instalada no seu dispositivo."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Verificar credenciais fidedignas"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 711956e..51ce1c6 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"A rede pode ser monitorada"</string>
- <string name="done_button" msgid="1759387181766603361">"Concluído"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Monitoramento de rede"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Este dispositivo é gerenciado por: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nO administrador pode monitorar sua atividade na rede, incluindo e-mails, aplicativos e websites seguros.\n\nPara mais informações, entre em contato com o administrador."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Sua atividade na rede, incluindo e-mails, aplicativos\ne websites seguros, pode ser monitorada por terceiros.\n\nUma credencial confiável instalada no dispositivo permite o monitoramento."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Verificar credenciais confiáveis"</string>
</resources>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 0a5689c..c26c055 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -366,14 +366,4 @@
<skip />
<!-- no translation found for ssl_ca_cert_warning (5848402127455021714) -->
<skip />
- <!-- no translation found for done_button (1759387181766603361) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_dialog_title (1273796967092027291) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_info_message (5430320539555358452) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_warning_message (2033091656129963669) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_settings_button (7946956977377166709) -->
- <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 0b93f57..4bd25f8 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminozitate"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAT"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rețeaua poate fi monitorizată"</string>
- <string name="done_button" msgid="1759387181766603361">"Terminat"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Monitorizarea rețelei"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Acest dispozitiv este gestionat de: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nAdministratorul este capabil să monitorizeze activitatea dvs. în rețea, inclusiv mesajele e-mail, aplicațiile și site-urile securizate.\n\nPentru mai multe informații, contactați administratorul."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"O terță parte poate monitoriza activitatea dvs. în\nrețea, inclusiv mesajele e-mail, aplicațiile și site-urile securizate.\n\nAcest lucru este posibil deoarece există o acreditare de încredere instalată pe dispozitivul dvs."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Verificați acreditările de încredere"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 520ffb4..0a45aa9 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -185,7 +185,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Автоповорот"</string>
<string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Автоповорот выкл."</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Способ ввода"</string>
- <string name="quick_settings_location_label" msgid="5011327048748762257">"Местоположение"</string>
+ <string name="quick_settings_location_label" msgid="5011327048748762257">"Передача геоданных"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Местоположение выкл."</string>
<string name="quick_settings_media_device_label" msgid="1302906836372603762">"Режим медиа"</string>
<string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
@@ -202,9 +202,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркость"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОНАСТРОЙКА"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Действия в сети могут отслеживаться"</string>
- <string name="done_button" msgid="1759387181766603361">"Готово"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Мониторинг сети"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Устройством управляет администратор домена <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nОн может отслеживать ваши действия в сети, в том числе просматривать письма, приложения и список посещенных веб-сайтов.\n\nЗа дополнительной информацией обратитесь к администратору."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Администратор может отслеживать ваши действия в сети.\nНапример, он может просматривать ваши письма, приложения и список посещенных сайтов.\n\nЭто возможно благодаря надежному сертификату, установленному на устройстве."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Настройки сертификатов"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si-rLK-land/strings.xml b/packages/SystemUI/res/values-si-rLK-land/strings.xml
new file mode 100644
index 0000000..b5aba2a
--- /dev/null
+++ b/packages/SystemUI/res/values-si-rLK-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"තිරය දැන් තිරස් දිශානතිය අගුළු දමා ඇත."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index d036f0e..8a4ef39 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jas"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Sieť môže byť monitorovaná"</string>
- <string name="done_button" msgid="1759387181766603361">"Hotovo"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Monitorovanie siete"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Toto zariadenie spravuje: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nVáš správca môže monitorovať vašu aktivitu v sieti vrátane e-mailov, aplikácií a zabezpečených webových stránok.\n\nAk chcete získať viac informácií, obráťte sa na svojho správcu."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Tretia strana môže monitorovať vašu aktivitu\nv sieti vrátane e-mailov, aplikácií a zabezpečených webových stránok.\n\nUmožňuje to dôveryhodné poverenie nainštalované vo vašom zariadení."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Skontrolovať dôveryhodné poverenia"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index e0b215a..eaa8b11 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Svetlost"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"SAMODEJNO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Omrežje je lahko nadzorovano"</string>
- <string name="done_button" msgid="1759387181766603361">"Dokončano"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Nadzor omrežja"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"To napravo upravlja: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nSkrbnik lahko nadzoruje vašo omrežno dejavnost, vključno z e-pošto, aplikacijami in varnimi spletnimi mesti.\n\nZa več informacij se obrnite na skrbnika."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Vašo omrežno dejavnost, vključno z e-pošto, aplikacijami\nin varnimi spletnimi mesti, lahko nadzira tretja oseba.\n\nTo omogoča zaupanja vredna poverilnica, nameščena v vaši napravi."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Preveri zaupanja vredne poverilnice"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 84d72df..ccda6e9 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Осветљеност"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АУТОМАТСКА"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежа се можда надгледа"</string>
- <string name="done_button" msgid="1759387181766603361">"Готово"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Надгледање мреже"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Овим уређајем управља: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nАдминистратор може да надгледа активности на мрежи, укључујући поруке е-поште, апликације и безбедне веб-сајтове.\n\nЗа више информација контактирајте администратора."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Трећа страна може да надгледа активности\nна мрежи, укључујући поруке е-поште, апликације и безбедне веб-сајтове.\n\nТо је могуће захваљујући поузданом акредитиву инсталираном на уређају."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Провери поуздане акредитиве"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index d27c9e4..ffe8c84 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ljusstyrka"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Nätverket kan vara övervakat"</string>
- <string name="done_button" msgid="1759387181766603361">"Klart"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Nätverksövervakning"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Enheten hanteras av: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nAdministratören kan övervaka dina aktiviteter på nätverket, inklusive e-post, appar och säkra webbplatser.\n\nKontakta din administratör om du vill veta mer."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Dina nätverksaktiviteter kan övervakas av tredje part\n, inklusive e-post, appar och säkra webbplatser.\n\nDetta är möjligt eftersom tillförlitlig autentisering har installerats på enheten."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Kontrollera tillförlitlig autentisering"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index d3ac4c2..bdf22c3 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -179,7 +179,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Zungusha Otomatiki"</string>
<string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Mzunguko Umefungwa"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Mbinu ya uingizaji"</string>
- <string name="quick_settings_location_label" msgid="5011327048748762257">"Eneo"</string>
+ <string name="quick_settings_location_label" msgid="5011327048748762257">"Kutambua Eneo"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Eneo Limezimwa"</string>
<string name="quick_settings_media_device_label" msgid="1302906836372603762">"Kifaa cha midia"</string>
<string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
@@ -196,9 +196,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ung\'avu"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"KIOTOMATIKI"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mtandao unaweza kufuatiliwa"</string>
- <string name="done_button" msgid="1759387181766603361">"Imekamilika"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Ufuatiliaji wa Mtandao"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Kifaa hiki kinasimamiwa na: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nMsimamizi wako anaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu, na tovuti salama.\n\nKwa maelezo zaidi, wasiliana na msimamizi wako."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Mtu mwingine anaweza kufuatilia shughuli za mtandao wako\n, ikiwa ni pamoja na barua pepe, programu, na tovuti salama.\n\nKitambulisho cha kuaminika kilichosakinishwa kwenye kifaa chako kinafanikisha hili."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Angalia kitambulisho cha kuaminika"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 2eb8896..af4bb092 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ความสว่าง"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"อัตโนมัติ"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"เครือข่ายอาจได้รับการตรวจสอบ"</string>
- <string name="done_button" msgid="1759387181766603361">"เสร็จสิ้น"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"การตรวจสอบเครือข่าย"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"อุปกรณ์นี้ได้รับการจัดการโดย: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>\n\nผู้ดูแลระบบของคุณสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ ซึ่งรวมถึงอีเมล แอป และเว็บไซต์ที่มีการรักษาความปลอดภัย\n\nสำหรับข้อมูลเพิ่มเติม โปรดติดต่อผู้ดูแลระบบของคุณ"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"บุคคลที่สามสามารถตรวจสอบกิจกรรมในเครือข่าย\nของคุณ ซึ่งรวมถึงอีเมล แอป และเว็บไซต์ที่มีการรักษาความปลอดภัย\n\nการดำเนินการนี้เกิดขึ้นได้ด้วยข้อมูลรับรองที่เชื่อถือได้ที่ติดตั้งอยู่ในอุปกรณ์ของคุณ"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"ตรวจสอบข้อมูลรับรองที่เชื่อถือได้"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 69b5aff..33bd368 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Maaaring sinusubaybayan ang network"</string>
- <string name="done_button" msgid="1759387181766603361">"Tapos na"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Pagsubaybay sa Network"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Ang device na ito ay pinamamahalaan ng: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nMay kakayahan ang iyong administrator na subaybayan ang gawain ng iyong network, kasama ang mga email, apps, at secure na mga website.\n\nPara sa higit pang impormasyon, makipag-ugnay sa iyong administrator."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"May kakayahan ang third party na subaybayan ang gawain ng iyong\nnetwork, kasama ang mga email, apps, at secure na mga website.\n\nGinagawa itong posible ng pinagkakatiwalaang kredensyal na naka-install sa iyong device."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Suriin ang mga pinagkakatiwalaang kredensyal"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 67e2be2..fcc5a97 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Parlaklık"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATİK"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Ağ izlenebilir"</string>
- <string name="done_button" msgid="1759387181766603361">"Bitti"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Ağ İzleme"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Bu cihazı yöneten alan adı: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nE-postalarınız, uygulamalarınız ve güvenli web siteleriniz dahil olmak üzere ağ etkinlikleriniz yöneticiniz tarafından izlenebilir.\n\nDaha fazla bilgi için yöneticinizle görüşün."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"E-postalarınız, uygulamalarınız ve güvenli web siteleriniz\ndahil olmak üzere ağ etkinliğiniz üçüncü bir tarafça izlenebilir.\n\nCihazınızda yüklü güvenilir bir kimlik bilgisi bunu mümkün kılmaktadır."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Güvenilen kimlik bilgilerini kontrol et"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 527525e..b1d8a39 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яскравість"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТО"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мережу можуть відстежувати"</string>
- <string name="done_button" msgid="1759387181766603361">"Готово"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Відстеження мережі"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Цим пристроєм керує домен <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nАдміністратор може відстежувати ваші дії в мережі, зокрема електронне листування, роботу в програмах і на захищених веб-сайтах.\n\nЩоб дізнатися більше, зверніться до свого адміністратора."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Третя сторона може відстежувати ваші дії в\nмережі, зокрема електронне листування, роботу в програмах і на захищених веб-сайтах, за допомогою надійних облікових даних, установлених на вашому пристрої.\n\n"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Переглянути надійні облікові дані"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 4be1bf0..6a079b3 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Độ sáng"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"TỰ ĐỘNG"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mạng có thể được giám sát"</string>
- <string name="done_button" msgid="1759387181766603361">"Xong"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Giám sát mạng"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Thiết bị này được quản lý bởi: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nQuản trị viên của bạn có thể giám sát hoạt động trên mạng của bạn, bao gồm email, ứng dụng và trang web bảo mật.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Bên thứ ba có thể giám sát hoạt động trên mạng\ncủa bạn, bao gồm email, ứng dụng và trang web bảo mật.\n\nMột bằng chứng xác thực tin cậy được cài đặt trên thiết bị của bạn có thể dẫn đến khả năng này."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Kiểm tra bằng chứng xác thực tin cậy"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 1093d0c..017c8fc 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -156,8 +156,8 @@
<string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"闹钟已设置为:<xliff:g id="TIME">%s</xliff:g>。"</string>
<string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G 数据网络已停用"</string>
<string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G 数据网络已停用"</string>
- <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"移动数据已停用"</string>
- <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"数据已停用"</string>
+ <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"移动数据网络已停用"</string>
+ <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"数据网络已停用"</string>
<string name="data_usage_disabled_dialog" msgid="3853117269051806280">"您已达到指定的数据流量上限。\n\n如果您重新启用数据,运营商可能会收取相应的费用。"</string>
<string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"重新启用数据连接"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"未连接互联网"</string>
@@ -178,10 +178,10 @@
<string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"充电完成"</string>
<string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"蓝牙"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"蓝牙(<xliff:g id="NUMBER">%d</xliff:g> 台设备)"</string>
- <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"蓝牙已关闭"</string>
+ <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"蓝牙:关闭"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"亮度"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"自动旋转"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"屏幕方向已锁定"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"屏幕方向:锁定"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"输入法"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"位置信息"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"位置信息服务已关闭"</string>
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自动"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"网络可能会受到监控"</string>
- <string name="done_button" msgid="1759387181766603361">"完成"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"网络监控"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"此设备由以下企业域管理:<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>。\n\n您的管理员可以监控您的网络活动,包括收发电子邮件、使用应用和浏览安全网站。\n\n如要了解详情,请与您的管理员联系。"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"第三方可以监控您的网络活动,包括\n收发电子邮件、使用应用和浏览安全网站。\n\n如果您在设备上安装受信任的凭据,就可能出现这种情况。"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"查看受信任的凭据"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK-land/strings.xml b/packages/SystemUI/res/values-zh-rHK-land/strings.xml
new file mode 100644
index 0000000..8d55df4
--- /dev/null
+++ b/packages/SystemUI/res/values-zh-rHK-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"屏幕現已鎖定為橫向模式"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index daef9d2..ae816380 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"網絡可能會受到監控"</string>
- <string name="done_button" msgid="1759387181766603361">"完成"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"網絡監控"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"這部裝置由下列網域管理:<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>。\n\n您的管理員可以監控您的網絡活動,包括收發電郵、使用應用程式及瀏覽安全網站。\n\n詳情請與您的管理員聯絡。"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"第三方可以監察您的網絡活動,\n包括收發電郵、使用應用程式及瀏覽安全網站。\n\n當裝置安裝了信任的憑證,便可能會出現這種情況。"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"檢查信任的憑證"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 73871c6..4f86806 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"網路可能會受到監控"</string>
- <string name="done_button" msgid="1759387181766603361">"完成"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"網路監控"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"這個裝置由下列網域管理:<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>。\n\n您的管理員可以監控您的網路活動,包括收發電子郵件、使用應用程式及瀏覽安全網站。\n\n如需詳細資訊,請與您的管理員聯絡。"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"第三方可以監控您的網路活動,\n包括收發電子郵件、使用應用程式及瀏覽安全網站。\n\n如果您在裝置上安裝信任的憑證,就會造成這種情況。"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"檢查信任的憑證"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 4dfad2f..def73ff 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -24,10 +24,10 @@
<string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Susa ohlwini"</string>
<string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Ulwazi lwensiza"</string>
<string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Azikho izinhlelo zokusebenza zakamuva"</string>
- <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Susa izinsiza zakamumva"</string>
+ <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Susa izinhlelo zokusebenza zakamumva"</string>
<plurals name="status_bar_accessibility_recent_apps">
<item quantity="one" msgid="5854176083865845541">"Insiza eyi-1 yakamumva"</item>
- <item quantity="other" msgid="1040784359794890744">"%d izinsiza zakamumva"</item>
+ <item quantity="other" msgid="1040784359794890744">"%d izinhlelo zokusebenza zakamumva"</item>
</plurals>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Azikho izaziso"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Okuqhubekayo"</string>
@@ -47,11 +47,11 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Ukusebenzisa i-Bluetooth njengemodemu"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Izilungiselelo zezindlela zokufakwayo"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Ukwakheka kwekhibhodi"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Vumela insiza <xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ufinyelele ezintweni eziphuma ne-USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vumela insiza <xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ufinyelele ezintweni eziphuma ne-USB?"</string>
+ <string name="usb_device_permission_prompt" msgid="834698001271562057">"Vumela uhlelo lokusebenza <xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ufinyelele ezintweni eziphuma ne-USB?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vumela uhlelo lokusebenza <xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ufinyelele ezintweni eziphuma ne-USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vula <xliff:g id="ACTIVITY">%1$s</xliff:g> uma ledivayisi ye-USB ixhunyiwe?"</string>
<string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Vula <xliff:g id="ACTIVITY">%1$s</xliff:g> uma le-accessory ye-USB ixhunyiwe"</string>
- <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Azikho izinsiza ezisebenze ngezinto ze-USB. Funda okwengeziwe ngale into kwi <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Azikho izinhlelo zokusebenza ezisebenze ngezinto ze-USB. Funda okwengeziwe ngale into kwi <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"ama-accessory e-USB"</string>
<string name="label_view" msgid="6304565553218192990">"Buka"</string>
<string name="always_use_device" msgid="1450287437017315906">"Sebenzisa ngokuzenzakalelayo yale divayisi ye-USB"</string>
@@ -71,7 +71,7 @@
<string name="usb_preference_title" msgid="6551050377388882787">"Okukhethwa kokudluliswa kwefayela ye-USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Lengisa njengesidlali semediya (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Lengisa ikhamera (PTP)"</string>
- <string name="installer_cd_button_title" msgid="2312667578562201583">"Faka insiza yokudluliswa Kwefayela ye-Android kwi-Mac"</string>
+ <string name="installer_cd_button_title" msgid="2312667578562201583">"Faka uhlelo lokusebenza yokudluliswa Kwefayela ye-Android kwi-Mac"</string>
<string name="accessibility_back" msgid="567011538994429120">"Emuva"</string>
<string name="accessibility_home" msgid="8217216074895377641">"Ekhaya"</string>
<string name="accessibility_menu" msgid="316839303324695949">"Imenyu"</string>
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ukugqama"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OKUZENZAKALELAYO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Inethiwekhi ingase inganyelwe"</string>
- <string name="done_button" msgid="1759387181766603361">"Kwenziwe"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Ukwenganyelwa kwenethiwekhi"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Le divayisi iphethwe ngu-: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nUmphathi wakho uyakwazi ukungamela umsebenzi wenethiwekhi yakho, okufaka phakathi ama-imeyili, izinhlelo zokusebenza, namawebhusayithi aphephile.\n\nUkuze uthole olunye ulwazi xhumana nomphathi wakho."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Inkampani yangaphandle ingakwazi ukungamela umsebenzi wenethiwekhi yakho\n, okufaka phakathi ama-imeyili, izinhlelo zokusebenza namawebhusayithi aphephile.\n\nIsiqinisekiso esethenjwayo kudivayisi yakho senza lokhu kwenzeke."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Hlola ukuqinisekisa okwethenjwayo"</string>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3ffa6f4..7fdd308 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -431,8 +431,8 @@
<!-- Description of the button in the phone-style notification panel that controls auto-rotation, when auto-rotation is off. [CHAR LIMIT=NONE] -->
<string name="accessibility_rotation_lock_on_portrait">Screen is locked in portrait orientation.</string>
- <!-- Name of the Jelly Bean platlogo screensaver -->
- <string name="jelly_bean_dream_name">BeanFlinger</string>
+ <!-- Name of the K-release easter egg: a display case for all our tastiest desserts. [CHAR LIMIT=30] -->
+ <string name="dessert_case">Dessert Case</string>
<!-- Name of the launcher shortcut icon that allows dreams to be started immediately [CHAR LIMIT=20] -->
<string name="start_dreams">Daydream</string>
@@ -500,16 +500,5 @@
<!-- Shows up when there is a user SSL CA Cert installed on the
device. Indicates to the user that SSL traffic can be intercepted. [CHAR LIMIT=NONE] -->
<string name="ssl_ca_cert_warning">Network may be monitored</string>
- <!-- Button to close the SSL CA cert warning dialog box. [CHAR LIMIT=NONE] -->
- <string name="done_button">Done</string>
- <!-- Title of Dialog warning users of SSL monitoring. [CHAR LIMIT=NONE] -->
- <string name="ssl_ca_cert_dialog_title">Network Monitoring</string>
- <!-- Text of message to show to users whose administrator has installed a SSL CA Cert.
- [CHAR LIMIT=NONE] -->
- <string name="ssl_ca_cert_info_message">This device is managed by: <xliff:g id="managing_domain">%s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity, including emails, apps, and secure websites.\n\nFor more information,contact your administrator.</string>
- <!-- Text of warning to show to users that have a SSL CA Cert installed. [CHAR LIMIT=NONE] -->
- <string name="ssl_ca_cert_warning_message">A third party is capable of monitoring your network\nactivity, including emails, apps, and secure websites.\n\nA trusted credential installed on your device is making this possible.</string>
- <!-- Label on button that will take the user to the Trusted Credentials settings page.
- [CHAR LIMIT=NONE]-->
- <string name="ssl_ca_cert_settings_button">Check trusted credentials</string>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 2257617..2be8ee5 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -292,11 +292,7 @@
c.drawRect(mFrame, mBatteryPaint);
c.restore();
- if (level <= EMPTY) {
- final float x = mWidth * 0.5f;
- final float y = (mHeight + mWarningTextHeight) * 0.48f;
- c.drawText(mWarningString, x, y, mWarningTextPaint);
- } else if (tracker.plugged) {
+ if (tracker.plugged) {
// draw the bolt
final int bl = (int)(mFrame.left + width / 4f);
final int bt = (int)(mFrame.top + height / 6f);
@@ -319,6 +315,10 @@
mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
}
c.drawPath(mBoltPath, mBoltPaint);
+ } else if (level <= EMPTY) {
+ final float x = mWidth * 0.5f;
+ final float y = (mHeight + mWarningTextHeight) * 0.48f;
+ c.drawText(mWarningString, x, y, mWarningTextPaint);
} else if (mShowPercent && !(tracker.level == 100 && !SHOW_100_PERCENT)) {
mTextPaint.setTextSize(height *
(SINGLE_DIGIT_PERCENT ? 0.75f
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCase.java b/packages/SystemUI/src/com/android/systemui/DessertCase.java
new file mode 100644
index 0000000..b6424af0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DessertCase.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 com.android.systemui;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.util.Slog;
+
+public class DessertCase extends Activity {
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ Slog.v("DessertCase", "ACHIEVEMENT UNLOCKED");
+ PackageManager pm = getPackageManager();
+ pm.setComponentEnabledSetting(new ComponentName(this, DessertCaseDream.class),
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+
+ finish();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java b/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java
new file mode 100644
index 0000000..022e4d8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.service.dreams.DreamService;
+
+public class DessertCaseDream extends DreamService {
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ setInteractive(true);
+ setFullscreen(true);
+ }
+
+ @Override
+ public void onDreamingStarted() {
+ super.onDreamingStarted();
+ }
+
+ @Override
+ public void onDreamingStopped() {
+ super.onDreamingStopped();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java b/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java
new file mode 100644
index 0000000..b4d3edd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recent;
+
+import android.graphics.drawable.ColorDrawable;
+
+public class ColorDrawableWithDimensions extends ColorDrawable {
+ private int mWidth;
+ private int mHeight;
+
+ public ColorDrawableWithDimensions(int color, int width, int height) {
+ super(color);
+ mWidth = width;
+ mHeight = height;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mHeight;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java b/packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
rename to packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
index f17766b..1cfc892 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
@@ -30,7 +30,7 @@
import com.android.systemui.R;
-public class RecentsScrollViewPerformanceHelper {
+public class FadedEdgeDrawHelper {
public static final boolean OPTIMIZE_SW_RENDERED_RECENTS = true;
public static final boolean USE_DARK_FADE_IN_HW_ACCELERATED_MODE = true;
private View mScrollView;
@@ -43,18 +43,18 @@
private Matrix mFadeMatrix;
private LinearGradient mFade;
- public static RecentsScrollViewPerformanceHelper create(Context context,
+ public static FadedEdgeDrawHelper create(Context context,
AttributeSet attrs, View scrollView, boolean isVertical) {
boolean isTablet = context.getResources().
getBoolean(R.bool.config_recents_interface_for_tablets);
if (!isTablet && (OPTIMIZE_SW_RENDERED_RECENTS || USE_DARK_FADE_IN_HW_ACCELERATED_MODE)) {
- return new RecentsScrollViewPerformanceHelper(context, attrs, scrollView, isVertical);
+ return new FadedEdgeDrawHelper(context, attrs, scrollView, isVertical);
} else {
return null;
}
}
- public RecentsScrollViewPerformanceHelper(Context context,
+ public FadedEdgeDrawHelper(Context context,
AttributeSet attrs, View scrollView, boolean isVertical) {
mScrollView = scrollView;
TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View);
@@ -64,7 +64,7 @@
}
public void onAttachedToWindowCallback(
- RecentsCallback callback, LinearLayout layout, boolean hardwareAccelerated) {
+ LinearLayout layout, boolean hardwareAccelerated) {
mSoftwareRendered = !hardwareAccelerated;
if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
|| USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
@@ -178,11 +178,11 @@
}
}
- public int getVerticalFadingEdgeLengthCallback() {
+ public int getVerticalFadingEdgeLength() {
return mFadingEdgeLength;
}
- public int getHorizontalFadingEdgeLengthCallback() {
+ public int getHorizontalFadingEdgeLength() {
return mFadingEdgeLength;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 8b2cd3f..c714d8b 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -25,7 +25,7 @@
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Handler;
@@ -62,8 +62,8 @@
private Handler mHandler;
private int mIconDpi;
- private Bitmap mDefaultThumbnailBackground;
- private Bitmap mDefaultIconBackground;
+ private ColorDrawableWithDimensions mDefaultThumbnailBackground;
+ private ColorDrawableWithDimensions mDefaultIconBackground;
private int mNumTasksInFirstScreenful = Integer.MAX_VALUE;
private boolean mFirstScreenful;
@@ -100,7 +100,7 @@
// Render default icon (just a blank image)
int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size);
int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi);
- mDefaultIconBackground = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+ mDefaultIconBackground = new ColorDrawableWithDimensions(0x00000000, iconSize, iconSize);
// Render the default thumbnail background
int thumbnailWidth =
@@ -110,9 +110,7 @@
int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
mDefaultThumbnailBackground =
- Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(mDefaultThumbnailBackground);
- c.drawColor(color);
+ new ColorDrawableWithDimensions(color, thumbnailWidth, thumbnailHeight);
}
public void setRecentsPanel(RecentsPanelView newRecentsPanel, RecentsPanelView caller) {
@@ -125,11 +123,11 @@
}
}
- public Bitmap getDefaultThumbnail() {
+ public Drawable getDefaultThumbnail() {
return mDefaultThumbnailBackground;
}
- public Bitmap getDefaultIcon() {
+ public Drawable getDefaultIcon() {
return mDefaultIconBackground;
}
@@ -199,7 +197,7 @@
+ td + ": " + thumbnail);
synchronized (td) {
if (thumbnail != null) {
- td.setThumbnail(thumbnail);
+ td.setThumbnail(new BitmapDrawable(mContext.getResources(), thumbnail));
} else {
td.setThumbnail(mDefaultThumbnailBackground);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
index f51e34b..f5670e1 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
@@ -22,7 +22,10 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -68,7 +71,14 @@
}
} else {
- Bitmap first = firstTask.getThumbnail();
+ Bitmap first = null;
+ if (firstTask.getThumbnail() instanceof BitmapDrawable) {
+ first = ((BitmapDrawable) firstTask.getThumbnail()).getBitmap();
+ } else {
+ first = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+ Drawable d = RecentTasksLoader.getInstance(mContext).getDefaultThumbnail();
+ d.draw(new Canvas(first));
+ }
final Resources res = mContext.getResources();
float thumbWidth = res
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 217b7fd..be42bc0 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -49,16 +49,17 @@
private RecentsCallback mCallback;
protected int mLastScrollPosition;
private SwipeHelper mSwipeHelper;
- private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+ private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
private HashSet<View> mRecycledViews;
private int mNumItemsInOneScreenful;
+ private Runnable mOnScrollListener;
public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
float densityScale = getResources().getDisplayMetrics().density;
float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop);
- mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, false);
+ mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, false);
mRecycledViews = new HashSet<View>();
}
@@ -108,8 +109,8 @@
final View view = mAdapter.getView(i, old, mLinearLayout);
- if (mPerformanceHelper != null) {
- mPerformanceHelper.addViewCallback(view);
+ if (mFadedEdgeDrawHelper != null) {
+ mFadedEdgeDrawHelper.addViewCallback(view);
}
OnTouchListener noOpListener = new OnTouchListener() {
@@ -234,26 +235,10 @@
}
@Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
+ public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
+ if (mFadedEdgeDrawHelper != null) {
- if (mPerformanceHelper != null) {
- int paddingLeft = mPaddingLeft;
- final boolean offsetRequired = isPaddingOffsetRequired();
- if (offsetRequired) {
- paddingLeft += getLeftPaddingOffset();
- }
-
- int left = mScrollX + paddingLeft;
- int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
- int top = mScrollY + getFadeTop(offsetRequired);
- int bottom = top + getFadeHeight(offsetRequired);
-
- if (offsetRequired) {
- right += getRightPaddingOffset();
- bottom += getBottomPaddingOffset();
- }
- mPerformanceHelper.drawCallback(canvas,
+ mFadedEdgeDrawHelper.drawCallback(canvas,
left, right, top, bottom, mScrollX, mScrollY,
0, 0,
getLeftFadingEdgeStrength(), getRightFadingEdgeStrength(), mPaddingTop);
@@ -261,9 +246,21 @@
}
@Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ if (mOnScrollListener != null) {
+ mOnScrollListener.run();
+ }
+ }
+
+ public void setOnScrollListener(Runnable listener) {
+ mOnScrollListener = listener;
+ }
+
+ @Override
public int getVerticalFadingEdgeLength() {
- if (mPerformanceHelper != null) {
- return mPerformanceHelper.getVerticalFadingEdgeLengthCallback();
+ if (mFadedEdgeDrawHelper != null) {
+ return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
} else {
return super.getVerticalFadingEdgeLength();
}
@@ -271,8 +268,8 @@
@Override
public int getHorizontalFadingEdgeLength() {
- if (mPerformanceHelper != null) {
- return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback();
+ if (mFadedEdgeDrawHelper != null) {
+ return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
} else {
return super.getHorizontalFadingEdgeLength();
}
@@ -290,9 +287,8 @@
@Override
public void onAttachedToWindow() {
- if (mPerformanceHelper != null) {
- mPerformanceHelper.onAttachedToWindowCallback(
- mCallback, mLinearLayout, isHardwareAccelerated());
+ if (mFadedEdgeDrawHelper != null) {
+ mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 3946d1c..788e843 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -23,12 +23,14 @@
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.TaskStackBuilder;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
@@ -73,7 +75,7 @@
private PopupMenu mPopup;
private View mRecentsScrim;
private View mRecentsNoApps;
- private ViewGroup mRecentsContainer;
+ private RecentsScrollView mRecentsContainer;
private boolean mShowing;
private boolean mWaitingToShow;
@@ -97,6 +99,8 @@
public void setCallback(RecentsCallback callback);
public void setMinSwipeAlpha(float minAlpha);
public View findViewForTask(int persistentTaskId);
+ public void drawFadedEdges(Canvas c, int left, int right, int top, int bottom);
+ public void setOnScrollListener(Runnable listener);
}
private final class OnLongClickDelegate implements View.OnLongClickListener {
@@ -112,7 +116,7 @@
/* package */ final static class ViewHolder {
View thumbnailView;
ImageView thumbnailViewImage;
- Bitmap thumbnailViewImageBitmap;
+ Drawable thumbnailViewDrawable;
ImageView iconView;
TextView labelView;
TextView descriptionView;
@@ -150,7 +154,7 @@
// the thumbnail later (if they both have the same dimensions)
updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
- holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+ holder.iconView.setImageDrawable(mRecentTasksLoader.getDefaultIcon());
holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
holder.calloutLine = convertView.findViewById(R.id.recents_callout_line);
holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
@@ -226,7 +230,7 @@
public void recycleView(View v) {
ViewHolder holder = (ViewHolder) v.getTag();
updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
- holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+ holder.iconView.setImageDrawable(mRecentTasksLoader.getDefaultIcon());
holder.iconView.setVisibility(INVISIBLE);
holder.iconView.animate().cancel();
holder.labelView.setText(null);
@@ -269,13 +273,7 @@
}
public int numItemsInOneScreenful() {
- if (mRecentsContainer instanceof RecentsScrollView){
- RecentsScrollView scrollView
- = (RecentsScrollView) mRecentsContainer;
- return scrollView.numItemsInOneScreenful();
- } else {
- throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
- }
+ return mRecentsContainer.numItemsInOneScreenful();
}
private boolean pointInside(int x, int y, View v) {
@@ -287,7 +285,7 @@
}
public boolean isInContentArea(int x, int y) {
- return pointInside(x, y, mRecentsContainer);
+ return pointInside(x, y, (View) mRecentsContainer);
}
public void show(boolean show) {
@@ -354,7 +352,6 @@
if (mPopup != null) {
mPopup.dismiss();
}
- ((RecentsActivity) mContext).moveTaskToBack(true);
}
}
@@ -436,16 +433,16 @@
protected void onFinishInflate() {
super.onFinishInflate();
- mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container);
+ mRecentsContainer = (RecentsScrollView) findViewById(R.id.recents_container);
+ mRecentsContainer.setOnScrollListener(new Runnable() {
+ public void run() {
+ // need to redraw the faded edges
+ invalidate();
+ }
+ });
mListAdapter = new TaskDescriptionAdapter(mContext);
- if (mRecentsContainer instanceof RecentsScrollView){
- RecentsScrollView scrollView
- = (RecentsScrollView) mRecentsContainer;
- scrollView.setAdapter(mListAdapter);
- scrollView.setCallback(this);
- } else {
- throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
- }
+ mRecentsContainer.setAdapter(mListAdapter);
+ mRecentsContainer.setCallback(this);
mRecentsScrim = findViewById(R.id.recents_bg_protect);
mRecentsNoApps = findViewById(R.id.recents_no_apps);
@@ -462,11 +459,7 @@
}
public void setMinSwipeAlpha(float minAlpha) {
- if (mRecentsContainer instanceof RecentsScrollView){
- RecentsScrollView scrollView
- = (RecentsScrollView) mRecentsContainer;
- scrollView.setMinSwipeAlpha(minAlpha);
- }
+ mRecentsContainer.setMinSwipeAlpha(minAlpha);
}
private void createCustomAnimations(LayoutTransition transitioner) {
@@ -488,23 +481,23 @@
}
}
- private void updateThumbnail(ViewHolder h, Bitmap thumbnail, boolean show, boolean anim) {
+ private void updateThumbnail(ViewHolder h, Drawable thumbnail, boolean show, boolean anim) {
if (thumbnail != null) {
// Should remove the default image in the frame
// that this now covers, to improve scrolling speed.
// That can't be done until the anim is complete though.
- h.thumbnailViewImage.setImageBitmap(thumbnail);
+ h.thumbnailViewImage.setImageDrawable(thumbnail);
// scale the image to fill the full width of the ImageView. do this only if
// we haven't set a bitmap before, or if the bitmap size has changed
- if (h.thumbnailViewImageBitmap == null ||
- h.thumbnailViewImageBitmap.getWidth() != thumbnail.getWidth() ||
- h.thumbnailViewImageBitmap.getHeight() != thumbnail.getHeight()) {
+ if (h.thumbnailViewDrawable == null ||
+ h.thumbnailViewDrawable.getIntrinsicWidth() != thumbnail.getIntrinsicWidth() ||
+ h.thumbnailViewDrawable.getIntrinsicHeight() != thumbnail.getIntrinsicHeight()) {
if (mFitThumbnailToXY) {
h.thumbnailViewImage.setScaleType(ScaleType.FIT_XY);
} else {
Matrix scaleMatrix = new Matrix();
- float scale = mThumbnailWidth / (float) thumbnail.getWidth();
+ float scale = mThumbnailWidth / (float) thumbnail.getIntrinsicWidth();
scaleMatrix.setScale(scale, scale);
h.thumbnailViewImage.setScaleType(ScaleType.MATRIX);
h.thumbnailViewImage.setImageMatrix(scaleMatrix);
@@ -517,14 +510,14 @@
}
h.thumbnailView.setVisibility(View.VISIBLE);
}
- h.thumbnailViewImageBitmap = thumbnail;
+ h.thumbnailViewDrawable = thumbnail;
}
}
void onTaskThumbnailLoaded(TaskDescription td) {
synchronized (td) {
if (mRecentsContainer != null) {
- ViewGroup container = mRecentsContainer;
+ ViewGroup container = (ViewGroup) mRecentsContainer;
if (container instanceof RecentsScrollView) {
container = (ViewGroup) container.findViewById(
R.id.recents_linear_layout);
@@ -633,7 +626,7 @@
final int items = mRecentTaskDescriptions != null
? mRecentTaskDescriptions.size() : 0;
- mRecentsContainer.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
+ ((View) mRecentsContainer).setVisibility(items > 0 ? View.VISIBLE : View.GONE);
// Set description for accessibility
int numRecentApps = mRecentTaskDescriptions != null
@@ -650,33 +643,33 @@
}
public boolean simulateClick(int persistentTaskId) {
- if (mRecentsContainer instanceof RecentsScrollView){
- RecentsScrollView scrollView
- = (RecentsScrollView) mRecentsContainer;
- View v = scrollView.findViewForTask(persistentTaskId);
- if (v != null) {
- handleOnClick(v);
- return true;
- }
+ View v = mRecentsContainer.findViewForTask(persistentTaskId);
+ if (v != null) {
+ handleOnClick(v);
+ return true;
}
return false;
}
public void handleOnClick(View view) {
- ViewHolder holder = (ViewHolder)view.getTag();
+ ViewHolder holder = (ViewHolder) view.getTag();
TaskDescription ad = holder.taskDescription;
final Context context = view.getContext();
final ActivityManager am = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
- Bitmap bm = holder.thumbnailViewImageBitmap;
- boolean usingDrawingCache;
- if (bm.getWidth() == holder.thumbnailViewImage.getWidth() &&
- bm.getHeight() == holder.thumbnailViewImage.getHeight()) {
- usingDrawingCache = false;
- } else {
+
+ Bitmap bm = null;
+ boolean usingDrawingCache = true;
+ if (holder.thumbnailViewDrawable instanceof BitmapDrawable) {
+ bm = ((BitmapDrawable) holder.thumbnailViewDrawable).getBitmap();
+ if (bm.getWidth() == holder.thumbnailViewImage.getWidth() &&
+ bm.getHeight() == holder.thumbnailViewImage.getHeight()) {
+ usingDrawingCache = false;
+ }
+ }
+ if (usingDrawingCache) {
holder.thumbnailViewImage.setDrawingCacheEnabled(true);
bm = holder.thumbnailViewImage.getDrawingCache();
- usingDrawingCache = true;
}
Bundle opts = (bm == null) ?
null :
@@ -699,6 +692,8 @@
new UserHandle(UserHandle.USER_CURRENT));
} catch (SecurityException e) {
Log.e(TAG, "Recents does not have the permission to launch " + intent, e);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "Error launching activity " + intent, e);
}
}
if (usingDrawingCache) {
@@ -769,7 +764,7 @@
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.recent_remove_item) {
- mRecentsContainer.removeViewInLayout(selectedView);
+ ((ViewGroup) mRecentsContainer).removeViewInLayout(selectedView);
} else if (item.getItemId() == R.id.recent_inspect_item) {
ViewHolder viewHolder = (ViewHolder) selectedView.getTag();
if (viewHolder != null) {
@@ -793,4 +788,26 @@
});
popup.show();
}
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+
+ int paddingLeft = mPaddingLeft;
+ final boolean offsetRequired = isPaddingOffsetRequired();
+ if (offsetRequired) {
+ paddingLeft += getLeftPaddingOffset();
+ }
+
+ int left = mScrollX + paddingLeft;
+ int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
+ int top = mScrollY + getFadeTop(offsetRequired);
+ int bottom = top + getFadeHeight(offsetRequired);
+
+ if (offsetRequired) {
+ right += getRightPaddingOffset();
+ bottom += getBottomPaddingOffset();
+ }
+ mRecentsContainer.drawFadedEdges(canvas, left, right, top, bottom);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index ee076d9..6dddc39 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -49,9 +49,10 @@
private RecentsCallback mCallback;
protected int mLastScrollPosition;
private SwipeHelper mSwipeHelper;
- private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+ private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
private HashSet<View> mRecycledViews;
private int mNumItemsInOneScreenful;
+ private Runnable mOnScrollListener;
public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
@@ -59,7 +60,7 @@
float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
- mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, true);
+ mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, true);
mRecycledViews = new HashSet<View>();
}
@@ -112,8 +113,8 @@
}
final View view = mAdapter.getView(i, old, mLinearLayout);
- if (mPerformanceHelper != null) {
- mPerformanceHelper.addViewCallback(view);
+ if (mFadedEdgeDrawHelper != null) {
+ mFadedEdgeDrawHelper.addViewCallback(view);
}
OnTouchListener noOpListener = new OnTouchListener() {
@@ -243,36 +244,32 @@
}
@Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
-
- if (mPerformanceHelper != null) {
- int paddingLeft = mPaddingLeft;
+ public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
+ if (mFadedEdgeDrawHelper != null) {
final boolean offsetRequired = isPaddingOffsetRequired();
- if (offsetRequired) {
- paddingLeft += getLeftPaddingOffset();
- }
-
- int left = mScrollX + paddingLeft;
- int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
- int top = mScrollY + getFadeTop(offsetRequired);
- int bottom = top + getFadeHeight(offsetRequired);
-
- if (offsetRequired) {
- right += getRightPaddingOffset();
- bottom += getBottomPaddingOffset();
- }
- mPerformanceHelper.drawCallback(canvas,
- left, right, top, bottom, mScrollX, mScrollY,
+ mFadedEdgeDrawHelper.drawCallback(canvas,
+ left, right, top + getFadeTop(offsetRequired), bottom, mScrollX, mScrollY,
getTopFadingEdgeStrength(), getBottomFadingEdgeStrength(),
0, 0, mPaddingTop);
}
}
@Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ if (mOnScrollListener != null) {
+ mOnScrollListener.run();
+ }
+ }
+
+ public void setOnScrollListener(Runnable listener) {
+ mOnScrollListener = listener;
+ }
+
+ @Override
public int getVerticalFadingEdgeLength() {
- if (mPerformanceHelper != null) {
- return mPerformanceHelper.getVerticalFadingEdgeLengthCallback();
+ if (mFadedEdgeDrawHelper != null) {
+ return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
} else {
return super.getVerticalFadingEdgeLength();
}
@@ -280,8 +277,8 @@
@Override
public int getHorizontalFadingEdgeLength() {
- if (mPerformanceHelper != null) {
- return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback();
+ if (mFadedEdgeDrawHelper != null) {
+ return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
} else {
return super.getHorizontalFadingEdgeLength();
}
@@ -299,9 +296,8 @@
@Override
public void onAttachedToWindow() {
- if (mPerformanceHelper != null) {
- mPerformanceHelper.onAttachedToWindowCallback(
- mCallback, mLinearLayout, isHardwareAccelerated());
+ if (mFadedEdgeDrawHelper != null) {
+ mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
index 7e979b7..2bc2821 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
@@ -29,7 +29,7 @@
final String packageName; // used to override animations (see onClick())
final CharSequence description;
- private Bitmap mThumbnail; // generated by Activity.onCreateThumbnail()
+ private Drawable mThumbnail; // generated by Activity.onCreateThumbnail()
private Drawable mIcon; // application package icon
private CharSequence mLabel; // application package label
private boolean mLoaded;
@@ -85,11 +85,11 @@
mIcon = icon;
}
- public void setThumbnail(Bitmap thumbnail) {
+ public void setThumbnail(Drawable thumbnail) {
mThumbnail = thumbnail;
}
- public Bitmap getThumbnail() {
+ public Drawable getThumbnail() {
return mThumbnail;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 119299f..2063563 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -196,7 +196,8 @@
// Create screenshot directory if it doesn't exist
mScreenshotDir.mkdirs();
- // media provider uses seconds, not milliseconds
+ // media provider uses seconds for DATE_MODIFIED and DATE_ADDED, but milliseconds
+ // for DATE_TAKEN
long dateSeconds = mImageTime / 1000;
// Save the screenshot to the MediaStore
@@ -205,7 +206,7 @@
values.put(MediaStore.Images.ImageColumns.DATA, mImageFilePath);
values.put(MediaStore.Images.ImageColumns.TITLE, mImageFileName);
values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, mImageFileName);
- values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, dateSeconds);
+ values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, mImageTime);
values.put(MediaStore.Images.ImageColumns.DATE_ADDED, dateSeconds);
values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, dateSeconds);
values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/png");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 6302244..212d704 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -20,7 +20,6 @@
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.ActivityManager;
-import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -35,6 +34,10 @@
public static final int MODE_OPAQUE = 0;
public static final int MODE_SEMI_TRANSPARENT = 1;
public static final int MODE_TRANSPARENT = 2;
+ public static final int MODE_LIGHTS_OUT = 3;
+
+ protected static final int LIGHTS_IN_DURATION = 250;
+ protected static final int LIGHTS_OUT_DURATION = 750;
private final String mTag;
protected final View mTarget;
@@ -52,10 +55,10 @@
}
};
- public BarTransitions(Context context, View target) {
+ public BarTransitions(View target) {
mTag = "BarTransitions." + target.getClass().getSimpleName();
mTarget = target;
- final Resources res = context.getResources();
+ final Resources res = target.getContext().getResources();
mOpaque = res.getColor(R.drawable.status_bar_background);
mSemiTransparent = res.getColor(R.color.status_bar_background_semi_transparent);
}
@@ -76,6 +79,7 @@
protected Integer getBackgroundColor(int mode) {
if (mode == MODE_SEMI_TRANSPARENT) return mSemiTransparent;
if (mode == MODE_OPAQUE) return mOpaque;
+ if (mode == MODE_LIGHTS_OUT) return mOpaque;
return null;
}
@@ -113,6 +117,7 @@
if (mode == MODE_OPAQUE) return "MODE_OPAQUE";
if (mode == MODE_SEMI_TRANSPARENT) return "MODE_SEMI_TRANSPARENT";
if (mode == MODE_TRANSPARENT) return "MODE_TRANSPARENT";
+ if (mode == MODE_LIGHTS_OUT) return "MODE_LIGHTS_OUT";
throw new IllegalArgumentException("Unknown mode " + mode);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
new file mode 100644
index 0000000..085130b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.GradientDrawable.Orientation;
+import android.os.ServiceManager;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.KeyButtonView;
+
+public final class NavigationBarTransitions extends BarTransitions {
+ private static final boolean ENABLE_GRADIENT = false; // until we can smooth transition
+
+ private final NavigationBarView mView;
+ private final Drawable mTransparentBottom;
+ private final Drawable mTransparentRight;
+ private final int mTransparentColor;
+ private final IStatusBarService mBarService;
+
+ private boolean mLightsOut;
+
+ public NavigationBarTransitions(NavigationBarView view) {
+ super(view);
+ mView = view;
+ final Resources res = mView.getContext().getResources();
+ final int[] gradientColors = new int[] {
+ res.getColor(R.color.navigation_bar_background_transparent_start),
+ res.getColor(R.color.navigation_bar_background_transparent_end)
+ };
+ mTransparentBottom = new GradientDrawable(Orientation.BOTTOM_TOP, gradientColors);
+ mTransparentRight = new GradientDrawable(Orientation.RIGHT_LEFT, gradientColors);
+ mTransparentColor = res.getColor(R.color.status_bar_background_transparent);
+ mBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ }
+
+ public void setVertical(boolean isVertical) {
+ if (!ENABLE_GRADIENT) return;
+ mTransparent = isVertical ? mTransparentRight : mTransparentBottom;
+ }
+
+ @Override
+ protected Integer getBackgroundColor(int mode) {
+ if (!ENABLE_GRADIENT && mode == MODE_TRANSPARENT) return mTransparentColor;
+ return super.getBackgroundColor(mode);
+ }
+
+ @Override
+ protected void onTransition(int oldMode, int newMode, boolean animate) {
+ super.onTransition(oldMode, newMode, animate);
+ applyMode(newMode, animate, false /*force*/);
+ }
+
+ public void reapplyMode() {
+ applyMode(getMode(), false /*animate*/, true /*force*/);
+ }
+
+ private void applyMode(int mode, boolean animate, boolean force) {
+ // apply to key buttons
+ final boolean isOpaque = mode == MODE_OPAQUE || mode == MODE_LIGHTS_OUT;
+ final float alpha = isOpaque ? KeyButtonView.DEFAULT_QUIESCENT_ALPHA : 1f;
+ setKeyButtonViewQuiescentAlpha(mView.getBackButton(), alpha, animate);
+ setKeyButtonViewQuiescentAlpha(mView.getHomeButton(), alpha, animate);
+ setKeyButtonViewQuiescentAlpha(mView.getRecentsButton(), alpha, animate);
+ setKeyButtonViewQuiescentAlpha(mView.getMenuButton(), alpha, animate);
+
+ // apply to lights out
+ applyLightsOut(mode == MODE_LIGHTS_OUT, animate, force);
+ }
+
+ private void setKeyButtonViewQuiescentAlpha(View button, float alpha, boolean animate) {
+ if (button instanceof KeyButtonView) {
+ ((KeyButtonView) button).setQuiescentAlpha(alpha, animate);
+ }
+ }
+
+ private void applyLightsOut(boolean lightsOut, boolean animate, boolean force) {
+ if (!force && lightsOut == mLightsOut) return;
+
+ mLightsOut = lightsOut;
+
+ final View navButtons = mView.getCurrentView().findViewById(R.id.nav_buttons);
+ final View lowLights = mView.getCurrentView().findViewById(R.id.lights_out);
+
+ // ok, everyone, stop it right there
+ navButtons.animate().cancel();
+ lowLights.animate().cancel();
+
+ final float navButtonsAlpha = lightsOut ? 0f : 1f;
+ final float lowLightsAlpha = lightsOut ? 1f : 0f;
+
+ if (!animate) {
+ navButtons.setAlpha(navButtonsAlpha);
+ lowLights.setAlpha(lowLightsAlpha);
+ lowLights.setVisibility(lightsOut ? View.VISIBLE : View.GONE);
+ } else {
+ final int duration = lightsOut ? LIGHTS_OUT_DURATION : LIGHTS_IN_DURATION;
+ navButtons.animate()
+ .alpha(navButtonsAlpha)
+ .setDuration(duration)
+ .start();
+
+ lowLights.setOnTouchListener(mLightsOutListener);
+ if (lowLights.getVisibility() == View.GONE) {
+ lowLights.setAlpha(0f);
+ lowLights.setVisibility(View.VISIBLE);
+ }
+ lowLights.animate()
+ .alpha(lowLightsAlpha)
+ .setDuration(duration)
+ .setInterpolator(new AccelerateInterpolator(2.0f))
+ .setListener(lightsOut ? null : new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator _a) {
+ lowLights.setVisibility(View.GONE);
+ }
+ })
+ .start();
+ }
+ }
+
+ private final View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ // even though setting the systemUI visibility below will turn these views
+ // on, we need them to come up faster so that they can catch this motion
+ // event
+ applyLightsOut(false, false, false);
+
+ try {
+ mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ } catch (android.os.RemoteException ex) {
+ }
+ }
+ return false;
+ }
+ };
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 850f94d..b56d7be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.phone;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
import android.app.StatusBarManager;
import android.content.Context;
@@ -25,11 +23,8 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.GradientDrawable.Orientation;
import android.os.Handler;
import android.os.Message;
-import android.os.ServiceManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
@@ -38,16 +33,13 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
-import android.view.animation.AccelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
-import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.DelegateViewHelper;
import com.android.systemui.statusbar.policy.DeadZone;
-import com.android.systemui.statusbar.policy.KeyButtonView;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -59,11 +51,8 @@
final static boolean NAVBAR_ALWAYS_AT_RIGHT = true;
// slippery nav bar when everything is disabled, e.g. during setup
- final static boolean SLIPPERY_WHEN_DISABLED= true;
+ final static boolean SLIPPERY_WHEN_DISABLED = true;
- final static boolean ANIMATE_HIDE_TRANSITION = false; // turned off because it introduces unsightly delay when videos goes to full screen
-
- protected IStatusBarService mBarService;
final Display mDisplay;
View mCurrentView = null;
View[] mRotatedViews = new View[4];
@@ -72,7 +61,7 @@
boolean mVertical;
boolean mScreenOn;
- boolean mHidden, mLowProfile, mShowMenu;
+ boolean mShowMenu;
int mDisabledFlags = 0;
int mNavigationIconHints = 0;
@@ -111,62 +100,11 @@
}
}
- private final class NavigationBarTransitions extends BarTransitions {
- private static final boolean ENABLE_GRADIENT = false; // until we can smooth transition
-
- private final Drawable mTransparentBottom;
- private final Drawable mTransparentRight;
- private final int mTransparentColor;
-
- public NavigationBarTransitions(Context context) {
- super(context, NavigationBarView.this);
- final Resources res = mContext.getResources();
- final int[] gradientColors = new int[] {
- res.getColor(R.color.navigation_bar_background_transparent_start),
- res.getColor(R.color.navigation_bar_background_transparent_end)
- };
- mTransparentBottom = new GradientDrawable(Orientation.BOTTOM_TOP, gradientColors);
- mTransparentRight = new GradientDrawable(Orientation.RIGHT_LEFT, gradientColors);
- mTransparentColor = res.getColor(R.color.status_bar_background_transparent);
- }
-
- public void setVertical(boolean isVertical) {
- if (!ENABLE_GRADIENT) return;
- mTransparent = isVertical ? mTransparentRight : mTransparentBottom;
- }
-
- @Override
- protected Integer getBackgroundColor(int mode) {
- if (!ENABLE_GRADIENT && mode == MODE_TRANSPARENT) return mTransparentColor;
- return super.getBackgroundColor(mode);
- }
-
- @Override
- protected void onTransition(int oldMode, int newMode, boolean animate) {
- super.onTransition(oldMode, newMode, animate);
- final float alpha = newMode == MODE_OPAQUE ? KeyButtonView.DEFAULT_QUIESCENT_ALPHA : 1f;
- setKeyButtonViewQuiescentAlpha(getBackButton(), alpha);
- setKeyButtonViewQuiescentAlpha(getHomeButton(), alpha);
- setKeyButtonViewQuiescentAlpha(getRecentsButton(), alpha);
- setKeyButtonViewQuiescentAlpha(getMenuButton(), alpha);
- }
-
- private void setKeyButtonViewQuiescentAlpha(View button, float alpha) {
- if (button instanceof KeyButtonView) {
- ((KeyButtonView) button).setQuiescentAlpha(alpha);
- }
- }
- }
-
public NavigationBarView(Context context, AttributeSet attrs) {
super(context, attrs);
- mHidden = false;
-
mDisplay = ((WindowManager)context.getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay();
- mBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
final Resources res = mContext.getResources();
mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
@@ -176,7 +114,7 @@
getIcons(res);
- mBarTransitions = new NavigationBarTransitions(context);
+ mBarTransitions = new NavigationBarTransitions(this);
}
public BarTransitions getBarTransitions() {
@@ -210,6 +148,10 @@
private H mHandler = new H();
+ public View getCurrentView() {
+ return mCurrentView;
+ }
+
public View getRecentsButton() {
return mCurrentView.findViewById(R.id.recent_apps);
}
@@ -252,24 +194,6 @@
setDisabledFlags(mDisabledFlags, true);
}
- View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- // even though setting the systemUI visibility below will turn these views
- // on, we need them to come up faster so that they can catch this motion
- // event
- setLowProfile(false, false, false);
-
- try {
- mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
- } catch (android.os.RemoteException ex) {
- }
- }
- return false;
- }
- };
-
public void setNavigationIconHints(int hints) {
setNavigationIconHints(hints, false);
}
@@ -366,65 +290,6 @@
getMenuButton().setVisibility(mShowMenu ? View.VISIBLE : View.INVISIBLE);
}
- public void setLowProfile(final boolean lightsOut) {
- setLowProfile(lightsOut, true, false);
- }
-
- public void setLowProfile(final boolean lightsOut, final boolean animate, final boolean force) {
- if (!force && lightsOut == mLowProfile) return;
-
- mLowProfile = lightsOut;
-
- if (DEBUG) Log.d(TAG, "setting lights " + (lightsOut?"out":"on"));
-
- final View navButtons = mCurrentView.findViewById(R.id.nav_buttons);
- final View lowLights = mCurrentView.findViewById(R.id.lights_out);
-
- // ok, everyone, stop it right there
- navButtons.animate().cancel();
- lowLights.animate().cancel();
-
- if (!animate) {
- navButtons.setAlpha(lightsOut ? 0f : 1f);
-
- lowLights.setAlpha(lightsOut ? 1f : 0f);
- lowLights.setVisibility(lightsOut ? View.VISIBLE : View.GONE);
- } else {
- navButtons.animate()
- .alpha(lightsOut ? 0f : 1f)
- .setDuration(lightsOut ? 750 : 250)
- .start();
-
- lowLights.setOnTouchListener(mLightsOutListener);
- if (lowLights.getVisibility() == View.GONE) {
- lowLights.setAlpha(0f);
- lowLights.setVisibility(View.VISIBLE);
- }
- lowLights.animate()
- .alpha(lightsOut ? 1f : 0f)
- .setDuration(lightsOut ? 750 : 250)
- .setInterpolator(new AccelerateInterpolator(2.0f))
- .setListener(lightsOut ? null : new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator _a) {
- lowLights.setVisibility(View.GONE);
- }
- })
- .start();
- }
- }
-
- public void setHidden(final boolean hide) {
- if (hide == mHidden) return;
-
- mHidden = hide;
- Log.d(TAG,
- (hide ? "HIDING" : "SHOWING") + " navigation bar");
-
- // bring up the lights no matter what
- setLowProfile(false);
- }
-
@Override
public void onFinishInflate() {
mRotatedViews[Surface.ROTATION_0] =
@@ -454,7 +319,7 @@
mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
// force the low profile & disabled states into compliance
- setLowProfile(mLowProfile, false, true /* force */);
+ mBarTransitions.reapplyMode();
setDisabledFlags(mDisabledFlags, true /* force */);
setMenuVisibility(mShowMenu, true /* force */);
@@ -559,11 +424,9 @@
mCurrentView.getWidth(), mCurrentView.getHeight(),
visibilityToString(mCurrentView.getVisibility())));
- pw.println(String.format(" disabled=0x%08x vertical=%s hidden=%s low=%s menu=%s",
+ pw.println(String.format(" disabled=0x%08x vertical=%s menu=%s",
mDisabledFlags,
mVertical ? "true" : "false",
- mHidden ? "true" : "false",
- mLowProfile ? "true" : "false",
mShowMenu ? "true" : "false"));
final View back = getBackButton();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 9db2805..d15626b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -17,15 +17,16 @@
package com.android.systemui.statusbar.phone;
import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
+import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.app.ActivityManager;
@@ -251,9 +252,6 @@
int[] mAbsPos = new int[2];
Runnable mPostCollapseCleanup = null;
- private Animator mLightsOutAnimation;
- private Animator mLightsOnAnimation;
-
// for disabling the status bar
int mDisabled = 0;
@@ -1349,8 +1347,7 @@
};
boolean panelsEnabled() {
- return ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0
- && mStatusBarWindowState != StatusBarManager.WINDOW_STATE_HIDING);
+ return (mDisabled & StatusBarManager.DISABLE_EXPAND) == 0;
}
void makeExpandedVisible() {
@@ -1381,6 +1378,14 @@
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
}
+ private void releaseFocus() {
+ WindowManager.LayoutParams lp =
+ (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams();
+ lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ lp.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ mWindowManager.updateViewLayout(mStatusBarWindow, lp);
+ }
+
public void animateCollapsePanels() {
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
}
@@ -1392,6 +1397,9 @@
+ " flags=" + flags);
}
+ // release focus immediately to kick off focus change transition
+ releaseFocus();
+
if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
@@ -1738,7 +1746,14 @@
}
if (mStatusBarWindowState == WINDOW_STATE_SHOWING) {
- setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
+ final boolean upOrCancel =
+ event.getAction() == MotionEvent.ACTION_UP ||
+ event.getAction() == MotionEvent.ACTION_CANCEL;
+ if (upOrCancel && !mExpandedVisible) {
+ setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
+ } else {
+ setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
+ }
}
return false;
}
@@ -1802,11 +1817,7 @@
}
}
- if (mNavigationBarView != null) {
- mNavigationBarView.setLowProfile(lightsOut);
- }
-
- setStatusBarLowProfile(lightsOut);
+ setAreThereNotifications();
}
// update status bar mode
@@ -1866,6 +1877,7 @@
private int barMode(int vis, int transientFlag, int transparentFlag) {
return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
: (vis & transparentFlag) != 0 ? MODE_TRANSPARENT
+ : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
: MODE_OPAQUE;
}
@@ -1882,7 +1894,7 @@
private void checkBarMode(int mode, int windowState, BarTransitions transitions) {
final boolean imeVisible = (mNavigationIconHints & NAVIGATION_HINT_BACK_ALT) != 0;
final int finalMode = imeVisible ? MODE_OPAQUE : mode;
- final boolean animate = windowState == WINDOW_STATE_SHOWING;
+ final boolean animate = windowState != WINDOW_STATE_HIDDEN;
transitions.transitionTo(finalMode, animate);
}
@@ -1942,47 +1954,6 @@
mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
}
- private void setStatusBarLowProfile(boolean lightsOut) {
- if (mLightsOutAnimation == null) {
- final View notifications = mStatusBarView.findViewById(R.id.notification_icon_area);
- final View systemIcons = mStatusBarView.findViewById(R.id.statusIcons);
- final View signal = mStatusBarView.findViewById(R.id.signal_cluster);
- final View battery = mStatusBarView.findViewById(R.id.battery);
- final View clock = mStatusBarView.findViewById(R.id.clock);
-
- final AnimatorSet lightsOutAnim = new AnimatorSet();
- lightsOutAnim.playTogether(
- ObjectAnimator.ofFloat(notifications, View.ALPHA, 0),
- ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 0),
- ObjectAnimator.ofFloat(signal, View.ALPHA, 0),
- ObjectAnimator.ofFloat(battery, View.ALPHA, 0.5f),
- ObjectAnimator.ofFloat(clock, View.ALPHA, 0.5f)
- );
- lightsOutAnim.setDuration(750);
-
- final AnimatorSet lightsOnAnim = new AnimatorSet();
- lightsOnAnim.playTogether(
- ObjectAnimator.ofFloat(notifications, View.ALPHA, 1),
- ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 1),
- ObjectAnimator.ofFloat(signal, View.ALPHA, 1),
- ObjectAnimator.ofFloat(battery, View.ALPHA, 1),
- ObjectAnimator.ofFloat(clock, View.ALPHA, 1)
- );
- lightsOnAnim.setDuration(250);
-
- mLightsOutAnimation = lightsOutAnim;
- mLightsOnAnimation = lightsOnAnim;
- }
-
- mLightsOutAnimation.cancel();
- mLightsOnAnimation.cancel();
-
- final Animator a = lightsOut ? mLightsOutAnimation : mLightsOnAnimation;
- a.start();
-
- setAreThereNotifications();
- }
-
private boolean areLightsOn() {
return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 159bc62..8957a77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -66,20 +66,6 @@
// bluetooth device status
private boolean mBluetoothEnabled = false;
- // wifi
- private static final int[][] sWifiSignalImages = {
- { R.drawable.stat_sys_wifi_signal_1,
- R.drawable.stat_sys_wifi_signal_2,
- R.drawable.stat_sys_wifi_signal_3,
- R.drawable.stat_sys_wifi_signal_4 },
- { R.drawable.stat_sys_wifi_signal_1_fully,
- R.drawable.stat_sys_wifi_signal_2_fully,
- R.drawable.stat_sys_wifi_signal_3_fully,
- R.drawable.stat_sys_wifi_signal_4_fully }
- };
- private static final int sWifiTemporarilyNotConnectedImage =
- R.drawable.stat_sys_wifi_signal_0;
-
private int mLastWifiSignalLevel = -1;
private boolean mIsWifiConnected = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
new file mode 100644
index 0000000..b9ffd6e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.res.Resources;
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.R;
+
+public final class PhoneStatusBarTransitions extends BarTransitions {
+ private static final float ALPHA_WHEN_TRANSPARENT = 1;
+ private static final float ALPHA_WHEN_LIGHTS_OUT_BATTERY_CLOCK = 0.5f;
+ private static final float ALPHA_WHEN_LIGHTS_OUT_NON_BATTERY_CLOCK = 0;
+
+ private final PhoneStatusBarView mView;
+ private final int mTransparent;
+ private final float mAlphaWhenOpaque;
+
+ private View mLeftSide, mStatusIcons, mSignalCluster, mBattery, mClock;
+ private Animator mCurrentAnimation;
+
+ public PhoneStatusBarTransitions(PhoneStatusBarView view) {
+ super(view);
+ mView = view;
+ final Resources res = mView.getContext().getResources();
+ mTransparent = res.getColor(R.color.status_bar_background_transparent);
+ mAlphaWhenOpaque = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
+ }
+
+ public void init() {
+ mLeftSide = mView.findViewById(R.id.notification_icon_area);
+ mStatusIcons = mView.findViewById(R.id.statusIcons);
+ mSignalCluster = mView.findViewById(R.id.signal_cluster);
+ mBattery = mView.findViewById(R.id.battery);
+ mClock = mView.findViewById(R.id.clock);
+ applyMode(getMode(), false /*animate*/);
+ }
+
+ @Override
+ protected Integer getBackgroundColor(int mode) {
+ if (mode == MODE_TRANSPARENT) return mTransparent;
+ return super.getBackgroundColor(mode);
+ }
+
+ public ObjectAnimator animateTransitionTo(View v, float toAlpha) {
+ return ObjectAnimator.ofFloat(v, "alpha", v.getAlpha(), toAlpha);
+ }
+
+ private float getNonBatteryClockAlphaFor(int mode) {
+ return mode == MODE_LIGHTS_OUT ? ALPHA_WHEN_LIGHTS_OUT_NON_BATTERY_CLOCK
+ : isTransparent(mode) ? ALPHA_WHEN_TRANSPARENT
+ : mAlphaWhenOpaque;
+ }
+
+ private float getBatteryClockAlpha(int mode) {
+ return mode == MODE_LIGHTS_OUT ? ALPHA_WHEN_LIGHTS_OUT_BATTERY_CLOCK
+ : getNonBatteryClockAlphaFor(mode);
+ }
+
+ private boolean isTransparent(int mode) {
+ return mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSPARENT;
+ }
+
+ @Override
+ protected void onTransition(int oldMode, int newMode, boolean animate) {
+ super.onTransition(oldMode, newMode, animate);
+ applyMode(newMode, animate);
+ }
+
+ private void applyMode(int mode, boolean animate) {
+ if (mLeftSide == null) return; // pre-init
+ float newAlpha = getNonBatteryClockAlphaFor(mode);
+ float newAlphaBC = getBatteryClockAlpha(mode);
+ if (mCurrentAnimation != null) {
+ mCurrentAnimation.cancel();
+ }
+ if (animate) {
+ AnimatorSet anims = new AnimatorSet();
+ anims.playTogether(
+ animateTransitionTo(mLeftSide, newAlpha),
+ animateTransitionTo(mStatusIcons, newAlpha),
+ animateTransitionTo(mSignalCluster, newAlpha),
+ animateTransitionTo(mBattery, newAlphaBC),
+ animateTransitionTo(mClock, newAlphaBC)
+ );
+ if (mode == MODE_LIGHTS_OUT) {
+ anims.setDuration(LIGHTS_OUT_DURATION);
+ }
+ anims.start();
+ mCurrentAnimation = anims;
+ } else {
+ mLeftSide.setAlpha(newAlpha);
+ mStatusIcons.setAlpha(newAlpha);
+ mSignalCluster.setAlpha(newAlpha);
+ mBattery.setAlpha(newAlphaBC);
+ mClock.setAlpha(newAlphaBC);
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index b263a6e..d9ac7e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.phone;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Resources;
@@ -47,73 +45,7 @@
PanelView mLastFullyOpenedPanel = null;
PanelView mNotificationPanel, mSettingsPanel;
private boolean mShouldFade;
- private final StatusBarTransitions mBarTransitions;
-
- private final class StatusBarTransitions extends BarTransitions {
- private final int mTransparent;
- private final float mAlphaWhenOpaque;
- private final float mAlphaWhenTransparent = 1;
- private View mLeftSide, mStatusIcons, mSignalCluster, mClock;
-
- public StatusBarTransitions(Context context) {
- super(context, PhoneStatusBarView.this);
- final Resources res = context.getResources();
- mTransparent = res.getColor(R.color.status_bar_background_transparent);
- mAlphaWhenOpaque = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
- }
-
- public void init() {
- mLeftSide = findViewById(R.id.notification_icon_area);
- mStatusIcons = findViewById(R.id.statusIcons);
- mSignalCluster = findViewById(R.id.signal_battery_cluster);
- mClock = findViewById(R.id.clock);
- applyMode(getMode(), false /*animate*/);
- }
-
- @Override
- protected Integer getBackgroundColor(int mode) {
- if (mode == MODE_TRANSPARENT) return mTransparent;
- return super.getBackgroundColor(mode);
- }
-
- public ObjectAnimator animateTransitionTo(View v, float toAlpha) {
- return ObjectAnimator.ofFloat(v, "alpha", v.getAlpha(), toAlpha);
- }
-
- public float getAlphaFor(int mode) {
- return isTransparent(mode) ? mAlphaWhenTransparent : mAlphaWhenOpaque;
- }
-
- private boolean isTransparent(int mode) {
- return mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSPARENT;
- }
-
- @Override
- protected void onTransition(int oldMode, int newMode, boolean animate) {
- super.onTransition(oldMode, newMode, animate);
- applyMode(newMode, animate);
- }
-
- private void applyMode(int mode, boolean animate) {
- if (mLeftSide == null) return; // pre-init
- float newAlpha = getAlphaFor(mode);
- if (animate) {
- AnimatorSet anims = new AnimatorSet();
- anims.playTogether(
- animateTransitionTo(mLeftSide, newAlpha),
- animateTransitionTo(mStatusIcons, newAlpha),
- animateTransitionTo(mSignalCluster, newAlpha),
- animateTransitionTo(mClock, newAlpha)
- );
- anims.start();
- } else {
- mLeftSide.setAlpha(newAlpha);
- mStatusIcons.setAlpha(newAlpha);
- mSignalCluster.setAlpha(newAlpha);
- mClock.setAlpha(newAlpha);
- }
- }
- }
+ private final PhoneStatusBarTransitions mBarTransitions;
public PhoneStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -127,7 +59,7 @@
mSettingsPanelDragzoneFrac = 0f;
}
mFullWidthNotifications = mSettingsPanelDragzoneFrac <= 0f;
- mBarTransitions = new StatusBarTransitions(context);
+ mBarTransitions = new PhoneStatusBarTransitions(this);
}
public BarTransitions getBarTransitions() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index 0d591ba..25ffbd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.animation.ValueAnimator;
import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -62,6 +63,7 @@
import android.widget.TextView;
import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.QuickSettingsModel.ActivityState;
import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState;
import com.android.systemui.statusbar.phone.QuickSettingsModel.RSSIState;
import com.android.systemui.statusbar.phone.QuickSettingsModel.State;
@@ -192,7 +194,7 @@
mQueryCertTask = new AsyncTask<Void, Void, Pair<Boolean, Boolean>>() {
@Override
protected Pair<Boolean, Boolean> doInBackground(Void... params) {
- boolean hasCert = mDevicePolicyManager.hasAnyCaCertsInstalled();
+ boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
return Pair.create(hasCert, isManaged);
@@ -401,8 +403,9 @@
private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) {
// Wi-fi
- final QuickSettingsBasicTile wifiTile
- = new QuickSettingsBasicTile(mContext);
+ final QuickSettingsTileView wifiTile = (QuickSettingsTileView)
+ inflater.inflate(R.layout.quick_settings_tile, parent, false);
+ wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater);
wifiTile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -433,12 +436,15 @@
return true;
}} );
}
- mModel.addWifiTile(wifiTile, new QuickSettingsModel.RefreshCallback() {
+ mModel.addWifiTile(wifiTile, new NetworkActivityCallback() {
@Override
- public void refreshView(QuickSettingsTileView unused, State state) {
+ public void refreshView(QuickSettingsTileView view, State state) {
WifiState wifiState = (WifiState) state;
- wifiTile.setImageResource(wifiState.iconId);
- wifiTile.setText(wifiState.label);
+ ImageView iv = (ImageView) view.findViewById(R.id.image);
+ iv.setImageResource(wifiState.iconId);
+ setActivity(view, wifiState);
+ TextView tv = (TextView) view.findViewById(R.id.text);
+ tv.setText(wifiState.label);
wifiTile.setContentDescription(mContext.getString(
R.string.accessibility_quick_settings_wifi,
wifiState.signalContentDescription,
@@ -462,7 +468,7 @@
startSettingsActivity(intent);
}
});
- mModel.addRSSITile(rssiTile, new QuickSettingsModel.RefreshCallback() {
+ mModel.addRSSITile(rssiTile, new NetworkActivityCallback() {
@Override
public void refreshView(QuickSettingsTileView view, State state) {
RSSIState rssiState = (RSSIState) state;
@@ -478,6 +484,8 @@
} else {
iov.setImageDrawable(null);
}
+ setActivity(view, rssiState);
+
tv.setText(state.label);
view.setContentDescription(mContext.getResources().getString(
R.string.accessibility_quick_settings_mobile,
@@ -663,7 +671,7 @@
alarmTile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- startSettingsActivity(AlarmClock.ACTION_SET_ALARM);
+ startSettingsActivity(AlarmClock.ACTION_SHOW_ALARMS);
}
});
mModel.addAlarmTile(alarmTile, new QuickSettingsModel.RefreshCallback() {
@@ -756,7 +764,7 @@
@Override
public void onClick(View v) {
collapsePanels();
- showSslCaCertWarningDialog();
+ startSettingsActivity(Settings.ACTION_MONITORING_CERT_INFO);
}
});
@@ -824,45 +832,6 @@
dialog.show();
}
- private void showSslCaCertWarningDialog() {
- final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
- builder.setTitle(R.string.ssl_ca_cert_dialog_title);
- builder.setCancelable(true);
- final boolean hasDeviceOwner = mDevicePolicyManager.getDeviceOwner() != null;
- int buttonLabel;
- if (hasDeviceOwner) {
- // Institutional case. Show informational message.
- String message = mContext.getResources().getString(R.string.ssl_ca_cert_info_message,
- mDevicePolicyManager.getDeviceOwnerName());
- builder.setMessage(message);
- buttonLabel = R.string.done_button;
- } else {
- // Consumer case. Show scary warning.
- builder.setMessage(R.string.ssl_ca_cert_warning_message);
- buttonLabel = R.string.ssl_ca_cert_settings_button;
- }
-
- builder.setPositiveButton(buttonLabel, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // do something.
- if (hasDeviceOwner) {
- // Close
- } else {
- startSettingsActivity("com.android.settings.TRUSTED_CREDENTIALS_USER");
- }
- }
- });
-
- final Dialog dialog = builder.create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
- try {
- WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
- } catch (RemoteException e) {
- }
- dialog.show();
- }
-
private void updateWifiDisplayStatus() {
mWifiDisplayStatus = mDisplayManager.getWifiDisplayStatus();
applyWifiDisplayStatus();
@@ -942,4 +911,25 @@
}
};
+
+ private abstract static class NetworkActivityCallback
+ implements QuickSettingsModel.RefreshCallback {
+ private final long mDefaultDuration = new ValueAnimator().getDuration();
+ private final long mShortDuration = mDefaultDuration / 3;
+
+ public void setActivity(View view, ActivityState state) {
+ setVisibility(view.findViewById(R.id.activity_in), state.activityIn);
+ setVisibility(view.findViewById(R.id.activity_out), state.activityOut);
+ }
+
+ private void setVisibility(View view, boolean visible) {
+ final float newAlpha = visible ? 1 : 0;
+ if (view.getAlpha() != newAlpha) {
+ view.animate()
+ .setDuration(visible ? mShortDuration : mDefaultDuration)
+ .alpha(newAlpha)
+ .start();
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index b9e3059..9d0418d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -70,13 +70,17 @@
int batteryLevel;
boolean pluggedIn;
}
- static class RSSIState extends State {
+ static class ActivityState extends State {
+ boolean activityIn;
+ boolean activityOut;
+ }
+ static class RSSIState extends ActivityState {
int signalIconId;
String signalContentDescription;
int dataTypeIconId;
String dataContentDescription;
}
- static class WifiState extends State {
+ static class WifiState extends ActivityState {
String signalContentDescription;
boolean connected;
}
@@ -430,6 +434,7 @@
// NetworkSignalChanged callback
@Override
public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
+ boolean activityIn, boolean activityOut,
String wifiSignalContentDescription, String enabledDesc) {
// TODO: If view is in awaiting state, disable
Resources r = mContext.getResources();
@@ -438,6 +443,8 @@
boolean wifiNotConnected = (wifiSignalIconId > 0) && (enabledDesc == null);
mWifiState.enabled = enabled;
mWifiState.connected = wifiConnected;
+ mWifiState.activityIn = enabled && activityIn;
+ mWifiState.activityOut = enabled && activityOut;
if (wifiConnected) {
mWifiState.iconId = wifiSignalIconId;
mWifiState.label = removeDoubleQuotes(enabledDesc);
@@ -468,7 +475,8 @@
@Override
public void onMobileDataSignalChanged(
boolean enabled, int mobileSignalIconId, String signalContentDescription,
- int dataTypeIconId, String dataContentDescription, String enabledDesc) {
+ int dataTypeIconId, boolean activityIn, boolean activityOut,
+ String dataContentDescription,String enabledDesc) {
if (deviceHasMobileData()) {
// TODO: If view is in awaiting state, disable
Resources r = mContext.getResources();
@@ -481,6 +489,8 @@
mRSSIState.dataTypeIconId = enabled && (dataTypeIconId > 0) && !mWifiState.enabled
? dataTypeIconId
: 0;
+ mRSSIState.activityIn = enabled && activityIn;
+ mRSSIState.activityOut = enabled && activityOut;
mRSSIState.dataContentDescription = enabled && (dataTypeIconId > 0) && !mWifiState.enabled
? dataContentDescription
: r.getString(R.string.accessibility_no_data);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 924478c..55fb95d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -17,8 +17,6 @@
package com.android.systemui.statusbar.policy;
import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
@@ -60,6 +58,7 @@
boolean mSupportsLongpress = true;
RectF mRect = new RectF(0f,0f,0f,0f);
AnimatorSet mPressedAnim;
+ Animator mAnimateToQuiescent = new ObjectAnimator();
Runnable mCheckLongPress = new Runnable() {
public void run() {
@@ -76,15 +75,6 @@
}
};
- private final AnimatorListener mRecoverToQuiescentListener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mQuiescentAlpha != mDrawingAlpha) {
- animateToQuiescent().setDuration(200).start();
- }
- }
- };
-
public KeyButtonView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -133,16 +123,26 @@
super.onDraw(canvas);
}
- public void setQuiescentAlpha(float alpha) {
+ public void setQuiescentAlpha(float alpha, boolean animate) {
+ mAnimateToQuiescent.cancel();
alpha = Math.min(Math.max(alpha, 0), 1);
if (alpha == mQuiescentAlpha) return;
mQuiescentAlpha = alpha;
if (DEBUG) Log.d(TAG, "New quiescent alpha = " + mQuiescentAlpha);
if (mGlowBG != null) {
- setDrawingAlpha(mQuiescentAlpha);
+ if (animate) {
+ mAnimateToQuiescent = animateToQuiescent();
+ mAnimateToQuiescent.start();
+ } else {
+ setDrawingAlpha(mQuiescentAlpha);
+ }
}
}
+ private ObjectAnimator animateToQuiescent() {
+ return ObjectAnimator.ofFloat(this, "drawingAlpha", mQuiescentAlpha);
+ }
+
public float getDrawingAlpha() {
if (mGlowBG == null) return 0;
return mDrawingAlpha;
@@ -197,12 +197,6 @@
}
}
- private ObjectAnimator animateToQuiescent() {
- ObjectAnimator anim = ObjectAnimator.ofFloat(this, "drawingAlpha", mQuiescentAlpha);
- anim.addListener(mRecoverToQuiescentListener); // mQuiescentAlpha may change mid-animation
- return anim;
- }
-
public void setPressed(boolean pressed) {
if (mGlowBG != null) {
if (pressed != isPressed()) {
@@ -222,10 +216,12 @@
);
as.setDuration(50);
} else {
+ mAnimateToQuiescent.cancel();
+ mAnimateToQuiescent = animateToQuiescent();
as.playTogether(
ObjectAnimator.ofFloat(this, "glowAlpha", 0f),
ObjectAnimator.ofFloat(this, "glowScale", 1f),
- animateToQuiescent()
+ mAnimateToQuiescent
);
as.setDuration(500);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 1e7e692..09f1695 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -165,9 +165,11 @@
public interface NetworkSignalChangedCallback {
void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
- String wifitSignalContentDescriptionId, String description);
+ boolean activityIn, boolean activityOut,
+ String wifiSignalContentDescriptionId, String description);
void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId,
String mobileSignalContentDescriptionId, int dataTypeIconId,
+ boolean activityIn, boolean activityOut,
String dataTypeContentDescriptionId, String description);
void onAirplaneModeChanged(boolean enabled);
}
@@ -313,22 +315,33 @@
boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature);
String wifiDesc = wifiEnabled ?
mWifiSsid : null;
- cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, mContentDescriptionWifi, wifiDesc);
+ boolean wifiIn = wifiEnabled && mWifiSsid != null
+ && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
+ || mWifiActivity == WifiManager.DATA_ACTIVITY_IN);
+ boolean wifiOut = wifiEnabled && mWifiSsid != null
+ && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
+ || mWifiActivity == WifiManager.DATA_ACTIVITY_OUT);
+ cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, wifiIn, wifiOut,
+ mContentDescriptionWifi, wifiDesc);
+ boolean mobileIn = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
+ || mDataActivity == TelephonyManager.DATA_ACTIVITY_IN);
+ boolean mobileOut = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
+ || mDataActivity == TelephonyManager.DATA_ACTIVITY_OUT);
if (isEmergencyOnly()) {
cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
- mContentDescriptionPhoneSignal, mQSDataTypeIconId, mContentDescriptionDataType,
- null);
+ mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
+ mContentDescriptionDataType, null);
} else {
if (mIsWimaxEnabled && mWimaxConnected) {
// Wimax is special
cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
- mContentDescriptionPhoneSignal, mQSDataTypeIconId,
+ mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
mContentDescriptionDataType, mNetworkName);
} else {
// Normal mobile data
cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
- mContentDescriptionPhoneSignal, mQSDataTypeIconId,
+ mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
mContentDescriptionDataType, mNetworkName);
}
}
@@ -552,8 +565,8 @@
if (mIsWimaxEnabled && mWimaxConnected) {
// wimax is a special 4g network not handled by telephony
mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_4g;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_4g);
} else {
@@ -572,8 +585,8 @@
case TelephonyManager.NETWORK_TYPE_EDGE:
if (!mShowAtLeastThreeGees) {
mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_e;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_e;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_e;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[mInetCondition];
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_edge);
break;
@@ -582,8 +595,8 @@
}
case TelephonyManager.NETWORK_TYPE_UMTS:
mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_3g);
break;
@@ -593,14 +606,14 @@
case TelephonyManager.NETWORK_TYPE_HSPAP:
if (mHspaDataDistinguishable) {
mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_h;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_h;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_h;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[mInetCondition];
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_3_5g);
} else {
mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_3g);
}
@@ -609,8 +622,8 @@
if (!mShowAtLeastThreeGees) {
// display 1xRTT for IS95A/B
mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_1x;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_cdma);
break;
@@ -620,8 +633,8 @@
case TelephonyManager.NETWORK_TYPE_1xRTT:
if (!mShowAtLeastThreeGees) {
mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_1x;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_cdma);
break;
@@ -633,8 +646,8 @@
case TelephonyManager.NETWORK_TYPE_EVDO_B:
case TelephonyManager.NETWORK_TYPE_EHRPD:
mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_3g);
break;
@@ -642,14 +655,14 @@
boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE);
if (show4GforLTE) {
mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_4g;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_4g);
} else {
mDataIconList = TelephonyIcons.DATA_LTE[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_lte;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_lte;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_lte;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[mInetCondition];
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_lte);
}
@@ -657,14 +670,14 @@
default:
if (!mShowAtLeastThreeGees) {
mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_g;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_g;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_g;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[mInetCondition];
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_gprs);
} else {
mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_3g;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_3g);
}
@@ -674,12 +687,12 @@
if (isCdma()) {
if (isCdmaEri()) {
- mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
}
} else if (mPhone.isNetworkRoaming()) {
- mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
}
}
@@ -1090,12 +1103,12 @@
mQSDataTypeIconId = 0;
if (isCdma()) {
if (isCdmaEri()) {
- mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
}
} else if (mPhone.isNetworkRoaming()) {
- mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
- mQSDataTypeIconId = R.drawable.ic_qs_signal_r;
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
}
}
@@ -1125,6 +1138,11 @@
+ " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId));
}
+ // update QS
+ for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
+ notifySignalsChangedCallbacks(cb);
+ }
+
if (mLastPhoneSignalIconId != mPhoneSignalIconId
|| mLastWifiIconId != mWifiIconId
|| mLastWimaxIconId != mWimaxIconId
@@ -1136,9 +1154,6 @@
for (SignalCluster cluster : mSignalClusters) {
refreshSignalCluster(cluster);
}
- for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
- notifySignalsChangedCallbacks(cb);
- }
}
if (mLastAirplaneMode != mAirplaneMode) {
@@ -1418,14 +1433,15 @@
String datatype = args.getString("datatype");
if (datatype != null) {
mDemoDataTypeIconId =
- datatype.equals("1x") ? R.drawable.stat_sys_data_connected_1x :
- datatype.equals("3g") ? R.drawable.stat_sys_data_connected_3g :
- datatype.equals("4g") ? R.drawable.stat_sys_data_connected_4g :
- datatype.equals("e") ? R.drawable.stat_sys_data_connected_e :
- datatype.equals("g") ? R.drawable.stat_sys_data_connected_g :
- datatype.equals("h") ? R.drawable.stat_sys_data_connected_h :
- datatype.equals("lte") ? R.drawable.stat_sys_data_connected_lte :
- datatype.equals("roam") ? R.drawable.stat_sys_data_connected_roam :
+ datatype.equals("1x") ? R.drawable.stat_sys_data_fully_connected_1x :
+ datatype.equals("3g") ? R.drawable.stat_sys_data_fully_connected_3g :
+ datatype.equals("4g") ? R.drawable.stat_sys_data_fully_connected_4g :
+ datatype.equals("e") ? R.drawable.stat_sys_data_fully_connected_e :
+ datatype.equals("g") ? R.drawable.stat_sys_data_fully_connected_g :
+ datatype.equals("h") ? R.drawable.stat_sys_data_fully_connected_h :
+ datatype.equals("lte") ? R.drawable.stat_sys_data_fully_connected_lte :
+ datatype.equals("roam")
+ ? R.drawable.stat_sys_data_fully_connected_roam :
0;
}
int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index 4b2c65e..67ba879 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -23,11 +23,11 @@
//GSM/UMTS
static final int[][] TELEPHONY_SIGNAL_STRENGTH = {
- { R.drawable.stat_sys_signal_0,
- R.drawable.stat_sys_signal_1,
- R.drawable.stat_sys_signal_2,
- R.drawable.stat_sys_signal_3,
- R.drawable.stat_sys_signal_4 },
+ { R.drawable.stat_sys_signal_0_fully,
+ R.drawable.stat_sys_signal_1_fully,
+ R.drawable.stat_sys_signal_2_fully,
+ R.drawable.stat_sys_signal_3_fully,
+ R.drawable.stat_sys_signal_4_fully },
{ R.drawable.stat_sys_signal_0_fully,
R.drawable.stat_sys_signal_1_fully,
R.drawable.stat_sys_signal_2_fully,
@@ -49,11 +49,11 @@
};
static final int[][] TELEPHONY_SIGNAL_STRENGTH_ROAMING = {
- { R.drawable.stat_sys_signal_0,
- R.drawable.stat_sys_signal_1,
- R.drawable.stat_sys_signal_2,
- R.drawable.stat_sys_signal_3,
- R.drawable.stat_sys_signal_4 },
+ { R.drawable.stat_sys_signal_0_fully,
+ R.drawable.stat_sys_signal_1_fully,
+ R.drawable.stat_sys_signal_2_fully,
+ R.drawable.stat_sys_signal_3_fully,
+ R.drawable.stat_sys_signal_4_fully },
{ R.drawable.stat_sys_signal_0_fully,
R.drawable.stat_sys_signal_1_fully,
R.drawable.stat_sys_signal_2_fully,
@@ -61,92 +61,132 @@
R.drawable.stat_sys_signal_4_fully }
};
+ static final int[] QS_DATA_R = {
+ R.drawable.ic_qs_signal_r,
+ R.drawable.ic_qs_signal_full_r
+ };
+
static final int[][] DATA_SIGNAL_STRENGTH = TELEPHONY_SIGNAL_STRENGTH;
//***** Data connection icons
//GSM/UMTS
static final int[][] DATA_G = {
- { R.drawable.stat_sys_data_connected_g,
- R.drawable.stat_sys_data_connected_g,
- R.drawable.stat_sys_data_connected_g,
- R.drawable.stat_sys_data_connected_g },
+ { R.drawable.stat_sys_data_fully_connected_g,
+ R.drawable.stat_sys_data_fully_connected_g,
+ R.drawable.stat_sys_data_fully_connected_g,
+ R.drawable.stat_sys_data_fully_connected_g },
{ R.drawable.stat_sys_data_fully_connected_g,
R.drawable.stat_sys_data_fully_connected_g,
R.drawable.stat_sys_data_fully_connected_g,
R.drawable.stat_sys_data_fully_connected_g }
};
+ static final int[] QS_DATA_G = {
+ R.drawable.ic_qs_signal_g,
+ R.drawable.ic_qs_signal_full_g
+ };
+
static final int[][] DATA_3G = {
- { R.drawable.stat_sys_data_connected_3g,
- R.drawable.stat_sys_data_connected_3g,
- R.drawable.stat_sys_data_connected_3g,
- R.drawable.stat_sys_data_connected_3g },
+ { R.drawable.stat_sys_data_fully_connected_3g,
+ R.drawable.stat_sys_data_fully_connected_3g,
+ R.drawable.stat_sys_data_fully_connected_3g,
+ R.drawable.stat_sys_data_fully_connected_3g },
{ R.drawable.stat_sys_data_fully_connected_3g,
R.drawable.stat_sys_data_fully_connected_3g,
R.drawable.stat_sys_data_fully_connected_3g,
R.drawable.stat_sys_data_fully_connected_3g }
};
+ static final int[] QS_DATA_3G = {
+ R.drawable.ic_qs_signal_3g,
+ R.drawable.ic_qs_signal_full_3g
+ };
+
static final int[][] DATA_E = {
- { R.drawable.stat_sys_data_connected_e,
- R.drawable.stat_sys_data_connected_e,
- R.drawable.stat_sys_data_connected_e,
- R.drawable.stat_sys_data_connected_e },
+ { R.drawable.stat_sys_data_fully_connected_e,
+ R.drawable.stat_sys_data_fully_connected_e,
+ R.drawable.stat_sys_data_fully_connected_e,
+ R.drawable.stat_sys_data_fully_connected_e },
{ R.drawable.stat_sys_data_fully_connected_e,
R.drawable.stat_sys_data_fully_connected_e,
R.drawable.stat_sys_data_fully_connected_e,
R.drawable.stat_sys_data_fully_connected_e }
};
+ static final int[] QS_DATA_E = {
+ R.drawable.ic_qs_signal_e,
+ R.drawable.ic_qs_signal_full_e
+ };
+
//3.5G
static final int[][] DATA_H = {
- { R.drawable.stat_sys_data_connected_h,
- R.drawable.stat_sys_data_connected_h,
- R.drawable.stat_sys_data_connected_h,
- R.drawable.stat_sys_data_connected_h },
+ { R.drawable.stat_sys_data_fully_connected_h,
+ R.drawable.stat_sys_data_fully_connected_h,
+ R.drawable.stat_sys_data_fully_connected_h,
+ R.drawable.stat_sys_data_fully_connected_h },
{ R.drawable.stat_sys_data_fully_connected_h,
R.drawable.stat_sys_data_fully_connected_h,
R.drawable.stat_sys_data_fully_connected_h,
R.drawable.stat_sys_data_fully_connected_h }
};
+ static final int[] QS_DATA_H = {
+ R.drawable.ic_qs_signal_h,
+ R.drawable.ic_qs_signal_full_h
+ };
+
//CDMA
// Use 3G icons for EVDO data and 1x icons for 1XRTT data
static final int[][] DATA_1X = {
- { R.drawable.stat_sys_data_connected_1x,
- R.drawable.stat_sys_data_connected_1x,
- R.drawable.stat_sys_data_connected_1x,
- R.drawable.stat_sys_data_connected_1x },
+ { R.drawable.stat_sys_data_fully_connected_1x,
+ R.drawable.stat_sys_data_fully_connected_1x,
+ R.drawable.stat_sys_data_fully_connected_1x,
+ R.drawable.stat_sys_data_fully_connected_1x },
{ R.drawable.stat_sys_data_fully_connected_1x,
R.drawable.stat_sys_data_fully_connected_1x,
R.drawable.stat_sys_data_fully_connected_1x,
R.drawable.stat_sys_data_fully_connected_1x }
};
+ static final int[] QS_DATA_1X = {
+ R.drawable.ic_qs_signal_1x,
+ R.drawable.ic_qs_signal_full_1x
+ };
+
// LTE and eHRPD
static final int[][] DATA_4G = {
- { R.drawable.stat_sys_data_connected_4g,
- R.drawable.stat_sys_data_connected_4g,
- R.drawable.stat_sys_data_connected_4g,
- R.drawable.stat_sys_data_connected_4g },
+ { R.drawable.stat_sys_data_fully_connected_4g,
+ R.drawable.stat_sys_data_fully_connected_4g,
+ R.drawable.stat_sys_data_fully_connected_4g,
+ R.drawable.stat_sys_data_fully_connected_4g },
{ R.drawable.stat_sys_data_fully_connected_4g,
R.drawable.stat_sys_data_fully_connected_4g,
R.drawable.stat_sys_data_fully_connected_4g,
R.drawable.stat_sys_data_fully_connected_4g }
};
+ static final int[] QS_DATA_4G = {
+ R.drawable.ic_qs_signal_4g,
+ R.drawable.ic_qs_signal_full_4g
+ };
+
// LTE branded "LTE"
static final int[][] DATA_LTE = {
- { R.drawable.stat_sys_data_connected_lte,
- R.drawable.stat_sys_data_connected_lte,
- R.drawable.stat_sys_data_connected_lte,
- R.drawable.stat_sys_data_connected_lte },
+ { R.drawable.stat_sys_data_fully_connected_lte,
+ R.drawable.stat_sys_data_fully_connected_lte,
+ R.drawable.stat_sys_data_fully_connected_lte,
+ R.drawable.stat_sys_data_fully_connected_lte },
{ R.drawable.stat_sys_data_fully_connected_lte,
R.drawable.stat_sys_data_fully_connected_lte,
R.drawable.stat_sys_data_fully_connected_lte,
R.drawable.stat_sys_data_fully_connected_lte }
};
+ static final int[] QS_DATA_LTE = {
+ R.drawable.ic_qs_signal_lte,
+ R.drawable.ic_qs_signal_full_lte
+ };
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
index 8cc0338..57ddf7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
@@ -21,10 +21,10 @@
class WifiIcons {
static final int[][] WIFI_SIGNAL_STRENGTH = {
{ R.drawable.stat_sys_wifi_signal_0,
- R.drawable.stat_sys_wifi_signal_1,
- R.drawable.stat_sys_wifi_signal_2,
- R.drawable.stat_sys_wifi_signal_3,
- R.drawable.stat_sys_wifi_signal_4 },
+ R.drawable.stat_sys_wifi_signal_1_fully,
+ R.drawable.stat_sys_wifi_signal_2_fully,
+ R.drawable.stat_sys_wifi_signal_3_fully,
+ R.drawable.stat_sys_wifi_signal_4_fully },
{ R.drawable.stat_sys_wifi_signal_0,
R.drawable.stat_sys_wifi_signal_1_fully,
R.drawable.stat_sys_wifi_signal_2_fully,
diff --git a/packages/VpnDialogs/res/values-en-rIN/strings.xml b/packages/VpnDialogs/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..afc46d8
--- /dev/null
+++ b/packages/VpnDialogs/res/values-en-rIN/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="prompt" msgid="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> attempts to create a VPN connection."</string>
+ <string name="warning" msgid="5470743576660160079">"By proceeding, you are giving the application permission to intercept all network traffic. "<b>"Do NOT accept unless you trust the application."</b>" Otherwise, you run the risk of having your data compromised by malicious software."</string>
+ <string name="accept" msgid="2889226408765810173">"I trust this application."</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN is connected"</string>
+ <string name="configure" msgid="4905518375574791375">"Configure"</string>
+ <string name="disconnect" msgid="971412338304200056">"Disconnect"</string>
+ <string name="session" msgid="6470628549473641030">"Session:"</string>
+ <string name="duration" msgid="3584782459928719435">"Duration:"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"Sent:"</string>
+ <string name="data_received" msgid="4062776929376067820">"Received:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> bytes / <xliff:g id="NUMBER_1">%2$s</xliff:g> packets"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-et-rEE/strings.xml b/packages/VpnDialogs/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..c016eb0
--- /dev/null
+++ b/packages/VpnDialogs/res/values-et-rEE/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="prompt" msgid="8359175999006833462">"Rakenduse <xliff:g id="APP">%s</xliff:g> katsed luua VPN-ühendust."</string>
+ <string name="warning" msgid="5470743576660160079">"Jätkates annate rakendusele loa jälgida kogu võrguliiklust. "<b>"ÄRGE nõustuge, kui te seda rakendust ei usalda."</b>" Vastasel juhul on oht, et pahavara võib kahjustada teie andmeid."</string>
+ <string name="accept" msgid="2889226408765810173">"Usaldan seda rakendust."</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN on ühendatud"</string>
+ <string name="configure" msgid="4905518375574791375">"Seadistamine"</string>
+ <string name="disconnect" msgid="971412338304200056">"Katkesta ühendus"</string>
+ <string name="session" msgid="6470628549473641030">"Seansid"</string>
+ <string name="duration" msgid="3584782459928719435">"Kestus:"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"Saadetud:"</string>
+ <string name="data_received" msgid="4062776929376067820">"Vastu on võetud:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> baiti / <xliff:g id="NUMBER_1">%2$s</xliff:g> paketti"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-fr-rCA/strings.xml b/packages/VpnDialogs/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..1028f83
--- /dev/null
+++ b/packages/VpnDialogs/res/values-fr-rCA/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="prompt" msgid="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> tente de créer une connexion VPN."</string>
+ <string name="warning" msgid="5470743576660160079">"En continuant, vous autorisez l\'application à intercepter l\'ensemble du trafic réseau. "<b>"N\'acceptez PAS, sauf si vous avez confiance en l\'application."</b>"Sinon, vos données risquent d\'être piratées par un logiciel malveillant."</string>
+ <string name="accept" msgid="2889226408765810173">"J\'ai confiance en cette application."</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN connecté"</string>
+ <string name="configure" msgid="4905518375574791375">"Configurer"</string>
+ <string name="disconnect" msgid="971412338304200056">"Déconnecter"</string>
+ <string name="session" msgid="6470628549473641030">"Session :"</string>
+ <string name="duration" msgid="3584782459928719435">"Durée :"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"Date d\'envoi :"</string>
+ <string name="data_received" msgid="4062776929376067820">"Reçu le :"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> octets / <xliff:g id="NUMBER_1">%2$s</xliff:g> paquets"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-hi/strings.xml b/packages/VpnDialogs/res/values-hi/strings.xml
index e2cb51a..50be98c 100644
--- a/packages/VpnDialogs/res/values-hi/strings.xml
+++ b/packages/VpnDialogs/res/values-hi/strings.xml
@@ -17,8 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> एक VPN कनेक्शन बनाने का प्रयास करता है."</string>
- <string name="warning" msgid="5470743576660160079">"जारी रखकर, आप एप्लिकेशन को सभी नेटवर्क ट्रैफ़िक अवरोधित करने की अनुमति देते हैं. "<b>"जब तक आपको एप्लिकेशन पर विश्वास न हो स्वीकार न करें."</b>" अन्यथा, आपको अपने डेटा के साथ किसी दुर्भावनापूर्ण सॉफ़्टवेयर द्वारा छेड़छाड़ किए जाने का जोखिम हो सकता है."</string>
- <string name="accept" msgid="2889226408765810173">"मुझे इस एप्लिकेशन पर विश्वास है."</string>
+ <string name="warning" msgid="5470743576660160079">"जारी रखकर, आप एप्स को सभी नेटवर्क ट्रैफ़िक अवरोधित करने की अनुमति देते हैं. "<b>"जब तक आपको एप्स पर विश्वास न हो स्वीकार न करें."</b>" अन्यथा, आपको अपने डेटा के साथ किसी दुर्भावनापूर्ण सॉफ़्टवेयर द्वारा छेड़छाड़ किए जाने का जोखिम हो सकता है."</string>
+ <string name="accept" msgid="2889226408765810173">"मुझे इस एप्स पर विश्वास है."</string>
<string name="legacy_title" msgid="192936250066580964">"VPN कनेक्ट है"</string>
<string name="configure" msgid="4905518375574791375">"कॉन्फ़िगर करें"</string>
<string name="disconnect" msgid="971412338304200056">"डिस्कनेक्ट करें"</string>
diff --git a/packages/VpnDialogs/res/values-hy-rAM/strings.xml b/packages/VpnDialogs/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..85db579
--- /dev/null
+++ b/packages/VpnDialogs/res/values-hy-rAM/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="prompt" msgid="8359175999006833462">"<xliff:g id="APP">%s</xliff:g>-ը փորձում է ստեղծել VPN կապ:"</string>
+ <string name="warning" msgid="5470743576660160079">"Շարունակելով` դուք հավելվածին թույլատրում եք կանգնեցնել ամբողջ ցանցային շարժը: "<b>"Մի ընդունեք, եթե չեք վստահում հավելվածին:"</b>" Այլապես ռիսկ կա ձեր տվյալները վտանգելու վնասարար հավելվածների կողմից:"</string>
+ <string name="accept" msgid="2889226408765810173">"Ես վստահում եմ այս ծրագրին:"</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN-ը կապակցված է"</string>
+ <string name="configure" msgid="4905518375574791375">"Կարգավորել"</string>
+ <string name="disconnect" msgid="971412338304200056">"Անջատել"</string>
+ <string name="session" msgid="6470628549473641030">"Աշխատաշրջան`"</string>
+ <string name="duration" msgid="3584782459928719435">"Տևողությունը՝"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"Ուղարկվել է՝"</string>
+ <string name="data_received" msgid="4062776929376067820">"Ստացվել է՝"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> բայթ / <xliff:g id="NUMBER_1">%2$s</xliff:g> փաթեթ"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-ka-rGE/strings.xml b/packages/VpnDialogs/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..960d3f6
--- /dev/null
+++ b/packages/VpnDialogs/res/values-ka-rGE/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="prompt" msgid="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> ცდილობს VPN კავშირის შექმნას."</string>
+ <string name="warning" msgid="5470743576660160079">"გაგრძელების შემთხვევაში, აპლიკაციას ექნება ქსელში გადაცემული მონაცემების მოპოვების საშუალება. "<b>"არ განაგრძოთ, თუ არ ენდობით აპლიკაციას."</b>" წინააღმდეგ შემთვევაში შესაძლოა მავნე პროგრამას თქვენ მონაცემებთან წვდომის საშუალება მიეცეს."</string>
+ <string name="accept" msgid="2889226408765810173">"ვენდობი ამ აპლიკაციას."</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN დაკავშირებულია"</string>
+ <string name="configure" msgid="4905518375574791375">"კონფიგურაცია"</string>
+ <string name="disconnect" msgid="971412338304200056">"კავშირის გაწყვეტა"</string>
+ <string name="session" msgid="6470628549473641030">"სესია:"</string>
+ <string name="duration" msgid="3584782459928719435">"ხანგრძლივობა:"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"გაგზავნილი:"</string>
+ <string name="data_received" msgid="4062776929376067820">"მიღებული:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> ბაიტი / <xliff:g id="NUMBER_1">%2$s</xliff:g> პაკეტი"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-km-rKH/strings.xml b/packages/VpnDialogs/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..2c79e26
--- /dev/null
+++ b/packages/VpnDialogs/res/values-km-rKH/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="prompt" msgid="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> ព្យាយាមបង្កើតការតភ្ជាប់ VPN ។"</string>
+ <string name="warning" msgid="5470743576660160079">"ដោយបន្ត អ្នកកំពុងផ្ដល់សិទ្ធិឲ្យកម្មវិធីទប់ស្កាត់ចរាចរណ៍បណ្ដាញ។ "<b>"កុំទទួល លុះត្រាតែអ្នកទុកចិត្តកម្មវិធី។"</b>" បើមិនដូច្នេះទេ អ្នកដំណើរការប្រឈមនឹងគ្រោះថ្នាក់ ដោយទិន្នន័យរបស់អ្នកបានសម្របសម្រួលដោយកម្មវិធីព្យាបាទ។"</string>
+ <string name="accept" msgid="2889226408765810173">"ខ្ញុំទុកចិត្តកម្មវិធីនេះ។"</string>
+ <string name="legacy_title" msgid="192936250066580964">"បានភ្ជាប់ VPN"</string>
+ <string name="configure" msgid="4905518375574791375">"កំណត់រចនាសម្ព័ន្ធ"</string>
+ <string name="disconnect" msgid="971412338304200056">"ផ្ដាច់"</string>
+ <string name="session" msgid="6470628549473641030">"សម័យ៖"</string>
+ <string name="duration" msgid="3584782459928719435">"ថិរវេលា៖"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"បានផ្ញើ៖"</string>
+ <string name="data_received" msgid="4062776929376067820">"បានទទួល៖"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> បៃ / <xliff:g id="NUMBER_1">%2$s</xliff:g> កញ្ចប់ព័ត៌មាន"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-lo-rLA/strings.xml b/packages/VpnDialogs/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..9f5216b
--- /dev/null
+++ b/packages/VpnDialogs/res/values-lo-rLA/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="prompt" msgid="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> ພະຍາຍາມສ້າງການເຊື່ອມຕໍ່ VPN."</string>
+ <string name="warning" msgid="5470743576660160079">"ຖ້າດຳເນີນຕໍ່, ແມ່ນທ່ານກຳລັງຈະໃຫ້ສິດແກ່ແອັບພລິເຄຊັນ ໃນການດັກຂໍ້ມູນຈະລາຈອນໃນເຄືອຂ່າຍທັງໝົດ. "<b>"ຢ່າຍອມຮັບ ນອກຈາກວ່າທ່ານຈະເຊື່ອໃຈແອັບພລິເຄຊັນດັ່ງກ່າວ."</b>" ຖ້າບໍ່ດັ່ງນັ້ນ, ທ່ານຈະຕົກຢູ່ໃນຄວາມສ່ຽງ ທີ່ຂໍ້ມູນຂອງທ່ານຈະຖືກຄຸກຄາມໂດຍຊອບແວທີ່ເປັນອັນຕະລາຍ."</string>
+ <string name="accept" msgid="2889226408765810173">"ຂ້ອຍເຊື່ອແອັບພລິເຄຊັນນີ້."</string>
+ <string name="legacy_title" msgid="192936250066580964">"ເຊື່ອມຕໍ່ VPN ແລ້ວ"</string>
+ <string name="configure" msgid="4905518375574791375">"ປັບຄ່າ"</string>
+ <string name="disconnect" msgid="971412338304200056">"ຕັດການເຊື່ອມຕໍ່"</string>
+ <string name="session" msgid="6470628549473641030">"ເຊສຊັນ:"</string>
+ <string name="duration" msgid="3584782459928719435">"ໄລຍະເວລາ:"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"ສົ່ງ:"</string>
+ <string name="data_received" msgid="4062776929376067820">"ຮັບ:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> ໄບ / <xliff:g id="NUMBER_1">%2$s</xliff:g> ແພັກເກັດ"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-mn-rMN/strings.xml b/packages/VpnDialogs/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..887bb73
--- /dev/null
+++ b/packages/VpnDialogs/res/values-mn-rMN/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="prompt" msgid="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> VPN холболтыг үүсгэх гэж байна."</string>
+ <string name="warning" msgid="5470743576660160079">"Үргэлжлүүлсэнээр та аппликешнд бүх сүлжээний урсгалыг таслах зөвшөөрлийг өгөх болно. "<b>"Аппикешн баталгаагүй гэж үзсэн тохиолдолд л зөвшөөрч болорхгүй."</b>" Бусад тохиолдолд та өөрийн датаг хортой софтверийн аюулд өртөх эрсдэлийг үүсгэж байна."</string>
+ <string name="accept" msgid="2889226408765810173">"Би энэ аппликешнд итгэж байна."</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN холбогдов"</string>
+ <string name="configure" msgid="4905518375574791375">"Тохируулах"</string>
+ <string name="disconnect" msgid="971412338304200056">"Салгах"</string>
+ <string name="session" msgid="6470628549473641030">"Сешн:"</string>
+ <string name="duration" msgid="3584782459928719435">"Үргэлжлэх хугацаа:"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"Илгээсэн:"</string>
+ <string name="data_received" msgid="4062776929376067820">"Хүлээн авсан:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> байт/ <xliff:g id="NUMBER_1">%2$s</xliff:g> пакет"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-ms-rMY/strings.xml b/packages/VpnDialogs/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..417fbae
--- /dev/null
+++ b/packages/VpnDialogs/res/values-ms-rMY/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="prompt" msgid="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> percubaan untuk membuat sambungan VPN."</string>
+ <string name="warning" msgid="5470743576660160079">"Dengan meneruskan, anda memberi keizinan kepada aplikasi untuk memintas semua trafik rangkaian. "<b>"JANGAN terima melainkan anda mempercayai aplikasi itu."</b>" Jika tidak, anda akan mengalami risiko data terjejas oleh perisian berniat jahat."</string>
+ <string name="accept" msgid="2889226408765810173">"Saya percayai aplikasi ini."</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN telah disambungkan"</string>
+ <string name="configure" msgid="4905518375574791375">"Konfigurasikan"</string>
+ <string name="disconnect" msgid="971412338304200056">"Putuskan sambungan"</string>
+ <string name="session" msgid="6470628549473641030">"Sesi:"</string>
+ <string name="duration" msgid="3584782459928719435">"Tempoh:"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"Dihantar:"</string>
+ <string name="data_received" msgid="4062776929376067820">"Diterima:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> bait / <xliff:g id="NUMBER_1">%2$s</xliff:g> bingkisan"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-nb/strings.xml b/packages/VpnDialogs/res/values-nb/strings.xml
index f716422..6bffc98 100644
--- a/packages/VpnDialogs/res/values-nb/strings.xml
+++ b/packages/VpnDialogs/res/values-nb/strings.xml
@@ -17,8 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> forsøker å etablere en VPN-tilkobling."</string>
- <string name="warning" msgid="5470743576660160079">"Ved å fortsette gir du applikasjonen tillatelse til å fange opp all nettverkstrafikk. "<b>"IKKE godta med mindre du stoler på applikasjonen."</b>" Ellers risikerer du at dataene dine kompromitteres av en ondsinnet programvare."</string>
- <string name="accept" msgid="2889226408765810173">"Jeg stoler på denne applikasjonen."</string>
+ <string name="warning" msgid="5470743576660160079">"Ved å fortsette gir du appen tillatelse til å fange opp all nettverkstrafikk. "<b>"IKKE godta med mindre du stoler på appen."</b>" Ellers risikerer du at dataene dine kompromitteres av en ondsinnet programvare."</string>
+ <string name="accept" msgid="2889226408765810173">"Jeg stoler på denne appen."</string>
<string name="legacy_title" msgid="192936250066580964">"VPN er tilkoblet"</string>
<string name="configure" msgid="4905518375574791375">"Konfigurer"</string>
<string name="disconnect" msgid="971412338304200056">"Koble fra"</string>
diff --git a/packages/VpnDialogs/res/values-zh-rHK/strings.xml b/packages/VpnDialogs/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..8b25d41
--- /dev/null
+++ b/packages/VpnDialogs/res/values-zh-rHK/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="prompt" msgid="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> 嘗試建立 VPN 連線。"</string>
+ <string name="warning" msgid="5470743576660160079">"如果繼續進行,即表示您允許該應用程式攔截所有網絡流量。"<b>"除非您信任該應用程式,否則不應接受。"</b>"不然就會讓您的資料陷於遭惡意程式入侵的風險。"</string>
+ <string name="accept" msgid="2889226408765810173">"我信任這個應用程式。"</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN 已連線"</string>
+ <string name="configure" msgid="4905518375574791375">"設定"</string>
+ <string name="disconnect" msgid="971412338304200056">"中斷連線"</string>
+ <string name="session" msgid="6470628549473641030">"時段:"</string>
+ <string name="duration" msgid="3584782459928719435">"持續時間︰"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"已傳送:"</string>
+ <string name="data_received" msgid="4062776929376067820">"已接收:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> 位元組 / <xliff:g id="NUMBER_1">%2$s</xliff:g> 封包"</string>
+</resources>
diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk
new file mode 100644
index 0000000..09b41fd
--- /dev/null
+++ b/packages/WallpaperCropper/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := telephony-common
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+
+LOCAL_PACKAGE_NAME := WallpaperCropper
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/WallpaperCropper/AndroidManifest.xml b/packages/WallpaperCropper/AndroidManifest.xml
new file mode 100644
index 0000000..27755bd
--- /dev/null
+++ b/packages/WallpaperCropper/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wallpapercropper" >
+ <uses-permission android:name="android.permission.SET_WALLPAPER" />
+ <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
+
+ <application android:requiredForAllUsers="true">
+ <activity
+ android:name="WallpaperCropActivity"
+ android:theme="@style/Theme.WallpaperCropper"
+ android:label="@string/crop_wallpaper"
+ android:finishOnCloseSystemDialogs="true">
+ <intent-filter>
+ <action android:name="android.service.wallpaper.CROP_AND_SET_WALLPAPER" />
+ <data android:mimeType="image/*" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/packages/WallpaperCropper/proguard.flags b/packages/WallpaperCropper/proguard.flags
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/WallpaperCropper/proguard.flags
diff --git a/packages/WallpaperCropper/res/drawable-hdpi/ic_actionbar_accept.png b/packages/WallpaperCropper/res/drawable-hdpi/ic_actionbar_accept.png
new file mode 100755
index 0000000..53cf687
--- /dev/null
+++ b/packages/WallpaperCropper/res/drawable-hdpi/ic_actionbar_accept.png
Binary files differ
diff --git a/packages/WallpaperCropper/res/drawable-mdpi/ic_actionbar_accept.png b/packages/WallpaperCropper/res/drawable-mdpi/ic_actionbar_accept.png
new file mode 100755
index 0000000..35cda8e
--- /dev/null
+++ b/packages/WallpaperCropper/res/drawable-mdpi/ic_actionbar_accept.png
Binary files differ
diff --git a/packages/WallpaperCropper/res/drawable-xhdpi/ic_actionbar_accept.png b/packages/WallpaperCropper/res/drawable-xhdpi/ic_actionbar_accept.png
new file mode 100755
index 0000000..b52dc37
--- /dev/null
+++ b/packages/WallpaperCropper/res/drawable-xhdpi/ic_actionbar_accept.png
Binary files differ
diff --git a/packages/WallpaperCropper/res/layout/actionbar_set_wallpaper.xml b/packages/WallpaperCropper/res/layout/actionbar_set_wallpaper.xml
new file mode 100644
index 0000000..1622742
--- /dev/null
+++ b/packages/WallpaperCropper/res/layout/actionbar_set_wallpaper.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ style="?android:actionButtonStyle"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+ <TextView style="?android:actionBarTabTextStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start|center_vertical"
+ android:paddingRight="20dp"
+ android:drawableLeft="@drawable/ic_actionbar_accept"
+ android:drawablePadding="8dp"
+ android:gravity="center_vertical"
+ android:text="@string/wallpaper_instructions" />
+</FrameLayout>
diff --git a/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml b/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml
new file mode 100644
index 0000000..6dc7e35
--- /dev/null
+++ b/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/wallpaper_cropper"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <com.android.wallpapercropper.CropView
+ android:id="@+id/cropView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ <ProgressBar
+ android:id="@+id/loading"
+ style="@android:style/Widget.Holo.ProgressBar.Large"
+ android:visibility="invisible"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:indeterminate="true"
+ android:indeterminateOnly="true"
+ android:background="@android:color/transparent" />
+</RelativeLayout>
diff --git a/packages/WallpaperCropper/res/values/strings.xml b/packages/WallpaperCropper/res/values/strings.xml
new file mode 100644
index 0000000..2b8111d
--- /dev/null
+++ b/packages/WallpaperCropper/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="crop_wallpaper">Crop wallpaper</string>
+ <!-- Button label on Wallpaper picker screen; user selects this button to set a specific wallpaper -->
+ <string name="wallpaper_instructions">Set wallpaper</string>
+</resources>
diff --git a/packages/WallpaperCropper/res/values/styles.xml b/packages/WallpaperCropper/res/values/styles.xml
new file mode 100644
index 0000000..2b63fe0
--- /dev/null
+++ b/packages/WallpaperCropper/res/values/styles.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <style name="Theme.WallpaperCropper" parent="@android:style/Theme.Holo">
+ <item name="android:actionBarStyle">@style/WallpaperCropperActionBar</item>
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowActionBarOverlay">true</item>
+ </style>
+
+ <style name="WallpaperCropperActionBar" parent="android:style/Widget.Holo.ActionBar">
+ <item name="android:displayOptions">showCustom</item>
+ <item name="android:background">#88000000</item>
+ </style>
+</resources>
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/common/BitmapUtils.java b/packages/WallpaperCropper/src/com/android/gallery3d/common/BitmapUtils.java
new file mode 100644
index 0000000..a671ed2
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/common/BitmapUtils.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.common;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.os.Build;
+import android.util.FloatMath;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class BitmapUtils {
+ private static final String TAG = "BitmapUtils";
+ private static final int DEFAULT_JPEG_QUALITY = 90;
+ public static final int UNCONSTRAINED = -1;
+
+ private BitmapUtils(){}
+
+ /*
+ * Compute the sample size as a function of minSideLength
+ * and maxNumOfPixels.
+ * minSideLength is used to specify that minimal width or height of a
+ * bitmap.
+ * maxNumOfPixels is used to specify the maximal size in pixels that is
+ * tolerable in terms of memory usage.
+ *
+ * The function returns a sample size based on the constraints.
+ * Both size and minSideLength can be passed in as UNCONSTRAINED,
+ * which indicates no care of the corresponding constraint.
+ * The functions prefers returning a sample size that
+ * generates a smaller bitmap, unless minSideLength = UNCONSTRAINED.
+ *
+ * Also, the function rounds up the sample size to a power of 2 or multiple
+ * of 8 because BitmapFactory only honors sample size this way.
+ * For example, BitmapFactory downsamples an image by 2 even though the
+ * request is 3. So we round up the sample size to avoid OOM.
+ */
+ public static int computeSampleSize(int width, int height,
+ int minSideLength, int maxNumOfPixels) {
+ int initialSize = computeInitialSampleSize(
+ width, height, minSideLength, maxNumOfPixels);
+
+ return initialSize <= 8
+ ? Utils.nextPowerOf2(initialSize)
+ : (initialSize + 7) / 8 * 8;
+ }
+
+ private static int computeInitialSampleSize(int w, int h,
+ int minSideLength, int maxNumOfPixels) {
+ if (maxNumOfPixels == UNCONSTRAINED
+ && minSideLength == UNCONSTRAINED) return 1;
+
+ int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 :
+ (int) FloatMath.ceil(FloatMath.sqrt((float) (w * h) / maxNumOfPixels));
+
+ if (minSideLength == UNCONSTRAINED) {
+ return lowerBound;
+ } else {
+ int sampleSize = Math.min(w / minSideLength, h / minSideLength);
+ return Math.max(sampleSize, lowerBound);
+ }
+ }
+
+ // This computes a sample size which makes the longer side at least
+ // minSideLength long. If that's not possible, return 1.
+ public static int computeSampleSizeLarger(int w, int h,
+ int minSideLength) {
+ int initialSize = Math.max(w / minSideLength, h / minSideLength);
+ if (initialSize <= 1) return 1;
+
+ return initialSize <= 8
+ ? Utils.prevPowerOf2(initialSize)
+ : initialSize / 8 * 8;
+ }
+
+ // Find the min x that 1 / x >= scale
+ public static int computeSampleSizeLarger(float scale) {
+ int initialSize = (int) FloatMath.floor(1f / scale);
+ if (initialSize <= 1) return 1;
+
+ return initialSize <= 8
+ ? Utils.prevPowerOf2(initialSize)
+ : initialSize / 8 * 8;
+ }
+
+ // Find the max x that 1 / x <= scale.
+ public static int computeSampleSize(float scale) {
+ Utils.assertTrue(scale > 0);
+ int initialSize = Math.max(1, (int) FloatMath.ceil(1 / scale));
+ return initialSize <= 8
+ ? Utils.nextPowerOf2(initialSize)
+ : (initialSize + 7) / 8 * 8;
+ }
+
+ public static Bitmap resizeBitmapByScale(
+ Bitmap bitmap, float scale, boolean recycle) {
+ int width = Math.round(bitmap.getWidth() * scale);
+ int height = Math.round(bitmap.getHeight() * scale);
+ if (width == bitmap.getWidth()
+ && height == bitmap.getHeight()) return bitmap;
+ Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap));
+ Canvas canvas = new Canvas(target);
+ canvas.scale(scale, scale);
+ Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
+ canvas.drawBitmap(bitmap, 0, 0, paint);
+ if (recycle) bitmap.recycle();
+ return target;
+ }
+
+ private static Bitmap.Config getConfig(Bitmap bitmap) {
+ Bitmap.Config config = bitmap.getConfig();
+ if (config == null) {
+ config = Bitmap.Config.ARGB_8888;
+ }
+ return config;
+ }
+
+ public static Bitmap resizeDownBySideLength(
+ Bitmap bitmap, int maxLength, boolean recycle) {
+ int srcWidth = bitmap.getWidth();
+ int srcHeight = bitmap.getHeight();
+ float scale = Math.min(
+ (float) maxLength / srcWidth, (float) maxLength / srcHeight);
+ if (scale >= 1.0f) return bitmap;
+ return resizeBitmapByScale(bitmap, scale, recycle);
+ }
+
+ public static Bitmap resizeAndCropCenter(Bitmap bitmap, int size, boolean recycle) {
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+ if (w == size && h == size) return bitmap;
+
+ // scale the image so that the shorter side equals to the target;
+ // the longer side will be center-cropped.
+ float scale = (float) size / Math.min(w, h);
+
+ Bitmap target = Bitmap.createBitmap(size, size, getConfig(bitmap));
+ int width = Math.round(scale * bitmap.getWidth());
+ int height = Math.round(scale * bitmap.getHeight());
+ Canvas canvas = new Canvas(target);
+ canvas.translate((size - width) / 2f, (size - height) / 2f);
+ canvas.scale(scale, scale);
+ Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
+ canvas.drawBitmap(bitmap, 0, 0, paint);
+ if (recycle) bitmap.recycle();
+ return target;
+ }
+
+ public static void recycleSilently(Bitmap bitmap) {
+ if (bitmap == null) return;
+ try {
+ bitmap.recycle();
+ } catch (Throwable t) {
+ Log.w(TAG, "unable recycle bitmap", t);
+ }
+ }
+
+ public static Bitmap rotateBitmap(Bitmap source, int rotation, boolean recycle) {
+ if (rotation == 0) return source;
+ int w = source.getWidth();
+ int h = source.getHeight();
+ Matrix m = new Matrix();
+ m.postRotate(rotation);
+ Bitmap bitmap = Bitmap.createBitmap(source, 0, 0, w, h, m, true);
+ if (recycle) source.recycle();
+ return bitmap;
+ }
+
+ public static Bitmap createVideoThumbnail(String filePath) {
+ // MediaMetadataRetriever is available on API Level 8
+ // but is hidden until API Level 10
+ Class<?> clazz = null;
+ Object instance = null;
+ try {
+ clazz = Class.forName("android.media.MediaMetadataRetriever");
+ instance = clazz.newInstance();
+
+ Method method = clazz.getMethod("setDataSource", String.class);
+ method.invoke(instance, filePath);
+
+ // The method name changes between API Level 9 and 10.
+ if (Build.VERSION.SDK_INT <= 9) {
+ return (Bitmap) clazz.getMethod("captureFrame").invoke(instance);
+ } else {
+ byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance);
+ if (data != null) {
+ Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
+ if (bitmap != null) return bitmap;
+ }
+ return (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance);
+ }
+ } catch (IllegalArgumentException ex) {
+ // Assume this is a corrupt video file
+ } catch (RuntimeException ex) {
+ // Assume this is a corrupt video file.
+ } catch (InstantiationException e) {
+ Log.e(TAG, "createVideoThumbnail", e);
+ } catch (InvocationTargetException e) {
+ Log.e(TAG, "createVideoThumbnail", e);
+ } catch (ClassNotFoundException e) {
+ Log.e(TAG, "createVideoThumbnail", e);
+ } catch (NoSuchMethodException e) {
+ Log.e(TAG, "createVideoThumbnail", e);
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, "createVideoThumbnail", e);
+ } finally {
+ try {
+ if (instance != null) {
+ clazz.getMethod("release").invoke(instance);
+ }
+ } catch (Exception ignored) {
+ }
+ }
+ return null;
+ }
+
+ public static byte[] compressToBytes(Bitmap bitmap) {
+ return compressToBytes(bitmap, DEFAULT_JPEG_QUALITY);
+ }
+
+ public static byte[] compressToBytes(Bitmap bitmap, int quality) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(65536);
+ bitmap.compress(CompressFormat.JPEG, quality, baos);
+ return baos.toByteArray();
+ }
+
+ public static boolean isSupportedByRegionDecoder(String mimeType) {
+ if (mimeType == null) return false;
+ mimeType = mimeType.toLowerCase();
+ return mimeType.startsWith("image/") &&
+ (!mimeType.equals("image/gif") && !mimeType.endsWith("bmp"));
+ }
+
+ public static boolean isRotationSupported(String mimeType) {
+ if (mimeType == null) return false;
+ mimeType = mimeType.toLowerCase();
+ return mimeType.equals("image/jpeg");
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/common/Utils.java b/packages/WallpaperCropper/src/com/android/gallery3d/common/Utils.java
new file mode 100644
index 0000000..614a081
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/common/Utils.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.common;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.Cursor;
+import android.os.Build;
+import android.os.ParcelFileDescriptor;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+
+public class Utils {
+ private static final String TAG = "Utils";
+ private static final String DEBUG_TAG = "GalleryDebug";
+
+ private static final long POLY64REV = 0x95AC9329AC4BC9B5L;
+ private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL;
+
+ private static long[] sCrcTable = new long[256];
+
+ private static final boolean IS_DEBUG_BUILD =
+ Build.TYPE.equals("eng") || Build.TYPE.equals("userdebug");
+
+ private static final String MASK_STRING = "********************************";
+
+ // Throws AssertionError if the input is false.
+ public static void assertTrue(boolean cond) {
+ if (!cond) {
+ throw new AssertionError();
+ }
+ }
+
+ // Throws AssertionError with the message. We had a method having the form
+ // assertTrue(boolean cond, String message, Object ... args);
+ // However a call to that method will cause memory allocation even if the
+ // condition is false (due to autoboxing generated by "Object ... args"),
+ // so we don't use that anymore.
+ public static void fail(String message, Object ... args) {
+ throw new AssertionError(
+ args.length == 0 ? message : String.format(message, args));
+ }
+
+ // Throws NullPointerException if the input is null.
+ public static <T> T checkNotNull(T object) {
+ if (object == null) throw new NullPointerException();
+ return object;
+ }
+
+ // Returns true if two input Object are both null or equal
+ // to each other.
+ public static boolean equals(Object a, Object b) {
+ return (a == b) || (a == null ? false : a.equals(b));
+ }
+
+ // Returns the next power of two.
+ // Returns the input if it is already power of 2.
+ // Throws IllegalArgumentException if the input is <= 0 or
+ // the answer overflows.
+ public static int nextPowerOf2(int n) {
+ if (n <= 0 || n > (1 << 30)) throw new IllegalArgumentException("n is invalid: " + n);
+ n -= 1;
+ n |= n >> 16;
+ n |= n >> 8;
+ n |= n >> 4;
+ n |= n >> 2;
+ n |= n >> 1;
+ return n + 1;
+ }
+
+ // Returns the previous power of two.
+ // Returns the input if it is already power of 2.
+ // Throws IllegalArgumentException if the input is <= 0
+ public static int prevPowerOf2(int n) {
+ if (n <= 0) throw new IllegalArgumentException();
+ return Integer.highestOneBit(n);
+ }
+
+ // Returns the input value x clamped to the range [min, max].
+ public static int clamp(int x, int min, int max) {
+ if (x > max) return max;
+ if (x < min) return min;
+ return x;
+ }
+
+ // Returns the input value x clamped to the range [min, max].
+ public static float clamp(float x, float min, float max) {
+ if (x > max) return max;
+ if (x < min) return min;
+ return x;
+ }
+
+ // Returns the input value x clamped to the range [min, max].
+ public static long clamp(long x, long min, long max) {
+ if (x > max) return max;
+ if (x < min) return min;
+ return x;
+ }
+
+ public static boolean isOpaque(int color) {
+ return color >>> 24 == 0xFF;
+ }
+
+ public static void swap(int[] array, int i, int j) {
+ int temp = array[i];
+ array[i] = array[j];
+ array[j] = temp;
+ }
+
+ /**
+ * A function thats returns a 64-bit crc for string
+ *
+ * @param in input string
+ * @return a 64-bit crc value
+ */
+ public static final long crc64Long(String in) {
+ if (in == null || in.length() == 0) {
+ return 0;
+ }
+ return crc64Long(getBytes(in));
+ }
+
+ static {
+ // http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c
+ long part;
+ for (int i = 0; i < 256; i++) {
+ part = i;
+ for (int j = 0; j < 8; j++) {
+ long x = ((int) part & 1) != 0 ? POLY64REV : 0;
+ part = (part >> 1) ^ x;
+ }
+ sCrcTable[i] = part;
+ }
+ }
+
+ public static final long crc64Long(byte[] buffer) {
+ long crc = INITIALCRC;
+ for (int k = 0, n = buffer.length; k < n; ++k) {
+ crc = sCrcTable[(((int) crc) ^ buffer[k]) & 0xff] ^ (crc >> 8);
+ }
+ return crc;
+ }
+
+ public static byte[] getBytes(String in) {
+ byte[] result = new byte[in.length() * 2];
+ int output = 0;
+ for (char ch : in.toCharArray()) {
+ result[output++] = (byte) (ch & 0xFF);
+ result[output++] = (byte) (ch >> 8);
+ }
+ return result;
+ }
+
+ public static void closeSilently(Closeable c) {
+ if (c == null) return;
+ try {
+ c.close();
+ } catch (IOException t) {
+ Log.w(TAG, "close fail ", t);
+ }
+ }
+
+ public static int compare(long a, long b) {
+ return a < b ? -1 : a == b ? 0 : 1;
+ }
+
+ public static int ceilLog2(float value) {
+ int i;
+ for (i = 0; i < 31; i++) {
+ if ((1 << i) >= value) break;
+ }
+ return i;
+ }
+
+ public static int floorLog2(float value) {
+ int i;
+ for (i = 0; i < 31; i++) {
+ if ((1 << i) > value) break;
+ }
+ return i - 1;
+ }
+
+ public static void closeSilently(ParcelFileDescriptor fd) {
+ try {
+ if (fd != null) fd.close();
+ } catch (Throwable t) {
+ Log.w(TAG, "fail to close", t);
+ }
+ }
+
+ public static void closeSilently(Cursor cursor) {
+ try {
+ if (cursor != null) cursor.close();
+ } catch (Throwable t) {
+ Log.w(TAG, "fail to close", t);
+ }
+ }
+
+ public static float interpolateAngle(
+ float source, float target, float progress) {
+ // interpolate the angle from source to target
+ // We make the difference in the range of [-179, 180], this is the
+ // shortest path to change source to target.
+ float diff = target - source;
+ if (diff < 0) diff += 360f;
+ if (diff > 180) diff -= 360f;
+
+ float result = source + diff * progress;
+ return result < 0 ? result + 360f : result;
+ }
+
+ public static float interpolateScale(
+ float source, float target, float progress) {
+ return source + progress * (target - source);
+ }
+
+ public static String ensureNotNull(String value) {
+ return value == null ? "" : value;
+ }
+
+ public static float parseFloatSafely(String content, float defaultValue) {
+ if (content == null) return defaultValue;
+ try {
+ return Float.parseFloat(content);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ public static int parseIntSafely(String content, int defaultValue) {
+ if (content == null) return defaultValue;
+ try {
+ return Integer.parseInt(content);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ public static boolean isNullOrEmpty(String exifMake) {
+ return TextUtils.isEmpty(exifMake);
+ }
+
+ public static void waitWithoutInterrupt(Object object) {
+ try {
+ object.wait();
+ } catch (InterruptedException e) {
+ Log.w(TAG, "unexpected interrupt: " + object);
+ }
+ }
+
+ public static boolean handleInterrruptedException(Throwable e) {
+ // A helper to deal with the interrupt exception
+ // If an interrupt detected, we will setup the bit again.
+ if (e instanceof InterruptedIOException
+ || e instanceof InterruptedException) {
+ Thread.currentThread().interrupt();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @return String with special XML characters escaped.
+ */
+ public static String escapeXml(String s) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0, len = s.length(); i < len; ++i) {
+ char c = s.charAt(i);
+ switch (c) {
+ case '<': sb.append("<"); break;
+ case '>': sb.append(">"); break;
+ case '\"': sb.append("""); break;
+ case '\'': sb.append("'"); break;
+ case '&': sb.append("&"); break;
+ default: sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+ public static String getUserAgent(Context context) {
+ PackageInfo packageInfo;
+ try {
+ packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
+ } catch (NameNotFoundException e) {
+ throw new IllegalStateException("getPackageInfo failed");
+ }
+ return String.format("%s/%s; %s/%s/%s/%s; %s/%s/%s",
+ packageInfo.packageName,
+ packageInfo.versionName,
+ Build.BRAND,
+ Build.DEVICE,
+ Build.MODEL,
+ Build.ID,
+ Build.VERSION.SDK_INT,
+ Build.VERSION.RELEASE,
+ Build.VERSION.INCREMENTAL);
+ }
+
+ public static String[] copyOf(String[] source, int newSize) {
+ String[] result = new String[newSize];
+ newSize = Math.min(source.length, newSize);
+ System.arraycopy(source, 0, result, 0, newSize);
+ return result;
+ }
+
+ // Mask information for debugging only. It returns <code>info.toString()</code> directly
+ // for debugging build (i.e., 'eng' and 'userdebug') and returns a mask ("****")
+ // in release build to protect the information (e.g. for privacy issue).
+ public static String maskDebugInfo(Object info) {
+ if (info == null) return null;
+ String s = info.toString();
+ int length = Math.min(s.length(), MASK_STRING.length());
+ return IS_DEBUG_BUILD ? s : MASK_STRING.substring(0, length);
+ }
+
+ // This method should be ONLY used for debugging.
+ public static void debug(String message, Object ... args) {
+ Log.v(DEBUG_TAG, String.format(message, args));
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ByteBufferInputStream.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ByteBufferInputStream.java
new file mode 100644
index 0000000..7fb9f22
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ByteBufferInputStream.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+class ByteBufferInputStream extends InputStream {
+
+ private ByteBuffer mBuf;
+
+ public ByteBufferInputStream(ByteBuffer buf) {
+ mBuf = buf;
+ }
+
+ @Override
+ public int read() {
+ if (!mBuf.hasRemaining()) {
+ return -1;
+ }
+ return mBuf.get() & 0xFF;
+ }
+
+ @Override
+ public int read(byte[] bytes, int off, int len) {
+ if (!mBuf.hasRemaining()) {
+ return -1;
+ }
+
+ len = Math.min(len, mBuf.remaining());
+ mBuf.get(bytes, off, len);
+ return len;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/CountedDataInputStream.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/CountedDataInputStream.java
new file mode 100644
index 0000000..dfd4a1a
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/CountedDataInputStream.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+class CountedDataInputStream extends FilterInputStream {
+
+ private int mCount = 0;
+
+ // allocate a byte buffer for a long value;
+ private final byte mByteArray[] = new byte[8];
+ private final ByteBuffer mByteBuffer = ByteBuffer.wrap(mByteArray);
+
+ protected CountedDataInputStream(InputStream in) {
+ super(in);
+ }
+
+ public int getReadByteCount() {
+ return mCount;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ int r = in.read(b);
+ mCount += (r >= 0) ? r : 0;
+ return r;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ int r = in.read(b, off, len);
+ mCount += (r >= 0) ? r : 0;
+ return r;
+ }
+
+ @Override
+ public int read() throws IOException {
+ int r = in.read();
+ mCount += (r >= 0) ? 1 : 0;
+ return r;
+ }
+
+ @Override
+ public long skip(long length) throws IOException {
+ long skip = in.skip(length);
+ mCount += skip;
+ return skip;
+ }
+
+ public void skipOrThrow(long length) throws IOException {
+ if (skip(length) != length) throw new EOFException();
+ }
+
+ public void skipTo(long target) throws IOException {
+ long cur = mCount;
+ long diff = target - cur;
+ assert(diff >= 0);
+ skipOrThrow(diff);
+ }
+
+ public void readOrThrow(byte[] b, int off, int len) throws IOException {
+ int r = read(b, off, len);
+ if (r != len) throw new EOFException();
+ }
+
+ public void readOrThrow(byte[] b) throws IOException {
+ readOrThrow(b, 0, b.length);
+ }
+
+ public void setByteOrder(ByteOrder order) {
+ mByteBuffer.order(order);
+ }
+
+ public ByteOrder getByteOrder() {
+ return mByteBuffer.order();
+ }
+
+ public short readShort() throws IOException {
+ readOrThrow(mByteArray, 0 ,2);
+ mByteBuffer.rewind();
+ return mByteBuffer.getShort();
+ }
+
+ public int readUnsignedShort() throws IOException {
+ return readShort() & 0xffff;
+ }
+
+ public int readInt() throws IOException {
+ readOrThrow(mByteArray, 0 , 4);
+ mByteBuffer.rewind();
+ return mByteBuffer.getInt();
+ }
+
+ public long readUnsignedInt() throws IOException {
+ return readInt() & 0xffffffffL;
+ }
+
+ public long readLong() throws IOException {
+ readOrThrow(mByteArray, 0 , 8);
+ mByteBuffer.rewind();
+ return mByteBuffer.getLong();
+ }
+
+ public String readString(int n) throws IOException {
+ byte buf[] = new byte[n];
+ readOrThrow(buf);
+ return new String(buf, "UTF8");
+ }
+
+ public String readString(int n, Charset charset) throws IOException {
+ byte buf[] = new byte[n];
+ readOrThrow(buf);
+ return new String(buf, charset);
+ }
+}
\ No newline at end of file
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifData.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifData.java
new file mode 100644
index 0000000..8422382
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifData.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This class stores the EXIF header in IFDs according to the JPEG
+ * specification. It is the result produced by {@link ExifReader}.
+ *
+ * @see ExifReader
+ * @see IfdData
+ */
+class ExifData {
+ private static final String TAG = "ExifData";
+ private static final byte[] USER_COMMENT_ASCII = {
+ 0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00
+ };
+ private static final byte[] USER_COMMENT_JIS = {
+ 0x4A, 0x49, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ private static final byte[] USER_COMMENT_UNICODE = {
+ 0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0x00
+ };
+
+ private final IfdData[] mIfdDatas = new IfdData[IfdId.TYPE_IFD_COUNT];
+ private byte[] mThumbnail;
+ private ArrayList<byte[]> mStripBytes = new ArrayList<byte[]>();
+ private final ByteOrder mByteOrder;
+
+ ExifData(ByteOrder order) {
+ mByteOrder = order;
+ }
+
+ /**
+ * Gets the compressed thumbnail. Returns null if there is no compressed
+ * thumbnail.
+ *
+ * @see #hasCompressedThumbnail()
+ */
+ protected byte[] getCompressedThumbnail() {
+ return mThumbnail;
+ }
+
+ /**
+ * Sets the compressed thumbnail.
+ */
+ protected void setCompressedThumbnail(byte[] thumbnail) {
+ mThumbnail = thumbnail;
+ }
+
+ /**
+ * Returns true it this header contains a compressed thumbnail.
+ */
+ protected boolean hasCompressedThumbnail() {
+ return mThumbnail != null;
+ }
+
+ /**
+ * Adds an uncompressed strip.
+ */
+ protected void setStripBytes(int index, byte[] strip) {
+ if (index < mStripBytes.size()) {
+ mStripBytes.set(index, strip);
+ } else {
+ for (int i = mStripBytes.size(); i < index; i++) {
+ mStripBytes.add(null);
+ }
+ mStripBytes.add(strip);
+ }
+ }
+
+ /**
+ * Gets the strip count.
+ */
+ protected int getStripCount() {
+ return mStripBytes.size();
+ }
+
+ /**
+ * Gets the strip at the specified index.
+ *
+ * @exceptions #IndexOutOfBoundException
+ */
+ protected byte[] getStrip(int index) {
+ return mStripBytes.get(index);
+ }
+
+ /**
+ * Returns true if this header contains uncompressed strip.
+ */
+ protected boolean hasUncompressedStrip() {
+ return mStripBytes.size() != 0;
+ }
+
+ /**
+ * Gets the byte order.
+ */
+ protected ByteOrder getByteOrder() {
+ return mByteOrder;
+ }
+
+ /**
+ * Returns the {@link IfdData} object corresponding to a given IFD if it
+ * exists or null.
+ */
+ protected IfdData getIfdData(int ifdId) {
+ if (ExifTag.isValidIfd(ifdId)) {
+ return mIfdDatas[ifdId];
+ }
+ return null;
+ }
+
+ /**
+ * Adds IFD data. If IFD data of the same type already exists, it will be
+ * replaced by the new data.
+ */
+ protected void addIfdData(IfdData data) {
+ mIfdDatas[data.getId()] = data;
+ }
+
+ /**
+ * Returns the {@link IfdData} object corresponding to a given IFD or
+ * generates one if none exist.
+ */
+ protected IfdData getOrCreateIfdData(int ifdId) {
+ IfdData ifdData = mIfdDatas[ifdId];
+ if (ifdData == null) {
+ ifdData = new IfdData(ifdId);
+ mIfdDatas[ifdId] = ifdData;
+ }
+ return ifdData;
+ }
+
+ /**
+ * Returns the tag with a given TID in the given IFD if the tag exists.
+ * Otherwise returns null.
+ */
+ protected ExifTag getTag(short tag, int ifd) {
+ IfdData ifdData = mIfdDatas[ifd];
+ return (ifdData == null) ? null : ifdData.getTag(tag);
+ }
+
+ /**
+ * Adds the given ExifTag to its default IFD and returns an existing ExifTag
+ * with the same TID or null if none exist.
+ */
+ protected ExifTag addTag(ExifTag tag) {
+ if (tag != null) {
+ int ifd = tag.getIfd();
+ return addTag(tag, ifd);
+ }
+ return null;
+ }
+
+ /**
+ * Adds the given ExifTag to the given IFD and returns an existing ExifTag
+ * with the same TID or null if none exist.
+ */
+ protected ExifTag addTag(ExifTag tag, int ifdId) {
+ if (tag != null && ExifTag.isValidIfd(ifdId)) {
+ IfdData ifdData = getOrCreateIfdData(ifdId);
+ return ifdData.setTag(tag);
+ }
+ return null;
+ }
+
+ protected void clearThumbnailAndStrips() {
+ mThumbnail = null;
+ mStripBytes.clear();
+ }
+
+ /**
+ * Removes the thumbnail and its related tags. IFD1 will be removed.
+ */
+ protected void removeThumbnailData() {
+ clearThumbnailAndStrips();
+ mIfdDatas[IfdId.TYPE_IFD_1] = null;
+ }
+
+ /**
+ * Removes the tag with a given TID and IFD.
+ */
+ protected void removeTag(short tagId, int ifdId) {
+ IfdData ifdData = mIfdDatas[ifdId];
+ if (ifdData == null) {
+ return;
+ }
+ ifdData.removeTag(tagId);
+ }
+
+ /**
+ * Decodes the user comment tag into string as specified in the EXIF
+ * standard. Returns null if decoding failed.
+ */
+ protected String getUserComment() {
+ IfdData ifdData = mIfdDatas[IfdId.TYPE_IFD_0];
+ if (ifdData == null) {
+ return null;
+ }
+ ExifTag tag = ifdData.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_USER_COMMENT));
+ if (tag == null) {
+ return null;
+ }
+ if (tag.getComponentCount() < 8) {
+ return null;
+ }
+
+ byte[] buf = new byte[tag.getComponentCount()];
+ tag.getBytes(buf);
+
+ byte[] code = new byte[8];
+ System.arraycopy(buf, 0, code, 0, 8);
+
+ try {
+ if (Arrays.equals(code, USER_COMMENT_ASCII)) {
+ return new String(buf, 8, buf.length - 8, "US-ASCII");
+ } else if (Arrays.equals(code, USER_COMMENT_JIS)) {
+ return new String(buf, 8, buf.length - 8, "EUC-JP");
+ } else if (Arrays.equals(code, USER_COMMENT_UNICODE)) {
+ return new String(buf, 8, buf.length - 8, "UTF-16");
+ } else {
+ return null;
+ }
+ } catch (UnsupportedEncodingException e) {
+ Log.w(TAG, "Failed to decode the user comment");
+ return null;
+ }
+ }
+
+ /**
+ * Returns a list of all {@link ExifTag}s in the ExifData or null if there
+ * are none.
+ */
+ protected List<ExifTag> getAllTags() {
+ ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
+ for (IfdData d : mIfdDatas) {
+ if (d != null) {
+ ExifTag[] tags = d.getAllTags();
+ if (tags != null) {
+ for (ExifTag t : tags) {
+ ret.add(t);
+ }
+ }
+ }
+ }
+ if (ret.size() == 0) {
+ return null;
+ }
+ return ret;
+ }
+
+ /**
+ * Returns a list of all {@link ExifTag}s in a given IFD or null if there
+ * are none.
+ */
+ protected List<ExifTag> getAllTagsForIfd(int ifd) {
+ IfdData d = mIfdDatas[ifd];
+ if (d == null) {
+ return null;
+ }
+ ExifTag[] tags = d.getAllTags();
+ if (tags == null) {
+ return null;
+ }
+ ArrayList<ExifTag> ret = new ArrayList<ExifTag>(tags.length);
+ for (ExifTag t : tags) {
+ ret.add(t);
+ }
+ if (ret.size() == 0) {
+ return null;
+ }
+ return ret;
+ }
+
+ /**
+ * Returns a list of all {@link ExifTag}s with a given TID or null if there
+ * are none.
+ */
+ protected List<ExifTag> getAllTagsForTagId(short tag) {
+ ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
+ for (IfdData d : mIfdDatas) {
+ if (d != null) {
+ ExifTag t = d.getTag(tag);
+ if (t != null) {
+ ret.add(t);
+ }
+ }
+ }
+ if (ret.size() == 0) {
+ return null;
+ }
+ return ret;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (obj instanceof ExifData) {
+ ExifData data = (ExifData) obj;
+ if (data.mByteOrder != mByteOrder ||
+ data.mStripBytes.size() != mStripBytes.size() ||
+ !Arrays.equals(data.mThumbnail, mThumbnail)) {
+ return false;
+ }
+ for (int i = 0; i < mStripBytes.size(); i++) {
+ if (!Arrays.equals(data.mStripBytes.get(i), mStripBytes.get(i))) {
+ return false;
+ }
+ }
+ for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
+ IfdData ifd1 = data.getIfdData(i);
+ IfdData ifd2 = getIfdData(i);
+ if (ifd1 != ifd2 && ifd1 != null && !ifd1.equals(ifd2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInterface.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInterface.java
new file mode 100644
index 0000000..a1cf0fc
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInterface.java
@@ -0,0 +1,2407 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.util.SparseIntArray;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel.MapMode;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.TimeZone;
+
+/**
+ * This class provides methods and constants for reading and writing jpeg file
+ * metadata. It contains a collection of ExifTags, and a collection of
+ * definitions for creating valid ExifTags. The collection of ExifTags can be
+ * updated by: reading new ones from a file, deleting or adding existing ones,
+ * or building new ExifTags from a tag definition. These ExifTags can be written
+ * to a valid jpeg image as exif metadata.
+ * <p>
+ * Each ExifTag has a tag ID (TID) and is stored in a specific image file
+ * directory (IFD) as specified by the exif standard. A tag definition can be
+ * looked up with a constant that is a combination of TID and IFD. This
+ * definition has information about the type, number of components, and valid
+ * IFDs for a tag.
+ *
+ * @see ExifTag
+ */
+public class ExifInterface {
+ public static final int TAG_NULL = -1;
+ public static final int IFD_NULL = -1;
+ public static final int DEFINITION_NULL = 0;
+
+ /**
+ * Tag constants for Jeita EXIF 2.2
+ */
+
+ // IFD 0
+ public static final int TAG_IMAGE_WIDTH =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0100);
+ public static final int TAG_IMAGE_LENGTH =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0101); // Image height
+ public static final int TAG_BITS_PER_SAMPLE =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0102);
+ public static final int TAG_COMPRESSION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0103);
+ public static final int TAG_PHOTOMETRIC_INTERPRETATION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0106);
+ public static final int TAG_IMAGE_DESCRIPTION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x010E);
+ public static final int TAG_MAKE =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x010F);
+ public static final int TAG_MODEL =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0110);
+ public static final int TAG_STRIP_OFFSETS =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0111);
+ public static final int TAG_ORIENTATION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0112);
+ public static final int TAG_SAMPLES_PER_PIXEL =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0115);
+ public static final int TAG_ROWS_PER_STRIP =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0116);
+ public static final int TAG_STRIP_BYTE_COUNTS =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0117);
+ public static final int TAG_X_RESOLUTION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x011A);
+ public static final int TAG_Y_RESOLUTION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x011B);
+ public static final int TAG_PLANAR_CONFIGURATION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x011C);
+ public static final int TAG_RESOLUTION_UNIT =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0128);
+ public static final int TAG_TRANSFER_FUNCTION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x012D);
+ public static final int TAG_SOFTWARE =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0131);
+ public static final int TAG_DATE_TIME =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0132);
+ public static final int TAG_ARTIST =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x013B);
+ public static final int TAG_WHITE_POINT =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x013E);
+ public static final int TAG_PRIMARY_CHROMATICITIES =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x013F);
+ public static final int TAG_Y_CB_CR_COEFFICIENTS =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0211);
+ public static final int TAG_Y_CB_CR_SUB_SAMPLING =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0212);
+ public static final int TAG_Y_CB_CR_POSITIONING =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0213);
+ public static final int TAG_REFERENCE_BLACK_WHITE =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0214);
+ public static final int TAG_COPYRIGHT =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x8298);
+ public static final int TAG_EXIF_IFD =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x8769);
+ public static final int TAG_GPS_IFD =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x8825);
+ // IFD 1
+ public static final int TAG_JPEG_INTERCHANGE_FORMAT =
+ defineTag(IfdId.TYPE_IFD_1, (short) 0x0201);
+ public static final int TAG_JPEG_INTERCHANGE_FORMAT_LENGTH =
+ defineTag(IfdId.TYPE_IFD_1, (short) 0x0202);
+ // IFD Exif Tags
+ public static final int TAG_EXPOSURE_TIME =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x829A);
+ public static final int TAG_F_NUMBER =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x829D);
+ public static final int TAG_EXPOSURE_PROGRAM =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8822);
+ public static final int TAG_SPECTRAL_SENSITIVITY =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8824);
+ public static final int TAG_ISO_SPEED_RATINGS =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8827);
+ public static final int TAG_OECF =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8828);
+ public static final int TAG_EXIF_VERSION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9000);
+ public static final int TAG_DATE_TIME_ORIGINAL =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9003);
+ public static final int TAG_DATE_TIME_DIGITIZED =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9004);
+ public static final int TAG_COMPONENTS_CONFIGURATION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9101);
+ public static final int TAG_COMPRESSED_BITS_PER_PIXEL =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9102);
+ public static final int TAG_SHUTTER_SPEED_VALUE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9201);
+ public static final int TAG_APERTURE_VALUE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9202);
+ public static final int TAG_BRIGHTNESS_VALUE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9203);
+ public static final int TAG_EXPOSURE_BIAS_VALUE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9204);
+ public static final int TAG_MAX_APERTURE_VALUE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9205);
+ public static final int TAG_SUBJECT_DISTANCE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9206);
+ public static final int TAG_METERING_MODE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9207);
+ public static final int TAG_LIGHT_SOURCE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9208);
+ public static final int TAG_FLASH =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9209);
+ public static final int TAG_FOCAL_LENGTH =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x920A);
+ public static final int TAG_SUBJECT_AREA =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9214);
+ public static final int TAG_MAKER_NOTE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x927C);
+ public static final int TAG_USER_COMMENT =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9286);
+ public static final int TAG_SUB_SEC_TIME =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9290);
+ public static final int TAG_SUB_SEC_TIME_ORIGINAL =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9291);
+ public static final int TAG_SUB_SEC_TIME_DIGITIZED =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9292);
+ public static final int TAG_FLASHPIX_VERSION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA000);
+ public static final int TAG_COLOR_SPACE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA001);
+ public static final int TAG_PIXEL_X_DIMENSION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA002);
+ public static final int TAG_PIXEL_Y_DIMENSION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA003);
+ public static final int TAG_RELATED_SOUND_FILE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA004);
+ public static final int TAG_INTEROPERABILITY_IFD =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA005);
+ public static final int TAG_FLASH_ENERGY =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20B);
+ public static final int TAG_SPATIAL_FREQUENCY_RESPONSE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20C);
+ public static final int TAG_FOCAL_PLANE_X_RESOLUTION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20E);
+ public static final int TAG_FOCAL_PLANE_Y_RESOLUTION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20F);
+ public static final int TAG_FOCAL_PLANE_RESOLUTION_UNIT =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA210);
+ public static final int TAG_SUBJECT_LOCATION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA214);
+ public static final int TAG_EXPOSURE_INDEX =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA215);
+ public static final int TAG_SENSING_METHOD =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA217);
+ public static final int TAG_FILE_SOURCE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA300);
+ public static final int TAG_SCENE_TYPE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA301);
+ public static final int TAG_CFA_PATTERN =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA302);
+ public static final int TAG_CUSTOM_RENDERED =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA401);
+ public static final int TAG_EXPOSURE_MODE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA402);
+ public static final int TAG_WHITE_BALANCE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA403);
+ public static final int TAG_DIGITAL_ZOOM_RATIO =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA404);
+ public static final int TAG_FOCAL_LENGTH_IN_35_MM_FILE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA405);
+ public static final int TAG_SCENE_CAPTURE_TYPE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA406);
+ public static final int TAG_GAIN_CONTROL =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA407);
+ public static final int TAG_CONTRAST =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA408);
+ public static final int TAG_SATURATION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA409);
+ public static final int TAG_SHARPNESS =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40A);
+ public static final int TAG_DEVICE_SETTING_DESCRIPTION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40B);
+ public static final int TAG_SUBJECT_DISTANCE_RANGE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40C);
+ public static final int TAG_IMAGE_UNIQUE_ID =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA420);
+ // IFD GPS tags
+ public static final int TAG_GPS_VERSION_ID =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 0);
+ public static final int TAG_GPS_LATITUDE_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 1);
+ public static final int TAG_GPS_LATITUDE =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 2);
+ public static final int TAG_GPS_LONGITUDE_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 3);
+ public static final int TAG_GPS_LONGITUDE =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 4);
+ public static final int TAG_GPS_ALTITUDE_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 5);
+ public static final int TAG_GPS_ALTITUDE =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 6);
+ public static final int TAG_GPS_TIME_STAMP =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 7);
+ public static final int TAG_GPS_SATTELLITES =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 8);
+ public static final int TAG_GPS_STATUS =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 9);
+ public static final int TAG_GPS_MEASURE_MODE =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 10);
+ public static final int TAG_GPS_DOP =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 11);
+ public static final int TAG_GPS_SPEED_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 12);
+ public static final int TAG_GPS_SPEED =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 13);
+ public static final int TAG_GPS_TRACK_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 14);
+ public static final int TAG_GPS_TRACK =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 15);
+ public static final int TAG_GPS_IMG_DIRECTION_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 16);
+ public static final int TAG_GPS_IMG_DIRECTION =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 17);
+ public static final int TAG_GPS_MAP_DATUM =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 18);
+ public static final int TAG_GPS_DEST_LATITUDE_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 19);
+ public static final int TAG_GPS_DEST_LATITUDE =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 20);
+ public static final int TAG_GPS_DEST_LONGITUDE_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 21);
+ public static final int TAG_GPS_DEST_LONGITUDE =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 22);
+ public static final int TAG_GPS_DEST_BEARING_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 23);
+ public static final int TAG_GPS_DEST_BEARING =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 24);
+ public static final int TAG_GPS_DEST_DISTANCE_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 25);
+ public static final int TAG_GPS_DEST_DISTANCE =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 26);
+ public static final int TAG_GPS_PROCESSING_METHOD =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 27);
+ public static final int TAG_GPS_AREA_INFORMATION =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 28);
+ public static final int TAG_GPS_DATE_STAMP =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 29);
+ public static final int TAG_GPS_DIFFERENTIAL =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 30);
+ // IFD Interoperability tags
+ public static final int TAG_INTEROPERABILITY_INDEX =
+ defineTag(IfdId.TYPE_IFD_INTEROPERABILITY, (short) 1);
+
+ /**
+ * Tags that contain offset markers. These are included in the banned
+ * defines.
+ */
+ private static HashSet<Short> sOffsetTags = new HashSet<Short>();
+ static {
+ sOffsetTags.add(getTrueTagKey(TAG_GPS_IFD));
+ sOffsetTags.add(getTrueTagKey(TAG_EXIF_IFD));
+ sOffsetTags.add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT));
+ sOffsetTags.add(getTrueTagKey(TAG_INTEROPERABILITY_IFD));
+ sOffsetTags.add(getTrueTagKey(TAG_STRIP_OFFSETS));
+ }
+
+ /**
+ * Tags with definitions that cannot be overridden (banned defines).
+ */
+ protected static HashSet<Short> sBannedDefines = new HashSet<Short>(sOffsetTags);
+ static {
+ sBannedDefines.add(getTrueTagKey(TAG_NULL));
+ sBannedDefines.add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH));
+ sBannedDefines.add(getTrueTagKey(TAG_STRIP_BYTE_COUNTS));
+ }
+
+ /**
+ * Returns the constant representing a tag with a given TID and default IFD.
+ */
+ public static int defineTag(int ifdId, short tagId) {
+ return (tagId & 0x0000ffff) | (ifdId << 16);
+ }
+
+ /**
+ * Returns the TID for a tag constant.
+ */
+ public static short getTrueTagKey(int tag) {
+ // Truncate
+ return (short) tag;
+ }
+
+ /**
+ * Returns the default IFD for a tag constant.
+ */
+ public static int getTrueIfd(int tag) {
+ return tag >>> 16;
+ }
+
+ /**
+ * Constants for {@link TAG_ORIENTATION}. They can be interpreted as
+ * follows:
+ * <ul>
+ * <li>TOP_LEFT is the normal orientation.</li>
+ * <li>TOP_RIGHT is a left-right mirror.</li>
+ * <li>BOTTOM_LEFT is a 180 degree rotation.</li>
+ * <li>BOTTOM_RIGHT is a top-bottom mirror.</li>
+ * <li>LEFT_TOP is mirrored about the top-left<->bottom-right axis.</li>
+ * <li>RIGHT_TOP is a 90 degree clockwise rotation.</li>
+ * <li>LEFT_BOTTOM is mirrored about the top-right<->bottom-left axis.</li>
+ * <li>RIGHT_BOTTOM is a 270 degree clockwise rotation.</li>
+ * </ul>
+ */
+ public static interface Orientation {
+ public static final short TOP_LEFT = 1;
+ public static final short TOP_RIGHT = 2;
+ public static final short BOTTOM_LEFT = 3;
+ public static final short BOTTOM_RIGHT = 4;
+ public static final short LEFT_TOP = 5;
+ public static final short RIGHT_TOP = 6;
+ public static final short LEFT_BOTTOM = 7;
+ public static final short RIGHT_BOTTOM = 8;
+ }
+
+ /**
+ * Constants for {@link TAG_Y_CB_CR_POSITIONING}
+ */
+ public static interface YCbCrPositioning {
+ public static final short CENTERED = 1;
+ public static final short CO_SITED = 2;
+ }
+
+ /**
+ * Constants for {@link TAG_COMPRESSION}
+ */
+ public static interface Compression {
+ public static final short UNCOMPRESSION = 1;
+ public static final short JPEG = 6;
+ }
+
+ /**
+ * Constants for {@link TAG_RESOLUTION_UNIT}
+ */
+ public static interface ResolutionUnit {
+ public static final short INCHES = 2;
+ public static final short CENTIMETERS = 3;
+ }
+
+ /**
+ * Constants for {@link TAG_PHOTOMETRIC_INTERPRETATION}
+ */
+ public static interface PhotometricInterpretation {
+ public static final short RGB = 2;
+ public static final short YCBCR = 6;
+ }
+
+ /**
+ * Constants for {@link TAG_PLANAR_CONFIGURATION}
+ */
+ public static interface PlanarConfiguration {
+ public static final short CHUNKY = 1;
+ public static final short PLANAR = 2;
+ }
+
+ /**
+ * Constants for {@link TAG_EXPOSURE_PROGRAM}
+ */
+ public static interface ExposureProgram {
+ public static final short NOT_DEFINED = 0;
+ public static final short MANUAL = 1;
+ public static final short NORMAL_PROGRAM = 2;
+ public static final short APERTURE_PRIORITY = 3;
+ public static final short SHUTTER_PRIORITY = 4;
+ public static final short CREATIVE_PROGRAM = 5;
+ public static final short ACTION_PROGRAM = 6;
+ public static final short PROTRAIT_MODE = 7;
+ public static final short LANDSCAPE_MODE = 8;
+ }
+
+ /**
+ * Constants for {@link TAG_METERING_MODE}
+ */
+ public static interface MeteringMode {
+ public static final short UNKNOWN = 0;
+ public static final short AVERAGE = 1;
+ public static final short CENTER_WEIGHTED_AVERAGE = 2;
+ public static final short SPOT = 3;
+ public static final short MULTISPOT = 4;
+ public static final short PATTERN = 5;
+ public static final short PARTAIL = 6;
+ public static final short OTHER = 255;
+ }
+
+ /**
+ * Constants for {@link TAG_FLASH} As the definition in Jeita EXIF 2.2
+ * standard, we can treat this constant as bitwise flag.
+ * <p>
+ * e.g.
+ * <p>
+ * short flash = FIRED | RETURN_STROBE_RETURN_LIGHT_DETECTED |
+ * MODE_AUTO_MODE
+ */
+ public static interface Flash {
+ // LSB
+ public static final short DID_NOT_FIRED = 0;
+ public static final short FIRED = 1;
+ // 1st~2nd bits
+ public static final short RETURN_NO_STROBE_RETURN_DETECTION_FUNCTION = 0 << 1;
+ public static final short RETURN_STROBE_RETURN_LIGHT_NOT_DETECTED = 2 << 1;
+ public static final short RETURN_STROBE_RETURN_LIGHT_DETECTED = 3 << 1;
+ // 3rd~4th bits
+ public static final short MODE_UNKNOWN = 0 << 3;
+ public static final short MODE_COMPULSORY_FLASH_FIRING = 1 << 3;
+ public static final short MODE_COMPULSORY_FLASH_SUPPRESSION = 2 << 3;
+ public static final short MODE_AUTO_MODE = 3 << 3;
+ // 5th bit
+ public static final short FUNCTION_PRESENT = 0 << 5;
+ public static final short FUNCTION_NO_FUNCTION = 1 << 5;
+ // 6th bit
+ public static final short RED_EYE_REDUCTION_NO_OR_UNKNOWN = 0 << 6;
+ public static final short RED_EYE_REDUCTION_SUPPORT = 1 << 6;
+ }
+
+ /**
+ * Constants for {@link TAG_COLOR_SPACE}
+ */
+ public static interface ColorSpace {
+ public static final short SRGB = 1;
+ public static final short UNCALIBRATED = (short) 0xFFFF;
+ }
+
+ /**
+ * Constants for {@link TAG_EXPOSURE_MODE}
+ */
+ public static interface ExposureMode {
+ public static final short AUTO_EXPOSURE = 0;
+ public static final short MANUAL_EXPOSURE = 1;
+ public static final short AUTO_BRACKET = 2;
+ }
+
+ /**
+ * Constants for {@link TAG_WHITE_BALANCE}
+ */
+ public static interface WhiteBalance {
+ public static final short AUTO = 0;
+ public static final short MANUAL = 1;
+ }
+
+ /**
+ * Constants for {@link TAG_SCENE_CAPTURE_TYPE}
+ */
+ public static interface SceneCapture {
+ public static final short STANDARD = 0;
+ public static final short LANDSCAPE = 1;
+ public static final short PROTRAIT = 2;
+ public static final short NIGHT_SCENE = 3;
+ }
+
+ /**
+ * Constants for {@link TAG_COMPONENTS_CONFIGURATION}
+ */
+ public static interface ComponentsConfiguration {
+ public static final short NOT_EXIST = 0;
+ public static final short Y = 1;
+ public static final short CB = 2;
+ public static final short CR = 3;
+ public static final short R = 4;
+ public static final short G = 5;
+ public static final short B = 6;
+ }
+
+ /**
+ * Constants for {@link TAG_LIGHT_SOURCE}
+ */
+ public static interface LightSource {
+ public static final short UNKNOWN = 0;
+ public static final short DAYLIGHT = 1;
+ public static final short FLUORESCENT = 2;
+ public static final short TUNGSTEN = 3;
+ public static final short FLASH = 4;
+ public static final short FINE_WEATHER = 9;
+ public static final short CLOUDY_WEATHER = 10;
+ public static final short SHADE = 11;
+ public static final short DAYLIGHT_FLUORESCENT = 12;
+ public static final short DAY_WHITE_FLUORESCENT = 13;
+ public static final short COOL_WHITE_FLUORESCENT = 14;
+ public static final short WHITE_FLUORESCENT = 15;
+ public static final short STANDARD_LIGHT_A = 17;
+ public static final short STANDARD_LIGHT_B = 18;
+ public static final short STANDARD_LIGHT_C = 19;
+ public static final short D55 = 20;
+ public static final short D65 = 21;
+ public static final short D75 = 22;
+ public static final short D50 = 23;
+ public static final short ISO_STUDIO_TUNGSTEN = 24;
+ public static final short OTHER = 255;
+ }
+
+ /**
+ * Constants for {@link TAG_SENSING_METHOD}
+ */
+ public static interface SensingMethod {
+ public static final short NOT_DEFINED = 1;
+ public static final short ONE_CHIP_COLOR = 2;
+ public static final short TWO_CHIP_COLOR = 3;
+ public static final short THREE_CHIP_COLOR = 4;
+ public static final short COLOR_SEQUENTIAL_AREA = 5;
+ public static final short TRILINEAR = 7;
+ public static final short COLOR_SEQUENTIAL_LINEAR = 8;
+ }
+
+ /**
+ * Constants for {@link TAG_FILE_SOURCE}
+ */
+ public static interface FileSource {
+ public static final short DSC = 3;
+ }
+
+ /**
+ * Constants for {@link TAG_SCENE_TYPE}
+ */
+ public static interface SceneType {
+ public static final short DIRECT_PHOTOGRAPHED = 1;
+ }
+
+ /**
+ * Constants for {@link TAG_GAIN_CONTROL}
+ */
+ public static interface GainControl {
+ public static final short NONE = 0;
+ public static final short LOW_UP = 1;
+ public static final short HIGH_UP = 2;
+ public static final short LOW_DOWN = 3;
+ public static final short HIGH_DOWN = 4;
+ }
+
+ /**
+ * Constants for {@link TAG_CONTRAST}
+ */
+ public static interface Contrast {
+ public static final short NORMAL = 0;
+ public static final short SOFT = 1;
+ public static final short HARD = 2;
+ }
+
+ /**
+ * Constants for {@link TAG_SATURATION}
+ */
+ public static interface Saturation {
+ public static final short NORMAL = 0;
+ public static final short LOW = 1;
+ public static final short HIGH = 2;
+ }
+
+ /**
+ * Constants for {@link TAG_SHARPNESS}
+ */
+ public static interface Sharpness {
+ public static final short NORMAL = 0;
+ public static final short SOFT = 1;
+ public static final short HARD = 2;
+ }
+
+ /**
+ * Constants for {@link TAG_SUBJECT_DISTANCE}
+ */
+ public static interface SubjectDistance {
+ public static final short UNKNOWN = 0;
+ public static final short MACRO = 1;
+ public static final short CLOSE_VIEW = 2;
+ public static final short DISTANT_VIEW = 3;
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_LATITUDE_REF},
+ * {@link TAG_GPS_DEST_LATITUDE_REF}
+ */
+ public static interface GpsLatitudeRef {
+ public static final String NORTH = "N";
+ public static final String SOUTH = "S";
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_LONGITUDE_REF},
+ * {@link TAG_GPS_DEST_LONGITUDE_REF}
+ */
+ public static interface GpsLongitudeRef {
+ public static final String EAST = "E";
+ public static final String WEST = "W";
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_ALTITUDE_REF}
+ */
+ public static interface GpsAltitudeRef {
+ public static final short SEA_LEVEL = 0;
+ public static final short SEA_LEVEL_NEGATIVE = 1;
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_STATUS}
+ */
+ public static interface GpsStatus {
+ public static final String IN_PROGRESS = "A";
+ public static final String INTEROPERABILITY = "V";
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_MEASURE_MODE}
+ */
+ public static interface GpsMeasureMode {
+ public static final String MODE_2_DIMENSIONAL = "2";
+ public static final String MODE_3_DIMENSIONAL = "3";
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_SPEED_REF},
+ * {@link TAG_GPS_DEST_DISTANCE_REF}
+ */
+ public static interface GpsSpeedRef {
+ public static final String KILOMETERS = "K";
+ public static final String MILES = "M";
+ public static final String KNOTS = "N";
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_TRACK_REF},
+ * {@link TAG_GPS_IMG_DIRECTION_REF}, {@link TAG_GPS_DEST_BEARING_REF}
+ */
+ public static interface GpsTrackRef {
+ public static final String TRUE_DIRECTION = "T";
+ public static final String MAGNETIC_DIRECTION = "M";
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_DIFFERENTIAL}
+ */
+ public static interface GpsDifferential {
+ public static final short WITHOUT_DIFFERENTIAL_CORRECTION = 0;
+ public static final short DIFFERENTIAL_CORRECTION_APPLIED = 1;
+ }
+
+ private static final String NULL_ARGUMENT_STRING = "Argument is null";
+ private ExifData mData = new ExifData(DEFAULT_BYTE_ORDER);
+ public static final ByteOrder DEFAULT_BYTE_ORDER = ByteOrder.BIG_ENDIAN;
+
+ public ExifInterface() {
+ mGPSDateStampFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
+
+ /**
+ * Reads the exif tags from a byte array, clearing this ExifInterface
+ * object's existing exif tags.
+ *
+ * @param jpeg a byte array containing a jpeg compressed image.
+ * @throws IOException
+ */
+ public void readExif(byte[] jpeg) throws IOException {
+ readExif(new ByteArrayInputStream(jpeg));
+ }
+
+ /**
+ * Reads the exif tags from an InputStream, clearing this ExifInterface
+ * object's existing exif tags.
+ *
+ * @param inStream an InputStream containing a jpeg compressed image.
+ * @throws IOException
+ */
+ public void readExif(InputStream inStream) throws IOException {
+ if (inStream == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ ExifData d = null;
+ try {
+ d = new ExifReader(this).read(inStream);
+ } catch (ExifInvalidFormatException e) {
+ throw new IOException("Invalid exif format : " + e);
+ }
+ mData = d;
+ }
+
+ /**
+ * Reads the exif tags from a file, clearing this ExifInterface object's
+ * existing exif tags.
+ *
+ * @param inFileName a string representing the filepath to jpeg file.
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public void readExif(String inFileName) throws FileNotFoundException, IOException {
+ if (inFileName == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ InputStream is = null;
+ try {
+ is = (InputStream) new BufferedInputStream(new FileInputStream(inFileName));
+ readExif(is);
+ } catch (IOException e) {
+ closeSilently(is);
+ throw e;
+ }
+ is.close();
+ }
+
+ /**
+ * Sets the exif tags, clearing this ExifInterface object's existing exif
+ * tags.
+ *
+ * @param tags a collection of exif tags to set.
+ */
+ public void setExif(Collection<ExifTag> tags) {
+ clearExif();
+ setTags(tags);
+ }
+
+ /**
+ * Clears this ExifInterface object's existing exif tags.
+ */
+ public void clearExif() {
+ mData = new ExifData(DEFAULT_BYTE_ORDER);
+ }
+
+ /**
+ * Writes the tags from this ExifInterface object into a jpeg image,
+ * removing prior exif tags.
+ *
+ * @param jpeg a byte array containing a jpeg compressed image.
+ * @param exifOutStream an OutputStream to which the jpeg image with added
+ * exif tags will be written.
+ * @throws IOException
+ */
+ public void writeExif(byte[] jpeg, OutputStream exifOutStream) throws IOException {
+ if (jpeg == null || exifOutStream == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ OutputStream s = getExifWriterStream(exifOutStream);
+ s.write(jpeg, 0, jpeg.length);
+ s.flush();
+ }
+
+ /**
+ * Writes the tags from this ExifInterface object into a jpeg compressed
+ * bitmap, removing prior exif tags.
+ *
+ * @param bmap a bitmap to compress and write exif into.
+ * @param exifOutStream the OutputStream to which the jpeg image with added
+ * exif tags will be written.
+ * @throws IOException
+ */
+ public void writeExif(Bitmap bmap, OutputStream exifOutStream) throws IOException {
+ if (bmap == null || exifOutStream == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ OutputStream s = getExifWriterStream(exifOutStream);
+ bmap.compress(Bitmap.CompressFormat.JPEG, 90, s);
+ s.flush();
+ }
+
+ /**
+ * Writes the tags from this ExifInterface object into a jpeg stream,
+ * removing prior exif tags.
+ *
+ * @param jpegStream an InputStream containing a jpeg compressed image.
+ * @param exifOutStream an OutputStream to which the jpeg image with added
+ * exif tags will be written.
+ * @throws IOException
+ */
+ public void writeExif(InputStream jpegStream, OutputStream exifOutStream) throws IOException {
+ if (jpegStream == null || exifOutStream == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ OutputStream s = getExifWriterStream(exifOutStream);
+ doExifStreamIO(jpegStream, s);
+ s.flush();
+ }
+
+ /**
+ * Writes the tags from this ExifInterface object into a jpeg image,
+ * removing prior exif tags.
+ *
+ * @param jpeg a byte array containing a jpeg compressed image.
+ * @param exifOutFileName a String containing the filepath to which the jpeg
+ * image with added exif tags will be written.
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public void writeExif(byte[] jpeg, String exifOutFileName) throws FileNotFoundException,
+ IOException {
+ if (jpeg == null || exifOutFileName == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ OutputStream s = null;
+ try {
+ s = getExifWriterStream(exifOutFileName);
+ s.write(jpeg, 0, jpeg.length);
+ s.flush();
+ } catch (IOException e) {
+ closeSilently(s);
+ throw e;
+ }
+ s.close();
+ }
+
+ /**
+ * Writes the tags from this ExifInterface object into a jpeg compressed
+ * bitmap, removing prior exif tags.
+ *
+ * @param bmap a bitmap to compress and write exif into.
+ * @param exifOutFileName a String containing the filepath to which the jpeg
+ * image with added exif tags will be written.
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public void writeExif(Bitmap bmap, String exifOutFileName) throws FileNotFoundException,
+ IOException {
+ if (bmap == null || exifOutFileName == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ OutputStream s = null;
+ try {
+ s = getExifWriterStream(exifOutFileName);
+ bmap.compress(Bitmap.CompressFormat.JPEG, 90, s);
+ s.flush();
+ } catch (IOException e) {
+ closeSilently(s);
+ throw e;
+ }
+ s.close();
+ }
+
+ /**
+ * Writes the tags from this ExifInterface object into a jpeg stream,
+ * removing prior exif tags.
+ *
+ * @param jpegStream an InputStream containing a jpeg compressed image.
+ * @param exifOutFileName a String containing the filepath to which the jpeg
+ * image with added exif tags will be written.
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public void writeExif(InputStream jpegStream, String exifOutFileName)
+ throws FileNotFoundException, IOException {
+ if (jpegStream == null || exifOutFileName == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ OutputStream s = null;
+ try {
+ s = getExifWriterStream(exifOutFileName);
+ doExifStreamIO(jpegStream, s);
+ s.flush();
+ } catch (IOException e) {
+ closeSilently(s);
+ throw e;
+ }
+ s.close();
+ }
+
+ /**
+ * Writes the tags from this ExifInterface object into a jpeg file, removing
+ * prior exif tags.
+ *
+ * @param jpegFileName a String containing the filepath for a jpeg file.
+ * @param exifOutFileName a String containing the filepath to which the jpeg
+ * image with added exif tags will be written.
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public void writeExif(String jpegFileName, String exifOutFileName)
+ throws FileNotFoundException, IOException {
+ if (jpegFileName == null || exifOutFileName == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ InputStream is = null;
+ try {
+ is = new FileInputStream(jpegFileName);
+ writeExif(is, exifOutFileName);
+ } catch (IOException e) {
+ closeSilently(is);
+ throw e;
+ }
+ is.close();
+ }
+
+ /**
+ * Wraps an OutputStream object with an ExifOutputStream. Exif tags in this
+ * ExifInterface object will be added to a jpeg image written to this
+ * stream, removing prior exif tags. Other methods of this ExifInterface
+ * object should not be called until the returned OutputStream has been
+ * closed.
+ *
+ * @param outStream an OutputStream to wrap.
+ * @return an OutputStream that wraps the outStream parameter, and adds exif
+ * metadata. A jpeg image should be written to this stream.
+ */
+ public OutputStream getExifWriterStream(OutputStream outStream) {
+ if (outStream == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ ExifOutputStream eos = new ExifOutputStream(outStream, this);
+ eos.setExifData(mData);
+ return eos;
+ }
+
+ /**
+ * Returns an OutputStream object that writes to a file. Exif tags in this
+ * ExifInterface object will be added to a jpeg image written to this
+ * stream, removing prior exif tags. Other methods of this ExifInterface
+ * object should not be called until the returned OutputStream has been
+ * closed.
+ *
+ * @param exifOutFileName an String containing a filepath for a jpeg file.
+ * @return an OutputStream that writes to the exifOutFileName file, and adds
+ * exif metadata. A jpeg image should be written to this stream.
+ * @throws FileNotFoundException
+ */
+ public OutputStream getExifWriterStream(String exifOutFileName) throws FileNotFoundException {
+ if (exifOutFileName == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ OutputStream out = null;
+ try {
+ out = (OutputStream) new FileOutputStream(exifOutFileName);
+ } catch (FileNotFoundException e) {
+ closeSilently(out);
+ throw e;
+ }
+ return getExifWriterStream(out);
+ }
+
+ /**
+ * Attempts to do an in-place rewrite the exif metadata in a file for the
+ * given tags. If tags do not exist or do not have the same size as the
+ * existing exif tags, this method will fail.
+ *
+ * @param filename a String containing a filepath for a jpeg file with exif
+ * tags to rewrite.
+ * @param tags tags that will be written into the jpeg file over existing
+ * tags if possible.
+ * @return true if success, false if could not overwrite. If false, no
+ * changes are made to the file.
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public boolean rewriteExif(String filename, Collection<ExifTag> tags)
+ throws FileNotFoundException, IOException {
+ RandomAccessFile file = null;
+ InputStream is = null;
+ boolean ret;
+ try {
+ File temp = new File(filename);
+ is = new BufferedInputStream(new FileInputStream(temp));
+
+ // Parse beginning of APP1 in exif to find size of exif header.
+ ExifParser parser = null;
+ try {
+ parser = ExifParser.parse(is, this);
+ } catch (ExifInvalidFormatException e) {
+ throw new IOException("Invalid exif format : ", e);
+ }
+ long exifSize = parser.getOffsetToExifEndFromSOF();
+
+ // Free up resources
+ is.close();
+ is = null;
+
+ // Open file for memory mapping.
+ file = new RandomAccessFile(temp, "rw");
+ long fileLength = file.length();
+ if (fileLength < exifSize) {
+ throw new IOException("Filesize changed during operation");
+ }
+
+ // Map only exif header into memory.
+ ByteBuffer buf = file.getChannel().map(MapMode.READ_WRITE, 0, exifSize);
+
+ // Attempt to overwrite tag values without changing lengths (avoids
+ // file copy).
+ ret = rewriteExif(buf, tags);
+ } catch (IOException e) {
+ closeSilently(file);
+ throw e;
+ } finally {
+ closeSilently(is);
+ }
+ file.close();
+ return ret;
+ }
+
+ /**
+ * Attempts to do an in-place rewrite the exif metadata in a ByteBuffer for
+ * the given tags. If tags do not exist or do not have the same size as the
+ * existing exif tags, this method will fail.
+ *
+ * @param buf a ByteBuffer containing a jpeg file with existing exif tags to
+ * rewrite.
+ * @param tags tags that will be written into the jpeg ByteBuffer over
+ * existing tags if possible.
+ * @return true if success, false if could not overwrite. If false, no
+ * changes are made to the ByteBuffer.
+ * @throws IOException
+ */
+ public boolean rewriteExif(ByteBuffer buf, Collection<ExifTag> tags) throws IOException {
+ ExifModifier mod = null;
+ try {
+ mod = new ExifModifier(buf, this);
+ for (ExifTag t : tags) {
+ mod.modifyTag(t);
+ }
+ return mod.commit();
+ } catch (ExifInvalidFormatException e) {
+ throw new IOException("Invalid exif format : " + e);
+ }
+ }
+
+ /**
+ * Attempts to do an in-place rewrite of the exif metadata. If this fails,
+ * fall back to overwriting file. This preserves tags that are not being
+ * rewritten.
+ *
+ * @param filename a String containing a filepath for a jpeg file.
+ * @param tags tags that will be written into the jpeg file over existing
+ * tags if possible.
+ * @throws FileNotFoundException
+ * @throws IOException
+ * @see #rewriteExif
+ */
+ public void forceRewriteExif(String filename, Collection<ExifTag> tags)
+ throws FileNotFoundException,
+ IOException {
+ // Attempt in-place write
+ if (!rewriteExif(filename, tags)) {
+ // Fall back to doing a copy
+ ExifData tempData = mData;
+ mData = new ExifData(DEFAULT_BYTE_ORDER);
+ FileInputStream is = null;
+ ByteArrayOutputStream bytes = null;
+ try {
+ is = new FileInputStream(filename);
+ bytes = new ByteArrayOutputStream();
+ doExifStreamIO(is, bytes);
+ byte[] imageBytes = bytes.toByteArray();
+ readExif(imageBytes);
+ setTags(tags);
+ writeExif(imageBytes, filename);
+ } catch (IOException e) {
+ closeSilently(is);
+ throw e;
+ } finally {
+ is.close();
+ // Prevent clobbering of mData
+ mData = tempData;
+ }
+ }
+ }
+
+ /**
+ * Attempts to do an in-place rewrite of the exif metadata using the tags in
+ * this ExifInterface object. If this fails, fall back to overwriting file.
+ * This preserves tags that are not being rewritten.
+ *
+ * @param filename a String containing a filepath for a jpeg file.
+ * @throws FileNotFoundException
+ * @throws IOException
+ * @see #rewriteExif
+ */
+ public void forceRewriteExif(String filename) throws FileNotFoundException, IOException {
+ forceRewriteExif(filename, getAllTags());
+ }
+
+ /**
+ * Get the exif tags in this ExifInterface object or null if none exist.
+ *
+ * @return a List of {@link ExifTag}s.
+ */
+ public List<ExifTag> getAllTags() {
+ return mData.getAllTags();
+ }
+
+ /**
+ * Returns a list of ExifTags that share a TID (which can be obtained by
+ * calling {@link #getTrueTagKey} on a defined tag constant) or null if none
+ * exist.
+ *
+ * @param tagId a TID as defined in the exif standard (or with
+ * {@link #defineTag}).
+ * @return a List of {@link ExifTag}s.
+ */
+ public List<ExifTag> getTagsForTagId(short tagId) {
+ return mData.getAllTagsForTagId(tagId);
+ }
+
+ /**
+ * Returns a list of ExifTags that share an IFD (which can be obtained by
+ * calling {@link #getTrueIFD} on a defined tag constant) or null if none
+ * exist.
+ *
+ * @param ifdId an IFD as defined in the exif standard (or with
+ * {@link #defineTag}).
+ * @return a List of {@link ExifTag}s.
+ */
+ public List<ExifTag> getTagsForIfdId(int ifdId) {
+ return mData.getAllTagsForIfd(ifdId);
+ }
+
+ /**
+ * Gets an ExifTag for an IFD other than the tag's default.
+ *
+ * @see #getTag
+ */
+ public ExifTag getTag(int tagId, int ifdId) {
+ if (!ExifTag.isValidIfd(ifdId)) {
+ return null;
+ }
+ return mData.getTag(getTrueTagKey(tagId), ifdId);
+ }
+
+ /**
+ * Returns the ExifTag in that tag's default IFD for a defined tag constant
+ * or null if none exists.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @return an {@link ExifTag} or null if none exists.
+ */
+ public ExifTag getTag(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTag(tagId, ifdId);
+ }
+
+ /**
+ * Gets a tag value for an IFD other than the tag's default.
+ *
+ * @see #getTagValue
+ */
+ public Object getTagValue(int tagId, int ifdId) {
+ ExifTag t = getTag(tagId, ifdId);
+ return (t == null) ? null : t.getValue();
+ }
+
+ /**
+ * Returns the value of the ExifTag in that tag's default IFD for a defined
+ * tag constant or null if none exists or the value could not be cast into
+ * the return type.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @return the value of the ExifTag or null if none exists.
+ */
+ public Object getTagValue(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagValue(tagId, ifdId);
+ }
+
+ /*
+ * Getter methods that are similar to getTagValue. Null is returned if the
+ * tag value cannot be cast into the return type.
+ */
+
+ /**
+ * @see #getTagValue
+ */
+ public String getTagStringValue(int tagId, int ifdId) {
+ ExifTag t = getTag(tagId, ifdId);
+ if (t == null) {
+ return null;
+ }
+ return t.getValueAsString();
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public String getTagStringValue(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagStringValue(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Long getTagLongValue(int tagId, int ifdId) {
+ long[] l = getTagLongValues(tagId, ifdId);
+ if (l == null || l.length <= 0) {
+ return null;
+ }
+ return new Long(l[0]);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Long getTagLongValue(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagLongValue(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Integer getTagIntValue(int tagId, int ifdId) {
+ int[] l = getTagIntValues(tagId, ifdId);
+ if (l == null || l.length <= 0) {
+ return null;
+ }
+ return new Integer(l[0]);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Integer getTagIntValue(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagIntValue(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Byte getTagByteValue(int tagId, int ifdId) {
+ byte[] l = getTagByteValues(tagId, ifdId);
+ if (l == null || l.length <= 0) {
+ return null;
+ }
+ return new Byte(l[0]);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Byte getTagByteValue(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagByteValue(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Rational getTagRationalValue(int tagId, int ifdId) {
+ Rational[] l = getTagRationalValues(tagId, ifdId);
+ if (l == null || l.length == 0) {
+ return null;
+ }
+ return new Rational(l[0]);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Rational getTagRationalValue(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagRationalValue(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public long[] getTagLongValues(int tagId, int ifdId) {
+ ExifTag t = getTag(tagId, ifdId);
+ if (t == null) {
+ return null;
+ }
+ return t.getValueAsLongs();
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public long[] getTagLongValues(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagLongValues(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public int[] getTagIntValues(int tagId, int ifdId) {
+ ExifTag t = getTag(tagId, ifdId);
+ if (t == null) {
+ return null;
+ }
+ return t.getValueAsInts();
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public int[] getTagIntValues(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagIntValues(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public byte[] getTagByteValues(int tagId, int ifdId) {
+ ExifTag t = getTag(tagId, ifdId);
+ if (t == null) {
+ return null;
+ }
+ return t.getValueAsBytes();
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public byte[] getTagByteValues(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagByteValues(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Rational[] getTagRationalValues(int tagId, int ifdId) {
+ ExifTag t = getTag(tagId, ifdId);
+ if (t == null) {
+ return null;
+ }
+ return t.getValueAsRationals();
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Rational[] getTagRationalValues(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagRationalValues(tagId, ifdId);
+ }
+
+ /**
+ * Checks whether a tag has a defined number of elements.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @return true if the tag has a defined number of elements.
+ */
+ public boolean isTagCountDefined(int tagId) {
+ int info = getTagInfo().get(tagId);
+ // No value in info can be zero, as all tags have a non-zero type
+ if (info == 0) {
+ return false;
+ }
+ return getComponentCountFromInfo(info) != ExifTag.SIZE_UNDEFINED;
+ }
+
+ /**
+ * Gets the defined number of elements for a tag.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @return the number of elements or {@link ExifTag#SIZE_UNDEFINED} if the
+ * tag or the number of elements is not defined.
+ */
+ public int getDefinedTagCount(int tagId) {
+ int info = getTagInfo().get(tagId);
+ if (info == 0) {
+ return ExifTag.SIZE_UNDEFINED;
+ }
+ return getComponentCountFromInfo(info);
+ }
+
+ /**
+ * Gets the number of elements for an ExifTag in a given IFD.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @param ifdId the IFD containing the ExifTag to check.
+ * @return the number of elements in the ExifTag, if the tag's size is
+ * undefined this will return the actual number of elements that is
+ * in the ExifTag's value.
+ */
+ public int getActualTagCount(int tagId, int ifdId) {
+ ExifTag t = getTag(tagId, ifdId);
+ if (t == null) {
+ return 0;
+ }
+ return t.getComponentCount();
+ }
+
+ /**
+ * Gets the default IFD for a tag.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @return the default IFD for a tag definition or {@link #IFD_NULL} if no
+ * definition exists.
+ */
+ public int getDefinedTagDefaultIfd(int tagId) {
+ int info = getTagInfo().get(tagId);
+ if (info == DEFINITION_NULL) {
+ return IFD_NULL;
+ }
+ return getTrueIfd(tagId);
+ }
+
+ /**
+ * Gets the defined type for a tag.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @return the type.
+ * @see ExifTag#getDataType()
+ */
+ public short getDefinedTagType(int tagId) {
+ int info = getTagInfo().get(tagId);
+ if (info == 0) {
+ return -1;
+ }
+ return getTypeFromInfo(info);
+ }
+
+ /**
+ * Returns true if tag TID is one of the following: {@link TAG_EXIF_IFD},
+ * {@link TAG_GPS_IFD}, {@link TAG_JPEG_INTERCHANGE_FORMAT},
+ * {@link TAG_STRIP_OFFSETS}, {@link TAG_INTEROPERABILITY_IFD}
+ * <p>
+ * Note: defining tags with these TID's is disallowed.
+ *
+ * @param tag a tag's TID (can be obtained from a defined tag constant with
+ * {@link #getTrueTagKey}).
+ * @return true if the TID is that of an offset tag.
+ */
+ protected static boolean isOffsetTag(short tag) {
+ return sOffsetTags.contains(tag);
+ }
+
+ /**
+ * Creates a tag for a defined tag constant in a given IFD if that IFD is
+ * allowed for the tag. This method will fail anytime the appropriate
+ * {@link ExifTag#setValue} for this tag's datatype would fail.
+ *
+ * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @param ifdId the IFD that the tag should be in.
+ * @param val the value of the tag to set.
+ * @return an ExifTag object or null if one could not be constructed.
+ * @see #buildTag
+ */
+ public ExifTag buildTag(int tagId, int ifdId, Object val) {
+ int info = getTagInfo().get(tagId);
+ if (info == 0 || val == null) {
+ return null;
+ }
+ short type = getTypeFromInfo(info);
+ int definedCount = getComponentCountFromInfo(info);
+ boolean hasDefinedCount = (definedCount != ExifTag.SIZE_UNDEFINED);
+ if (!ExifInterface.isIfdAllowed(info, ifdId)) {
+ return null;
+ }
+ ExifTag t = new ExifTag(getTrueTagKey(tagId), type, definedCount, ifdId, hasDefinedCount);
+ if (!t.setValue(val)) {
+ return null;
+ }
+ return t;
+ }
+
+ /**
+ * Creates a tag for a defined tag constant in the tag's default IFD.
+ *
+ * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @param val the tag's value.
+ * @return an ExifTag object.
+ */
+ public ExifTag buildTag(int tagId, Object val) {
+ int ifdId = getTrueIfd(tagId);
+ return buildTag(tagId, ifdId, val);
+ }
+
+ protected ExifTag buildUninitializedTag(int tagId) {
+ int info = getTagInfo().get(tagId);
+ if (info == 0) {
+ return null;
+ }
+ short type = getTypeFromInfo(info);
+ int definedCount = getComponentCountFromInfo(info);
+ boolean hasDefinedCount = (definedCount != ExifTag.SIZE_UNDEFINED);
+ int ifdId = getTrueIfd(tagId);
+ ExifTag t = new ExifTag(getTrueTagKey(tagId), type, definedCount, ifdId, hasDefinedCount);
+ return t;
+ }
+
+ /**
+ * Sets the value of an ExifTag if it exists in the given IFD. The value
+ * must be the correct type and length for that ExifTag.
+ *
+ * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @param ifdId the IFD that the ExifTag is in.
+ * @param val the value to set.
+ * @return true if success, false if the ExifTag doesn't exist or the value
+ * is the wrong type/length.
+ * @see #setTagValue
+ */
+ public boolean setTagValue(int tagId, int ifdId, Object val) {
+ ExifTag t = getTag(tagId, ifdId);
+ if (t == null) {
+ return false;
+ }
+ return t.setValue(val);
+ }
+
+ /**
+ * Sets the value of an ExifTag if it exists it's default IFD. The value
+ * must be the correct type and length for that ExifTag.
+ *
+ * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @param val the value to set.
+ * @return true if success, false if the ExifTag doesn't exist or the value
+ * is the wrong type/length.
+ */
+ public boolean setTagValue(int tagId, Object val) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return setTagValue(tagId, ifdId, val);
+ }
+
+ /**
+ * Puts an ExifTag into this ExifInterface object's tags, removing a
+ * previous ExifTag with the same TID and IFD. The IFD it is put into will
+ * be the one the tag was created with in {@link #buildTag}.
+ *
+ * @param tag an ExifTag to put into this ExifInterface's tags.
+ * @return the previous ExifTag with the same TID and IFD or null if none
+ * exists.
+ */
+ public ExifTag setTag(ExifTag tag) {
+ return mData.addTag(tag);
+ }
+
+ /**
+ * Puts a collection of ExifTags into this ExifInterface objects's tags. Any
+ * previous ExifTags with the same TID and IFDs will be removed.
+ *
+ * @param tags a Collection of ExifTags.
+ * @see #setTag
+ */
+ public void setTags(Collection<ExifTag> tags) {
+ for (ExifTag t : tags) {
+ setTag(t);
+ }
+ }
+
+ /**
+ * Removes the ExifTag for a tag constant from the given IFD.
+ *
+ * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @param ifdId the IFD of the ExifTag to remove.
+ */
+ public void deleteTag(int tagId, int ifdId) {
+ mData.removeTag(getTrueTagKey(tagId), ifdId);
+ }
+
+ /**
+ * Removes the ExifTag for a tag constant from that tag's default IFD.
+ *
+ * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ */
+ public void deleteTag(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ deleteTag(tagId, ifdId);
+ }
+
+ /**
+ * Creates a new tag definition in this ExifInterface object for a given TID
+ * and default IFD. Creating a definition with the same TID and default IFD
+ * as a previous definition will override it.
+ *
+ * @param tagId the TID for the tag.
+ * @param defaultIfd the default IFD for the tag.
+ * @param tagType the type of the tag (see {@link ExifTag#getDataType()}).
+ * @param defaultComponentCount the number of elements of this tag's type in
+ * the tags value.
+ * @param allowedIfds the IFD's this tag is allowed to be put in.
+ * @return the defined tag constant (e.g. {@link #TAG_IMAGE_WIDTH}) or
+ * {@link #TAG_NULL} if the definition could not be made.
+ */
+ public int setTagDefinition(short tagId, int defaultIfd, short tagType,
+ short defaultComponentCount, int[] allowedIfds) {
+ if (sBannedDefines.contains(tagId)) {
+ return TAG_NULL;
+ }
+ if (ExifTag.isValidType(tagType) && ExifTag.isValidIfd(defaultIfd)) {
+ int tagDef = defineTag(defaultIfd, tagId);
+ if (tagDef == TAG_NULL) {
+ return TAG_NULL;
+ }
+ int[] otherDefs = getTagDefinitionsForTagId(tagId);
+ SparseIntArray infos = getTagInfo();
+ // Make sure defaultIfd is in allowedIfds
+ boolean defaultCheck = false;
+ for (int i : allowedIfds) {
+ if (defaultIfd == i) {
+ defaultCheck = true;
+ }
+ if (!ExifTag.isValidIfd(i)) {
+ return TAG_NULL;
+ }
+ }
+ if (!defaultCheck) {
+ return TAG_NULL;
+ }
+
+ int ifdFlags = getFlagsFromAllowedIfds(allowedIfds);
+ // Make sure no identical tags can exist in allowedIfds
+ if (otherDefs != null) {
+ for (int def : otherDefs) {
+ int tagInfo = infos.get(def);
+ int allowedFlags = getAllowedIfdFlagsFromInfo(tagInfo);
+ if ((ifdFlags & allowedFlags) != 0) {
+ return TAG_NULL;
+ }
+ }
+ }
+ getTagInfo().put(tagDef, ifdFlags << 24 | (tagType << 16) | defaultComponentCount);
+ return tagDef;
+ }
+ return TAG_NULL;
+ }
+
+ protected int getTagDefinition(short tagId, int defaultIfd) {
+ return getTagInfo().get(defineTag(defaultIfd, tagId));
+ }
+
+ protected int[] getTagDefinitionsForTagId(short tagId) {
+ int[] ifds = IfdData.getIfds();
+ int[] defs = new int[ifds.length];
+ int counter = 0;
+ SparseIntArray infos = getTagInfo();
+ for (int i : ifds) {
+ int def = defineTag(i, tagId);
+ if (infos.get(def) != DEFINITION_NULL) {
+ defs[counter++] = def;
+ }
+ }
+ if (counter == 0) {
+ return null;
+ }
+
+ return Arrays.copyOfRange(defs, 0, counter);
+ }
+
+ protected int getTagDefinitionForTag(ExifTag tag) {
+ short type = tag.getDataType();
+ int count = tag.getComponentCount();
+ int ifd = tag.getIfd();
+ return getTagDefinitionForTag(tag.getTagId(), type, count, ifd);
+ }
+
+ protected int getTagDefinitionForTag(short tagId, short type, int count, int ifd) {
+ int[] defs = getTagDefinitionsForTagId(tagId);
+ if (defs == null) {
+ return TAG_NULL;
+ }
+ SparseIntArray infos = getTagInfo();
+ int ret = TAG_NULL;
+ for (int i : defs) {
+ int info = infos.get(i);
+ short def_type = getTypeFromInfo(info);
+ int def_count = getComponentCountFromInfo(info);
+ int[] def_ifds = getAllowedIfdsFromInfo(info);
+ boolean valid_ifd = false;
+ for (int j : def_ifds) {
+ if (j == ifd) {
+ valid_ifd = true;
+ break;
+ }
+ }
+ if (valid_ifd && type == def_type
+ && (count == def_count || def_count == ExifTag.SIZE_UNDEFINED)) {
+ ret = i;
+ break;
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Removes a tag definition for given defined tag constant.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ */
+ public void removeTagDefinition(int tagId) {
+ getTagInfo().delete(tagId);
+ }
+
+ /**
+ * Resets tag definitions to the default ones.
+ */
+ public void resetTagDefinitions() {
+ mTagInfo = null;
+ }
+
+ /**
+ * Returns the thumbnail from IFD1 as a bitmap, or null if none exists.
+ *
+ * @return the thumbnail as a bitmap.
+ */
+ public Bitmap getThumbnailBitmap() {
+ if (mData.hasCompressedThumbnail()) {
+ byte[] thumb = mData.getCompressedThumbnail();
+ return BitmapFactory.decodeByteArray(thumb, 0, thumb.length);
+ } else if (mData.hasUncompressedStrip()) {
+ // TODO: implement uncompressed
+ }
+ return null;
+ }
+
+ /**
+ * Returns the thumbnail from IFD1 as a byte array, or null if none exists.
+ * The bytes may either be an uncompressed strip as specified in the exif
+ * standard or a jpeg compressed image.
+ *
+ * @return the thumbnail as a byte array.
+ */
+ public byte[] getThumbnailBytes() {
+ if (mData.hasCompressedThumbnail()) {
+ return mData.getCompressedThumbnail();
+ } else if (mData.hasUncompressedStrip()) {
+ // TODO: implement this
+ }
+ return null;
+ }
+
+ /**
+ * Returns the thumbnail if it is jpeg compressed, or null if none exists.
+ *
+ * @return the thumbnail as a byte array.
+ */
+ public byte[] getThumbnail() {
+ return mData.getCompressedThumbnail();
+ }
+
+ /**
+ * Check if thumbnail is compressed.
+ *
+ * @return true if the thumbnail is compressed.
+ */
+ public boolean isThumbnailCompressed() {
+ return mData.hasCompressedThumbnail();
+ }
+
+ /**
+ * Check if thumbnail exists.
+ *
+ * @return true if a compressed thumbnail exists.
+ */
+ public boolean hasThumbnail() {
+ // TODO: add back in uncompressed strip
+ return mData.hasCompressedThumbnail();
+ }
+
+ // TODO: uncompressed thumbnail setters
+
+ /**
+ * Sets the thumbnail to be a jpeg compressed image. Clears any prior
+ * thumbnail.
+ *
+ * @param thumb a byte array containing a jpeg compressed image.
+ * @return true if the thumbnail was set.
+ */
+ public boolean setCompressedThumbnail(byte[] thumb) {
+ mData.clearThumbnailAndStrips();
+ mData.setCompressedThumbnail(thumb);
+ return true;
+ }
+
+ /**
+ * Sets the thumbnail to be a jpeg compressed bitmap. Clears any prior
+ * thumbnail.
+ *
+ * @param thumb a bitmap to compress to a jpeg thumbnail.
+ * @return true if the thumbnail was set.
+ */
+ public boolean setCompressedThumbnail(Bitmap thumb) {
+ ByteArrayOutputStream thumbnail = new ByteArrayOutputStream();
+ if (!thumb.compress(Bitmap.CompressFormat.JPEG, 90, thumbnail)) {
+ return false;
+ }
+ return setCompressedThumbnail(thumbnail.toByteArray());
+ }
+
+ /**
+ * Clears the compressed thumbnail if it exists.
+ */
+ public void removeCompressedThumbnail() {
+ mData.setCompressedThumbnail(null);
+ }
+
+ // Convenience methods:
+
+ /**
+ * Decodes the user comment tag into string as specified in the EXIF
+ * standard. Returns null if decoding failed.
+ */
+ public String getUserComment() {
+ return mData.getUserComment();
+ }
+
+ /**
+ * Returns the Orientation ExifTag value for a given number of degrees.
+ *
+ * @param degrees the amount an image is rotated in degrees.
+ */
+ public static short getOrientationValueForRotation(int degrees) {
+ degrees %= 360;
+ if (degrees < 0) {
+ degrees += 360;
+ }
+ if (degrees < 90) {
+ return Orientation.TOP_LEFT; // 0 degrees
+ } else if (degrees < 180) {
+ return Orientation.RIGHT_TOP; // 90 degrees cw
+ } else if (degrees < 270) {
+ return Orientation.BOTTOM_LEFT; // 180 degrees
+ } else {
+ return Orientation.RIGHT_BOTTOM; // 270 degrees cw
+ }
+ }
+
+ /**
+ * Returns the rotation degrees corresponding to an ExifTag Orientation
+ * value.
+ *
+ * @param orientation the ExifTag Orientation value.
+ */
+ public static int getRotationForOrientationValue(short orientation) {
+ switch (orientation) {
+ case Orientation.TOP_LEFT:
+ return 0;
+ case Orientation.RIGHT_TOP:
+ return 90;
+ case Orientation.BOTTOM_LEFT:
+ return 180;
+ case Orientation.RIGHT_BOTTOM:
+ return 270;
+ default:
+ return 0;
+ }
+ }
+
+ /**
+ * Gets the double representation of the GPS latitude or longitude
+ * coordinate.
+ *
+ * @param coordinate an array of 3 Rationals representing the degrees,
+ * minutes, and seconds of the GPS location as defined in the
+ * exif specification.
+ * @param reference a GPS reference reperesented by a String containing "N",
+ * "S", "E", or "W".
+ * @return the GPS coordinate represented as degrees + minutes/60 +
+ * seconds/3600
+ */
+ public static double convertLatOrLongToDouble(Rational[] coordinate, String reference) {
+ try {
+ double degrees = coordinate[0].toDouble();
+ double minutes = coordinate[1].toDouble();
+ double seconds = coordinate[2].toDouble();
+ double result = degrees + minutes / 60.0 + seconds / 3600.0;
+ if ((reference.equals("S") || reference.equals("W"))) {
+ return -result;
+ }
+ return result;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Gets the GPS latitude and longitude as a pair of doubles from this
+ * ExifInterface object's tags, or null if the necessary tags do not exist.
+ *
+ * @return an array of 2 doubles containing the latitude, and longitude
+ * respectively.
+ * @see #convertLatOrLongToDouble
+ */
+ public double[] getLatLongAsDoubles() {
+ Rational[] latitude = getTagRationalValues(TAG_GPS_LATITUDE);
+ String latitudeRef = getTagStringValue(TAG_GPS_LATITUDE_REF);
+ Rational[] longitude = getTagRationalValues(TAG_GPS_LONGITUDE);
+ String longitudeRef = getTagStringValue(TAG_GPS_LONGITUDE_REF);
+ if (latitude == null || longitude == null || latitudeRef == null || longitudeRef == null
+ || latitude.length < 3 || longitude.length < 3) {
+ return null;
+ }
+ double[] latLon = new double[2];
+ latLon[0] = convertLatOrLongToDouble(latitude, latitudeRef);
+ latLon[1] = convertLatOrLongToDouble(longitude, longitudeRef);
+ return latLon;
+ }
+
+ private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd";
+ private static final String DATETIME_FORMAT_STR = "yyyy:MM:dd kk:mm:ss";
+ private final DateFormat mDateTimeStampFormat = new SimpleDateFormat(DATETIME_FORMAT_STR);
+ private final DateFormat mGPSDateStampFormat = new SimpleDateFormat(GPS_DATE_FORMAT_STR);
+ private final Calendar mGPSTimeStampCalendar = Calendar
+ .getInstance(TimeZone.getTimeZone("UTC"));
+
+ /**
+ * Creates, formats, and sets the DateTimeStamp tag for one of:
+ * {@link #TAG_DATE_TIME}, {@link #TAG_DATE_TIME_DIGITIZED},
+ * {@link #TAG_DATE_TIME_ORIGINAL}.
+ *
+ * @param tagId one of the DateTimeStamp tags.
+ * @param timestamp a timestamp to format.
+ * @param timezone a TimeZone object.
+ * @return true if success, false if the tag could not be set.
+ */
+ public boolean addDateTimeStampTag(int tagId, long timestamp, TimeZone timezone) {
+ if (tagId == TAG_DATE_TIME || tagId == TAG_DATE_TIME_DIGITIZED
+ || tagId == TAG_DATE_TIME_ORIGINAL) {
+ mDateTimeStampFormat.setTimeZone(timezone);
+ ExifTag t = buildTag(tagId, mDateTimeStampFormat.format(timestamp));
+ if (t == null) {
+ return false;
+ }
+ setTag(t);
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Creates and sets all to the GPS tags for a give latitude and longitude.
+ *
+ * @param latitude a GPS latitude coordinate.
+ * @param longitude a GPS longitude coordinate.
+ * @return true if success, false if they could not be created or set.
+ */
+ public boolean addGpsTags(double latitude, double longitude) {
+ ExifTag latTag = buildTag(TAG_GPS_LATITUDE, toExifLatLong(latitude));
+ ExifTag longTag = buildTag(TAG_GPS_LONGITUDE, toExifLatLong(longitude));
+ ExifTag latRefTag = buildTag(TAG_GPS_LATITUDE_REF,
+ latitude >= 0 ? ExifInterface.GpsLatitudeRef.NORTH
+ : ExifInterface.GpsLatitudeRef.SOUTH);
+ ExifTag longRefTag = buildTag(TAG_GPS_LONGITUDE_REF,
+ longitude >= 0 ? ExifInterface.GpsLongitudeRef.EAST
+ : ExifInterface.GpsLongitudeRef.WEST);
+ if (latTag == null || longTag == null || latRefTag == null || longRefTag == null) {
+ return false;
+ }
+ setTag(latTag);
+ setTag(longTag);
+ setTag(latRefTag);
+ setTag(longRefTag);
+ return true;
+ }
+
+ /**
+ * Creates and sets the GPS timestamp tag.
+ *
+ * @param timestamp a GPS timestamp.
+ * @return true if success, false if could not be created or set.
+ */
+ public boolean addGpsDateTimeStampTag(long timestamp) {
+ ExifTag t = buildTag(TAG_GPS_DATE_STAMP, mGPSDateStampFormat.format(timestamp));
+ if (t == null) {
+ return false;
+ }
+ setTag(t);
+ mGPSTimeStampCalendar.setTimeInMillis(timestamp);
+ t = buildTag(TAG_GPS_TIME_STAMP, new Rational[] {
+ new Rational(mGPSTimeStampCalendar.get(Calendar.HOUR_OF_DAY), 1),
+ new Rational(mGPSTimeStampCalendar.get(Calendar.MINUTE), 1),
+ new Rational(mGPSTimeStampCalendar.get(Calendar.SECOND), 1)
+ });
+ if (t == null) {
+ return false;
+ }
+ setTag(t);
+ return true;
+ }
+
+ private static Rational[] toExifLatLong(double value) {
+ // convert to the format dd/1 mm/1 ssss/100
+ value = Math.abs(value);
+ int degrees = (int) value;
+ value = (value - degrees) * 60;
+ int minutes = (int) value;
+ value = (value - minutes) * 6000;
+ int seconds = (int) value;
+ return new Rational[] {
+ new Rational(degrees, 1), new Rational(minutes, 1), new Rational(seconds, 100)
+ };
+ }
+
+ private void doExifStreamIO(InputStream is, OutputStream os) throws IOException {
+ byte[] buf = new byte[1024];
+ int ret = is.read(buf, 0, 1024);
+ while (ret != -1) {
+ os.write(buf, 0, ret);
+ ret = is.read(buf, 0, 1024);
+ }
+ }
+
+ protected static void closeSilently(Closeable c) {
+ if (c != null) {
+ try {
+ c.close();
+ } catch (Throwable e) {
+ // ignored
+ }
+ }
+ }
+
+ private SparseIntArray mTagInfo = null;
+
+ protected SparseIntArray getTagInfo() {
+ if (mTagInfo == null) {
+ mTagInfo = new SparseIntArray();
+ initTagInfo();
+ }
+ return mTagInfo;
+ }
+
+ private void initTagInfo() {
+ /**
+ * We put tag information in a 4-bytes integer. The first byte a bitmask
+ * representing the allowed IFDs of the tag, the second byte is the data
+ * type, and the last two byte are a short value indicating the default
+ * component count of this tag.
+ */
+ // IFD0 tags
+ int[] ifdAllowedIfds = {
+ IfdId.TYPE_IFD_0, IfdId.TYPE_IFD_1
+ };
+ int ifdFlags = getFlagsFromAllowedIfds(ifdAllowedIfds) << 24;
+ mTagInfo.put(ExifInterface.TAG_MAKE,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_IMAGE_WIDTH,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_IMAGE_LENGTH,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_BITS_PER_SAMPLE,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 3);
+ mTagInfo.put(ExifInterface.TAG_COMPRESSION,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_PHOTOMETRIC_INTERPRETATION,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_ORIENTATION, ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16
+ | 1);
+ mTagInfo.put(ExifInterface.TAG_SAMPLES_PER_PIXEL,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_PLANAR_CONFIGURATION,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_Y_CB_CR_SUB_SAMPLING,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_Y_CB_CR_POSITIONING,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_X_RESOLUTION,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_Y_RESOLUTION,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_RESOLUTION_UNIT,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_STRIP_OFFSETS,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_ROWS_PER_STRIP,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_STRIP_BYTE_COUNTS,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_TRANSFER_FUNCTION,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 3 * 256);
+ mTagInfo.put(ExifInterface.TAG_WHITE_POINT,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_PRIMARY_CHROMATICITIES,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 6);
+ mTagInfo.put(ExifInterface.TAG_Y_CB_CR_COEFFICIENTS,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 3);
+ mTagInfo.put(ExifInterface.TAG_REFERENCE_BLACK_WHITE,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 6);
+ mTagInfo.put(ExifInterface.TAG_DATE_TIME,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | 20);
+ mTagInfo.put(ExifInterface.TAG_IMAGE_DESCRIPTION,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_MAKE,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_MODEL,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_SOFTWARE,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_ARTIST,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_COPYRIGHT,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_EXIF_IFD,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_IFD,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ // IFD1 tags
+ int[] ifd1AllowedIfds = {
+ IfdId.TYPE_IFD_1
+ };
+ int ifdFlags1 = getFlagsFromAllowedIfds(ifd1AllowedIfds) << 24;
+ mTagInfo.put(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT,
+ ifdFlags1 | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
+ ifdFlags1 | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ // Exif tags
+ int[] exifAllowedIfds = {
+ IfdId.TYPE_IFD_EXIF
+ };
+ int exifFlags = getFlagsFromAllowedIfds(exifAllowedIfds) << 24;
+ mTagInfo.put(ExifInterface.TAG_EXIF_VERSION,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
+ mTagInfo.put(ExifInterface.TAG_FLASHPIX_VERSION,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
+ mTagInfo.put(ExifInterface.TAG_COLOR_SPACE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_COMPONENTS_CONFIGURATION,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
+ mTagInfo.put(ExifInterface.TAG_COMPRESSED_BITS_PER_PIXEL,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_PIXEL_X_DIMENSION,
+ exifFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_PIXEL_Y_DIMENSION,
+ exifFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_MAKER_NOTE,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_USER_COMMENT,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_RELATED_SOUND_FILE,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | 13);
+ mTagInfo.put(ExifInterface.TAG_DATE_TIME_ORIGINAL,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | 20);
+ mTagInfo.put(ExifInterface.TAG_DATE_TIME_DIGITIZED,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | 20);
+ mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME_ORIGINAL,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME_DIGITIZED,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_IMAGE_UNIQUE_ID,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | 33);
+ mTagInfo.put(ExifInterface.TAG_EXPOSURE_TIME,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_F_NUMBER,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_EXPOSURE_PROGRAM,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SPECTRAL_SENSITIVITY,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_ISO_SPEED_RATINGS,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_OECF,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_SHUTTER_SPEED_VALUE,
+ exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_APERTURE_VALUE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_BRIGHTNESS_VALUE,
+ exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_EXPOSURE_BIAS_VALUE,
+ exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_MAX_APERTURE_VALUE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SUBJECT_DISTANCE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_METERING_MODE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_LIGHT_SOURCE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_FLASH,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_FOCAL_LENGTH,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SUBJECT_AREA,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_FLASH_ENERGY,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SPATIAL_FREQUENCY_RESPONSE,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_X_RESOLUTION,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_Y_RESOLUTION,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_RESOLUTION_UNIT,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SUBJECT_LOCATION,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_EXPOSURE_INDEX,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SENSING_METHOD,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_FILE_SOURCE,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SCENE_TYPE,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_CFA_PATTERN,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_CUSTOM_RENDERED,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_EXPOSURE_MODE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_WHITE_BALANCE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_DIGITAL_ZOOM_RATIO,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_FOCAL_LENGTH_IN_35_MM_FILE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SCENE_CAPTURE_TYPE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GAIN_CONTROL,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_CONTRAST,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SATURATION,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SHARPNESS,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_DEVICE_SETTING_DESCRIPTION,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_SUBJECT_DISTANCE_RANGE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_INTEROPERABILITY_IFD, exifFlags
+ | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ // GPS tag
+ int[] gpsAllowedIfds = {
+ IfdId.TYPE_IFD_GPS
+ };
+ int gpsFlags = getFlagsFromAllowedIfds(gpsAllowedIfds) << 24;
+ mTagInfo.put(ExifInterface.TAG_GPS_VERSION_ID,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_BYTE << 16 | 4);
+ mTagInfo.put(ExifInterface.TAG_GPS_LATITUDE_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_LONGITUDE_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_LATITUDE,
+ gpsFlags | ExifTag.TYPE_RATIONAL << 16 | 3);
+ mTagInfo.put(ExifInterface.TAG_GPS_LONGITUDE,
+ gpsFlags | ExifTag.TYPE_RATIONAL << 16 | 3);
+ mTagInfo.put(ExifInterface.TAG_GPS_ALTITUDE_REF,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_BYTE << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_ALTITUDE,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_TIME_STAMP,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 3);
+ mTagInfo.put(ExifInterface.TAG_GPS_SATTELLITES,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_GPS_STATUS,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_MEASURE_MODE,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_DOP,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_SPEED_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_SPEED,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_TRACK_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_TRACK,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_IMG_DIRECTION,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_MAP_DATUM,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_GPS_DEST_LATITUDE_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_DEST_LATITUDE,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_DEST_BEARING_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_DEST_BEARING,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_DEST_DISTANCE_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_DEST_DISTANCE,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_PROCESSING_METHOD,
+ gpsFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_GPS_AREA_INFORMATION,
+ gpsFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_GPS_DATE_STAMP,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 11);
+ mTagInfo.put(ExifInterface.TAG_GPS_DIFFERENTIAL,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 11);
+ // Interoperability tag
+ int[] interopAllowedIfds = {
+ IfdId.TYPE_IFD_INTEROPERABILITY
+ };
+ int interopFlags = getFlagsFromAllowedIfds(interopAllowedIfds) << 24;
+ mTagInfo.put(TAG_INTEROPERABILITY_INDEX, interopFlags | ExifTag.TYPE_ASCII << 16
+ | ExifTag.SIZE_UNDEFINED);
+ }
+
+ protected static int getAllowedIfdFlagsFromInfo(int info) {
+ return info >>> 24;
+ }
+
+ protected static int[] getAllowedIfdsFromInfo(int info) {
+ int ifdFlags = getAllowedIfdFlagsFromInfo(info);
+ int[] ifds = IfdData.getIfds();
+ ArrayList<Integer> l = new ArrayList<Integer>();
+ for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
+ int flag = (ifdFlags >> i) & 1;
+ if (flag == 1) {
+ l.add(ifds[i]);
+ }
+ }
+ if (l.size() <= 0) {
+ return null;
+ }
+ int[] ret = new int[l.size()];
+ int j = 0;
+ for (int i : l) {
+ ret[j++] = i;
+ }
+ return ret;
+ }
+
+ protected static boolean isIfdAllowed(int info, int ifd) {
+ int[] ifds = IfdData.getIfds();
+ int ifdFlags = getAllowedIfdFlagsFromInfo(info);
+ for (int i = 0; i < ifds.length; i++) {
+ if (ifd == ifds[i] && ((ifdFlags >> i) & 1) == 1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected static int getFlagsFromAllowedIfds(int[] allowedIfds) {
+ if (allowedIfds == null || allowedIfds.length == 0) {
+ return 0;
+ }
+ int flags = 0;
+ int[] ifds = IfdData.getIfds();
+ for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
+ for (int j : allowedIfds) {
+ if (ifds[i] == j) {
+ flags |= 1 << i;
+ break;
+ }
+ }
+ }
+ return flags;
+ }
+
+ protected static short getTypeFromInfo(int info) {
+ return (short) ((info >> 16) & 0x0ff);
+ }
+
+ protected static int getComponentCountFromInfo(int info) {
+ return info & 0x0ffff;
+ }
+
+}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.aidl b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInvalidFormatException.java
similarity index 70%
copy from core/java/android/hardware/camera2/CameraMetadata.aidl
copy to packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInvalidFormatException.java
index 71dd471..bf923ec 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.aidl
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInvalidFormatException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,10 @@
* limitations under the License.
*/
-package android.hardware.camera2;
+package com.android.gallery3d.exif;
-/** @hide */
-parcelable CameraMetadata;
+public class ExifInvalidFormatException extends Exception {
+ public ExifInvalidFormatException(String meg) {
+ super(meg);
+ }
+}
\ No newline at end of file
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifModifier.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifModifier.java
new file mode 100644
index 0000000..f00362b
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifModifier.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+class ExifModifier {
+ public static final String TAG = "ExifModifier";
+ public static final boolean DEBUG = false;
+ private final ByteBuffer mByteBuffer;
+ private final ExifData mTagToModified;
+ private final List<TagOffset> mTagOffsets = new ArrayList<TagOffset>();
+ private final ExifInterface mInterface;
+ private int mOffsetBase;
+
+ private static class TagOffset {
+ final int mOffset;
+ final ExifTag mTag;
+
+ TagOffset(ExifTag tag, int offset) {
+ mTag = tag;
+ mOffset = offset;
+ }
+ }
+
+ protected ExifModifier(ByteBuffer byteBuffer, ExifInterface iRef) throws IOException,
+ ExifInvalidFormatException {
+ mByteBuffer = byteBuffer;
+ mOffsetBase = byteBuffer.position();
+ mInterface = iRef;
+ InputStream is = null;
+ try {
+ is = new ByteBufferInputStream(byteBuffer);
+ // Do not require any IFD;
+ ExifParser parser = ExifParser.parse(is, mInterface);
+ mTagToModified = new ExifData(parser.getByteOrder());
+ mOffsetBase += parser.getTiffStartPosition();
+ mByteBuffer.position(0);
+ } finally {
+ ExifInterface.closeSilently(is);
+ }
+ }
+
+ protected ByteOrder getByteOrder() {
+ return mTagToModified.getByteOrder();
+ }
+
+ protected boolean commit() throws IOException, ExifInvalidFormatException {
+ InputStream is = null;
+ try {
+ is = new ByteBufferInputStream(mByteBuffer);
+ int flag = 0;
+ IfdData[] ifdDatas = new IfdData[] {
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_0),
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_1),
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_EXIF),
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY),
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_GPS)
+ };
+
+ if (ifdDatas[IfdId.TYPE_IFD_0] != null) {
+ flag |= ExifParser.OPTION_IFD_0;
+ }
+ if (ifdDatas[IfdId.TYPE_IFD_1] != null) {
+ flag |= ExifParser.OPTION_IFD_1;
+ }
+ if (ifdDatas[IfdId.TYPE_IFD_EXIF] != null) {
+ flag |= ExifParser.OPTION_IFD_EXIF;
+ }
+ if (ifdDatas[IfdId.TYPE_IFD_GPS] != null) {
+ flag |= ExifParser.OPTION_IFD_GPS;
+ }
+ if (ifdDatas[IfdId.TYPE_IFD_INTEROPERABILITY] != null) {
+ flag |= ExifParser.OPTION_IFD_INTEROPERABILITY;
+ }
+
+ ExifParser parser = ExifParser.parse(is, flag, mInterface);
+ int event = parser.next();
+ IfdData currIfd = null;
+ while (event != ExifParser.EVENT_END) {
+ switch (event) {
+ case ExifParser.EVENT_START_OF_IFD:
+ currIfd = ifdDatas[parser.getCurrentIfd()];
+ if (currIfd == null) {
+ parser.skipRemainingTagsInCurrentIfd();
+ }
+ break;
+ case ExifParser.EVENT_NEW_TAG:
+ ExifTag oldTag = parser.getTag();
+ ExifTag newTag = currIfd.getTag(oldTag.getTagId());
+ if (newTag != null) {
+ if (newTag.getComponentCount() != oldTag.getComponentCount()
+ || newTag.getDataType() != oldTag.getDataType()) {
+ return false;
+ } else {
+ mTagOffsets.add(new TagOffset(newTag, oldTag.getOffset()));
+ currIfd.removeTag(oldTag.getTagId());
+ if (currIfd.getTagCount() == 0) {
+ parser.skipRemainingTagsInCurrentIfd();
+ }
+ }
+ }
+ break;
+ }
+ event = parser.next();
+ }
+ for (IfdData ifd : ifdDatas) {
+ if (ifd != null && ifd.getTagCount() > 0) {
+ return false;
+ }
+ }
+ modify();
+ } finally {
+ ExifInterface.closeSilently(is);
+ }
+ return true;
+ }
+
+ private void modify() {
+ mByteBuffer.order(getByteOrder());
+ for (TagOffset tagOffset : mTagOffsets) {
+ writeTagValue(tagOffset.mTag, tagOffset.mOffset);
+ }
+ }
+
+ private void writeTagValue(ExifTag tag, int offset) {
+ if (DEBUG) {
+ Log.v(TAG, "modifying tag to: \n" + tag.toString());
+ Log.v(TAG, "at offset: " + offset);
+ }
+ mByteBuffer.position(offset + mOffsetBase);
+ switch (tag.getDataType()) {
+ case ExifTag.TYPE_ASCII:
+ byte buf[] = tag.getStringByte();
+ if (buf.length == tag.getComponentCount()) {
+ buf[buf.length - 1] = 0;
+ mByteBuffer.put(buf);
+ } else {
+ mByteBuffer.put(buf);
+ mByteBuffer.put((byte) 0);
+ }
+ break;
+ case ExifTag.TYPE_LONG:
+ case ExifTag.TYPE_UNSIGNED_LONG:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ mByteBuffer.putInt((int) tag.getValueAt(i));
+ }
+ break;
+ case ExifTag.TYPE_RATIONAL:
+ case ExifTag.TYPE_UNSIGNED_RATIONAL:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ Rational v = tag.getRational(i);
+ mByteBuffer.putInt((int) v.getNumerator());
+ mByteBuffer.putInt((int) v.getDenominator());
+ }
+ break;
+ case ExifTag.TYPE_UNDEFINED:
+ case ExifTag.TYPE_UNSIGNED_BYTE:
+ buf = new byte[tag.getComponentCount()];
+ tag.getBytes(buf);
+ mByteBuffer.put(buf);
+ break;
+ case ExifTag.TYPE_UNSIGNED_SHORT:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ mByteBuffer.putShort((short) tag.getValueAt(i));
+ }
+ break;
+ }
+ }
+
+ public void modifyTag(ExifTag tag) {
+ mTagToModified.addTag(tag);
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifOutputStream.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifOutputStream.java
new file mode 100644
index 0000000..7ca05f2e
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifOutputStream.java
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.BufferedOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+
+/**
+ * This class provides a way to replace the Exif header of a JPEG image.
+ * <p>
+ * Below is an example of writing EXIF data into a file
+ *
+ * <pre>
+ * public static void writeExif(byte[] jpeg, ExifData exif, String path) {
+ * OutputStream os = null;
+ * try {
+ * os = new FileOutputStream(path);
+ * ExifOutputStream eos = new ExifOutputStream(os);
+ * // Set the exif header
+ * eos.setExifData(exif);
+ * // Write the original jpeg out, the header will be add into the file.
+ * eos.write(jpeg);
+ * } catch (FileNotFoundException e) {
+ * e.printStackTrace();
+ * } catch (IOException e) {
+ * e.printStackTrace();
+ * } finally {
+ * if (os != null) {
+ * try {
+ * os.close();
+ * } catch (IOException e) {
+ * e.printStackTrace();
+ * }
+ * }
+ * }
+ * }
+ * </pre>
+ */
+class ExifOutputStream extends FilterOutputStream {
+ private static final String TAG = "ExifOutputStream";
+ private static final boolean DEBUG = false;
+ private static final int STREAMBUFFER_SIZE = 0x00010000; // 64Kb
+
+ private static final int STATE_SOI = 0;
+ private static final int STATE_FRAME_HEADER = 1;
+ private static final int STATE_JPEG_DATA = 2;
+
+ private static final int EXIF_HEADER = 0x45786966;
+ private static final short TIFF_HEADER = 0x002A;
+ private static final short TIFF_BIG_ENDIAN = 0x4d4d;
+ private static final short TIFF_LITTLE_ENDIAN = 0x4949;
+ private static final short TAG_SIZE = 12;
+ private static final short TIFF_HEADER_SIZE = 8;
+ private static final int MAX_EXIF_SIZE = 65535;
+
+ private ExifData mExifData;
+ private int mState = STATE_SOI;
+ private int mByteToSkip;
+ private int mByteToCopy;
+ private byte[] mSingleByteArray = new byte[1];
+ private ByteBuffer mBuffer = ByteBuffer.allocate(4);
+ private final ExifInterface mInterface;
+
+ protected ExifOutputStream(OutputStream ou, ExifInterface iRef) {
+ super(new BufferedOutputStream(ou, STREAMBUFFER_SIZE));
+ mInterface = iRef;
+ }
+
+ /**
+ * Sets the ExifData to be written into the JPEG file. Should be called
+ * before writing image data.
+ */
+ protected void setExifData(ExifData exifData) {
+ mExifData = exifData;
+ }
+
+ /**
+ * Gets the Exif header to be written into the JPEF file.
+ */
+ protected ExifData getExifData() {
+ return mExifData;
+ }
+
+ private int requestByteToBuffer(int requestByteCount, byte[] buffer
+ , int offset, int length) {
+ int byteNeeded = requestByteCount - mBuffer.position();
+ int byteToRead = length > byteNeeded ? byteNeeded : length;
+ mBuffer.put(buffer, offset, byteToRead);
+ return byteToRead;
+ }
+
+ /**
+ * Writes the image out. The input data should be a valid JPEG format. After
+ * writing, it's Exif header will be replaced by the given header.
+ */
+ @Override
+ public void write(byte[] buffer, int offset, int length) throws IOException {
+ while ((mByteToSkip > 0 || mByteToCopy > 0 || mState != STATE_JPEG_DATA)
+ && length > 0) {
+ if (mByteToSkip > 0) {
+ int byteToProcess = length > mByteToSkip ? mByteToSkip : length;
+ length -= byteToProcess;
+ mByteToSkip -= byteToProcess;
+ offset += byteToProcess;
+ }
+ if (mByteToCopy > 0) {
+ int byteToProcess = length > mByteToCopy ? mByteToCopy : length;
+ out.write(buffer, offset, byteToProcess);
+ length -= byteToProcess;
+ mByteToCopy -= byteToProcess;
+ offset += byteToProcess;
+ }
+ if (length == 0) {
+ return;
+ }
+ switch (mState) {
+ case STATE_SOI:
+ int byteRead = requestByteToBuffer(2, buffer, offset, length);
+ offset += byteRead;
+ length -= byteRead;
+ if (mBuffer.position() < 2) {
+ return;
+ }
+ mBuffer.rewind();
+ if (mBuffer.getShort() != JpegHeader.SOI) {
+ throw new IOException("Not a valid jpeg image, cannot write exif");
+ }
+ out.write(mBuffer.array(), 0, 2);
+ mState = STATE_FRAME_HEADER;
+ mBuffer.rewind();
+ writeExifData();
+ break;
+ case STATE_FRAME_HEADER:
+ // We ignore the APP1 segment and copy all other segments
+ // until SOF tag.
+ byteRead = requestByteToBuffer(4, buffer, offset, length);
+ offset += byteRead;
+ length -= byteRead;
+ // Check if this image data doesn't contain SOF.
+ if (mBuffer.position() == 2) {
+ short tag = mBuffer.getShort();
+ if (tag == JpegHeader.EOI) {
+ out.write(mBuffer.array(), 0, 2);
+ mBuffer.rewind();
+ }
+ }
+ if (mBuffer.position() < 4) {
+ return;
+ }
+ mBuffer.rewind();
+ short marker = mBuffer.getShort();
+ if (marker == JpegHeader.APP1) {
+ mByteToSkip = (mBuffer.getShort() & 0x0000ffff) - 2;
+ mState = STATE_JPEG_DATA;
+ } else if (!JpegHeader.isSofMarker(marker)) {
+ out.write(mBuffer.array(), 0, 4);
+ mByteToCopy = (mBuffer.getShort() & 0x0000ffff) - 2;
+ } else {
+ out.write(mBuffer.array(), 0, 4);
+ mState = STATE_JPEG_DATA;
+ }
+ mBuffer.rewind();
+ }
+ }
+ if (length > 0) {
+ out.write(buffer, offset, length);
+ }
+ }
+
+ /**
+ * Writes the one bytes out. The input data should be a valid JPEG format.
+ * After writing, it's Exif header will be replaced by the given header.
+ */
+ @Override
+ public void write(int oneByte) throws IOException {
+ mSingleByteArray[0] = (byte) (0xff & oneByte);
+ write(mSingleByteArray);
+ }
+
+ /**
+ * Equivalent to calling write(buffer, 0, buffer.length).
+ */
+ @Override
+ public void write(byte[] buffer) throws IOException {
+ write(buffer, 0, buffer.length);
+ }
+
+ private void writeExifData() throws IOException {
+ if (mExifData == null) {
+ return;
+ }
+ if (DEBUG) {
+ Log.v(TAG, "Writing exif data...");
+ }
+ ArrayList<ExifTag> nullTags = stripNullValueTags(mExifData);
+ createRequiredIfdAndTag();
+ int exifSize = calculateAllOffset();
+ if (exifSize + 8 > MAX_EXIF_SIZE) {
+ throw new IOException("Exif header is too large (>64Kb)");
+ }
+ OrderedDataOutputStream dataOutputStream = new OrderedDataOutputStream(out);
+ dataOutputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
+ dataOutputStream.writeShort(JpegHeader.APP1);
+ dataOutputStream.writeShort((short) (exifSize + 8));
+ dataOutputStream.writeInt(EXIF_HEADER);
+ dataOutputStream.writeShort((short) 0x0000);
+ if (mExifData.getByteOrder() == ByteOrder.BIG_ENDIAN) {
+ dataOutputStream.writeShort(TIFF_BIG_ENDIAN);
+ } else {
+ dataOutputStream.writeShort(TIFF_LITTLE_ENDIAN);
+ }
+ dataOutputStream.setByteOrder(mExifData.getByteOrder());
+ dataOutputStream.writeShort(TIFF_HEADER);
+ dataOutputStream.writeInt(8);
+ writeAllTags(dataOutputStream);
+ writeThumbnail(dataOutputStream);
+ for (ExifTag t : nullTags) {
+ mExifData.addTag(t);
+ }
+ }
+
+ private ArrayList<ExifTag> stripNullValueTags(ExifData data) {
+ ArrayList<ExifTag> nullTags = new ArrayList<ExifTag>();
+ for(ExifTag t : data.getAllTags()) {
+ if (t.getValue() == null && !ExifInterface.isOffsetTag(t.getTagId())) {
+ data.removeTag(t.getTagId(), t.getIfd());
+ nullTags.add(t);
+ }
+ }
+ return nullTags;
+ }
+
+ private void writeThumbnail(OrderedDataOutputStream dataOutputStream) throws IOException {
+ if (mExifData.hasCompressedThumbnail()) {
+ dataOutputStream.write(mExifData.getCompressedThumbnail());
+ } else if (mExifData.hasUncompressedStrip()) {
+ for (int i = 0; i < mExifData.getStripCount(); i++) {
+ dataOutputStream.write(mExifData.getStrip(i));
+ }
+ }
+ }
+
+ private void writeAllTags(OrderedDataOutputStream dataOutputStream) throws IOException {
+ writeIfd(mExifData.getIfdData(IfdId.TYPE_IFD_0), dataOutputStream);
+ writeIfd(mExifData.getIfdData(IfdId.TYPE_IFD_EXIF), dataOutputStream);
+ IfdData interoperabilityIfd = mExifData.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY);
+ if (interoperabilityIfd != null) {
+ writeIfd(interoperabilityIfd, dataOutputStream);
+ }
+ IfdData gpsIfd = mExifData.getIfdData(IfdId.TYPE_IFD_GPS);
+ if (gpsIfd != null) {
+ writeIfd(gpsIfd, dataOutputStream);
+ }
+ IfdData ifd1 = mExifData.getIfdData(IfdId.TYPE_IFD_1);
+ if (ifd1 != null) {
+ writeIfd(mExifData.getIfdData(IfdId.TYPE_IFD_1), dataOutputStream);
+ }
+ }
+
+ private void writeIfd(IfdData ifd, OrderedDataOutputStream dataOutputStream)
+ throws IOException {
+ ExifTag[] tags = ifd.getAllTags();
+ dataOutputStream.writeShort((short) tags.length);
+ for (ExifTag tag : tags) {
+ dataOutputStream.writeShort(tag.getTagId());
+ dataOutputStream.writeShort(tag.getDataType());
+ dataOutputStream.writeInt(tag.getComponentCount());
+ if (DEBUG) {
+ Log.v(TAG, "\n" + tag.toString());
+ }
+ if (tag.getDataSize() > 4) {
+ dataOutputStream.writeInt(tag.getOffset());
+ } else {
+ ExifOutputStream.writeTagValue(tag, dataOutputStream);
+ for (int i = 0, n = 4 - tag.getDataSize(); i < n; i++) {
+ dataOutputStream.write(0);
+ }
+ }
+ }
+ dataOutputStream.writeInt(ifd.getOffsetToNextIfd());
+ for (ExifTag tag : tags) {
+ if (tag.getDataSize() > 4) {
+ ExifOutputStream.writeTagValue(tag, dataOutputStream);
+ }
+ }
+ }
+
+ private int calculateOffsetOfIfd(IfdData ifd, int offset) {
+ offset += 2 + ifd.getTagCount() * TAG_SIZE + 4;
+ ExifTag[] tags = ifd.getAllTags();
+ for (ExifTag tag : tags) {
+ if (tag.getDataSize() > 4) {
+ tag.setOffset(offset);
+ offset += tag.getDataSize();
+ }
+ }
+ return offset;
+ }
+
+ private void createRequiredIfdAndTag() throws IOException {
+ // IFD0 is required for all file
+ IfdData ifd0 = mExifData.getIfdData(IfdId.TYPE_IFD_0);
+ if (ifd0 == null) {
+ ifd0 = new IfdData(IfdId.TYPE_IFD_0);
+ mExifData.addIfdData(ifd0);
+ }
+ ExifTag exifOffsetTag = mInterface.buildUninitializedTag(ExifInterface.TAG_EXIF_IFD);
+ if (exifOffsetTag == null) {
+ throw new IOException("No definition for crucial exif tag: "
+ + ExifInterface.TAG_EXIF_IFD);
+ }
+ ifd0.setTag(exifOffsetTag);
+
+ // Exif IFD is required for all files.
+ IfdData exifIfd = mExifData.getIfdData(IfdId.TYPE_IFD_EXIF);
+ if (exifIfd == null) {
+ exifIfd = new IfdData(IfdId.TYPE_IFD_EXIF);
+ mExifData.addIfdData(exifIfd);
+ }
+
+ // GPS IFD
+ IfdData gpsIfd = mExifData.getIfdData(IfdId.TYPE_IFD_GPS);
+ if (gpsIfd != null) {
+ ExifTag gpsOffsetTag = mInterface.buildUninitializedTag(ExifInterface.TAG_GPS_IFD);
+ if (gpsOffsetTag == null) {
+ throw new IOException("No definition for crucial exif tag: "
+ + ExifInterface.TAG_GPS_IFD);
+ }
+ ifd0.setTag(gpsOffsetTag);
+ }
+
+ // Interoperability IFD
+ IfdData interIfd = mExifData.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY);
+ if (interIfd != null) {
+ ExifTag interOffsetTag = mInterface
+ .buildUninitializedTag(ExifInterface.TAG_INTEROPERABILITY_IFD);
+ if (interOffsetTag == null) {
+ throw new IOException("No definition for crucial exif tag: "
+ + ExifInterface.TAG_INTEROPERABILITY_IFD);
+ }
+ exifIfd.setTag(interOffsetTag);
+ }
+
+ IfdData ifd1 = mExifData.getIfdData(IfdId.TYPE_IFD_1);
+
+ // thumbnail
+ if (mExifData.hasCompressedThumbnail()) {
+
+ if (ifd1 == null) {
+ ifd1 = new IfdData(IfdId.TYPE_IFD_1);
+ mExifData.addIfdData(ifd1);
+ }
+
+ ExifTag offsetTag = mInterface
+ .buildUninitializedTag(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
+ if (offsetTag == null) {
+ throw new IOException("No definition for crucial exif tag: "
+ + ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
+ }
+
+ ifd1.setTag(offsetTag);
+ ExifTag lengthTag = mInterface
+ .buildUninitializedTag(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
+ if (lengthTag == null) {
+ throw new IOException("No definition for crucial exif tag: "
+ + ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
+ }
+
+ lengthTag.setValue(mExifData.getCompressedThumbnail().length);
+ ifd1.setTag(lengthTag);
+
+ // Get rid of tags for uncompressed if they exist.
+ ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS));
+ ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS));
+ } else if (mExifData.hasUncompressedStrip()) {
+ if (ifd1 == null) {
+ ifd1 = new IfdData(IfdId.TYPE_IFD_1);
+ mExifData.addIfdData(ifd1);
+ }
+ int stripCount = mExifData.getStripCount();
+ ExifTag offsetTag = mInterface.buildUninitializedTag(ExifInterface.TAG_STRIP_OFFSETS);
+ if (offsetTag == null) {
+ throw new IOException("No definition for crucial exif tag: "
+ + ExifInterface.TAG_STRIP_OFFSETS);
+ }
+ ExifTag lengthTag = mInterface
+ .buildUninitializedTag(ExifInterface.TAG_STRIP_BYTE_COUNTS);
+ if (lengthTag == null) {
+ throw new IOException("No definition for crucial exif tag: "
+ + ExifInterface.TAG_STRIP_BYTE_COUNTS);
+ }
+ long[] lengths = new long[stripCount];
+ for (int i = 0; i < mExifData.getStripCount(); i++) {
+ lengths[i] = mExifData.getStrip(i).length;
+ }
+ lengthTag.setValue(lengths);
+ ifd1.setTag(offsetTag);
+ ifd1.setTag(lengthTag);
+ // Get rid of tags for compressed if they exist.
+ ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT));
+ ifd1.removeTag(ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH));
+ } else if (ifd1 != null) {
+ // Get rid of offset and length tags if there is no thumbnail.
+ ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS));
+ ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS));
+ ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT));
+ ifd1.removeTag(ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH));
+ }
+ }
+
+ private int calculateAllOffset() {
+ int offset = TIFF_HEADER_SIZE;
+ IfdData ifd0 = mExifData.getIfdData(IfdId.TYPE_IFD_0);
+ offset = calculateOffsetOfIfd(ifd0, offset);
+ ifd0.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_EXIF_IFD)).setValue(offset);
+
+ IfdData exifIfd = mExifData.getIfdData(IfdId.TYPE_IFD_EXIF);
+ offset = calculateOffsetOfIfd(exifIfd, offset);
+
+ IfdData interIfd = mExifData.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY);
+ if (interIfd != null) {
+ exifIfd.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_INTEROPERABILITY_IFD))
+ .setValue(offset);
+ offset = calculateOffsetOfIfd(interIfd, offset);
+ }
+
+ IfdData gpsIfd = mExifData.getIfdData(IfdId.TYPE_IFD_GPS);
+ if (gpsIfd != null) {
+ ifd0.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_GPS_IFD)).setValue(offset);
+ offset = calculateOffsetOfIfd(gpsIfd, offset);
+ }
+
+ IfdData ifd1 = mExifData.getIfdData(IfdId.TYPE_IFD_1);
+ if (ifd1 != null) {
+ ifd0.setOffsetToNextIfd(offset);
+ offset = calculateOffsetOfIfd(ifd1, offset);
+ }
+
+ // thumbnail
+ if (mExifData.hasCompressedThumbnail()) {
+ ifd1.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT))
+ .setValue(offset);
+ offset += mExifData.getCompressedThumbnail().length;
+ } else if (mExifData.hasUncompressedStrip()) {
+ int stripCount = mExifData.getStripCount();
+ long[] offsets = new long[stripCount];
+ for (int i = 0; i < mExifData.getStripCount(); i++) {
+ offsets[i] = offset;
+ offset += mExifData.getStrip(i).length;
+ }
+ ifd1.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS)).setValue(
+ offsets);
+ }
+ return offset;
+ }
+
+ static void writeTagValue(ExifTag tag, OrderedDataOutputStream dataOutputStream)
+ throws IOException {
+ switch (tag.getDataType()) {
+ case ExifTag.TYPE_ASCII:
+ byte buf[] = tag.getStringByte();
+ if (buf.length == tag.getComponentCount()) {
+ buf[buf.length - 1] = 0;
+ dataOutputStream.write(buf);
+ } else {
+ dataOutputStream.write(buf);
+ dataOutputStream.write(0);
+ }
+ break;
+ case ExifTag.TYPE_LONG:
+ case ExifTag.TYPE_UNSIGNED_LONG:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ dataOutputStream.writeInt((int) tag.getValueAt(i));
+ }
+ break;
+ case ExifTag.TYPE_RATIONAL:
+ case ExifTag.TYPE_UNSIGNED_RATIONAL:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ dataOutputStream.writeRational(tag.getRational(i));
+ }
+ break;
+ case ExifTag.TYPE_UNDEFINED:
+ case ExifTag.TYPE_UNSIGNED_BYTE:
+ buf = new byte[tag.getComponentCount()];
+ tag.getBytes(buf);
+ dataOutputStream.write(buf);
+ break;
+ case ExifTag.TYPE_UNSIGNED_SHORT:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ dataOutputStream.writeShort((short) tag.getValueAt(i));
+ }
+ break;
+ }
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifParser.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifParser.java
new file mode 100644
index 0000000..5467d42
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifParser.java
@@ -0,0 +1,916 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+/**
+ * This class provides a low-level EXIF parsing API. Given a JPEG format
+ * InputStream, the caller can request which IFD's to read via
+ * {@link #parse(InputStream, int)} with given options.
+ * <p>
+ * Below is an example of getting EXIF data from IFD 0 and EXIF IFD using the
+ * parser.
+ *
+ * <pre>
+ * void parse() {
+ * ExifParser parser = ExifParser.parse(mImageInputStream,
+ * ExifParser.OPTION_IFD_0 | ExifParser.OPTIONS_IFD_EXIF);
+ * int event = parser.next();
+ * while (event != ExifParser.EVENT_END) {
+ * switch (event) {
+ * case ExifParser.EVENT_START_OF_IFD:
+ * break;
+ * case ExifParser.EVENT_NEW_TAG:
+ * ExifTag tag = parser.getTag();
+ * if (!tag.hasValue()) {
+ * parser.registerForTagValue(tag);
+ * } else {
+ * processTag(tag);
+ * }
+ * break;
+ * case ExifParser.EVENT_VALUE_OF_REGISTERED_TAG:
+ * tag = parser.getTag();
+ * if (tag.getDataType() != ExifTag.TYPE_UNDEFINED) {
+ * processTag(tag);
+ * }
+ * break;
+ * }
+ * event = parser.next();
+ * }
+ * }
+ *
+ * void processTag(ExifTag tag) {
+ * // process the tag as you like.
+ * }
+ * </pre>
+ */
+class ExifParser {
+ private static final boolean LOGV = false;
+ private static final String TAG = "ExifParser";
+ /**
+ * When the parser reaches a new IFD area. Call {@link #getCurrentIfd()} to
+ * know which IFD we are in.
+ */
+ public static final int EVENT_START_OF_IFD = 0;
+ /**
+ * When the parser reaches a new tag. Call {@link #getTag()}to get the
+ * corresponding tag.
+ */
+ public static final int EVENT_NEW_TAG = 1;
+ /**
+ * When the parser reaches the value area of tag that is registered by
+ * {@link #registerForTagValue(ExifTag)} previously. Call {@link #getTag()}
+ * to get the corresponding tag.
+ */
+ public static final int EVENT_VALUE_OF_REGISTERED_TAG = 2;
+
+ /**
+ * When the parser reaches the compressed image area.
+ */
+ public static final int EVENT_COMPRESSED_IMAGE = 3;
+ /**
+ * When the parser reaches the uncompressed image strip. Call
+ * {@link #getStripIndex()} to get the index of the strip.
+ *
+ * @see #getStripIndex()
+ * @see #getStripCount()
+ */
+ public static final int EVENT_UNCOMPRESSED_STRIP = 4;
+ /**
+ * When there is nothing more to parse.
+ */
+ public static final int EVENT_END = 5;
+
+ /**
+ * Option bit to request to parse IFD0.
+ */
+ public static final int OPTION_IFD_0 = 1 << 0;
+ /**
+ * Option bit to request to parse IFD1.
+ */
+ public static final int OPTION_IFD_1 = 1 << 1;
+ /**
+ * Option bit to request to parse Exif-IFD.
+ */
+ public static final int OPTION_IFD_EXIF = 1 << 2;
+ /**
+ * Option bit to request to parse GPS-IFD.
+ */
+ public static final int OPTION_IFD_GPS = 1 << 3;
+ /**
+ * Option bit to request to parse Interoperability-IFD.
+ */
+ public static final int OPTION_IFD_INTEROPERABILITY = 1 << 4;
+ /**
+ * Option bit to request to parse thumbnail.
+ */
+ public static final int OPTION_THUMBNAIL = 1 << 5;
+
+ protected static final int EXIF_HEADER = 0x45786966; // EXIF header "Exif"
+ protected static final short EXIF_HEADER_TAIL = (short) 0x0000; // EXIF header in APP1
+
+ // TIFF header
+ protected static final short LITTLE_ENDIAN_TAG = (short) 0x4949; // "II"
+ protected static final short BIG_ENDIAN_TAG = (short) 0x4d4d; // "MM"
+ protected static final short TIFF_HEADER_TAIL = 0x002A;
+
+ protected static final int TAG_SIZE = 12;
+ protected static final int OFFSET_SIZE = 2;
+
+ private static final Charset US_ASCII = Charset.forName("US-ASCII");
+
+ protected static final int DEFAULT_IFD0_OFFSET = 8;
+
+ private final CountedDataInputStream mTiffStream;
+ private final int mOptions;
+ private int mIfdStartOffset = 0;
+ private int mNumOfTagInIfd = 0;
+ private int mIfdType;
+ private ExifTag mTag;
+ private ImageEvent mImageEvent;
+ private int mStripCount;
+ private ExifTag mStripSizeTag;
+ private ExifTag mJpegSizeTag;
+ private boolean mNeedToParseOffsetsInCurrentIfd;
+ private boolean mContainExifData = false;
+ private int mApp1End;
+ private int mOffsetToApp1EndFromSOF = 0;
+ private byte[] mDataAboveIfd0;
+ private int mIfd0Position;
+ private int mTiffStartPosition;
+ private final ExifInterface mInterface;
+
+ private static final short TAG_EXIF_IFD = ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_EXIF_IFD);
+ private static final short TAG_GPS_IFD = ExifInterface.getTrueTagKey(ExifInterface.TAG_GPS_IFD);
+ private static final short TAG_INTEROPERABILITY_IFD = ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_INTEROPERABILITY_IFD);
+ private static final short TAG_JPEG_INTERCHANGE_FORMAT = ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
+ private static final short TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
+ private static final short TAG_STRIP_OFFSETS = ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS);
+ private static final short TAG_STRIP_BYTE_COUNTS = ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS);
+
+ private final TreeMap<Integer, Object> mCorrespondingEvent = new TreeMap<Integer, Object>();
+
+ private boolean isIfdRequested(int ifdType) {
+ switch (ifdType) {
+ case IfdId.TYPE_IFD_0:
+ return (mOptions & OPTION_IFD_0) != 0;
+ case IfdId.TYPE_IFD_1:
+ return (mOptions & OPTION_IFD_1) != 0;
+ case IfdId.TYPE_IFD_EXIF:
+ return (mOptions & OPTION_IFD_EXIF) != 0;
+ case IfdId.TYPE_IFD_GPS:
+ return (mOptions & OPTION_IFD_GPS) != 0;
+ case IfdId.TYPE_IFD_INTEROPERABILITY:
+ return (mOptions & OPTION_IFD_INTEROPERABILITY) != 0;
+ }
+ return false;
+ }
+
+ private boolean isThumbnailRequested() {
+ return (mOptions & OPTION_THUMBNAIL) != 0;
+ }
+
+ private ExifParser(InputStream inputStream, int options, ExifInterface iRef)
+ throws IOException, ExifInvalidFormatException {
+ if (inputStream == null) {
+ throw new IOException("Null argument inputStream to ExifParser");
+ }
+ if (LOGV) {
+ Log.v(TAG, "Reading exif...");
+ }
+ mInterface = iRef;
+ mContainExifData = seekTiffData(inputStream);
+ mTiffStream = new CountedDataInputStream(inputStream);
+ mOptions = options;
+ if (!mContainExifData) {
+ return;
+ }
+
+ parseTiffHeader();
+ long offset = mTiffStream.readUnsignedInt();
+ if (offset > Integer.MAX_VALUE) {
+ throw new ExifInvalidFormatException("Invalid offset " + offset);
+ }
+ mIfd0Position = (int) offset;
+ mIfdType = IfdId.TYPE_IFD_0;
+ if (isIfdRequested(IfdId.TYPE_IFD_0) || needToParseOffsetsInCurrentIfd()) {
+ registerIfd(IfdId.TYPE_IFD_0, offset);
+ if (offset != DEFAULT_IFD0_OFFSET) {
+ mDataAboveIfd0 = new byte[(int) offset - DEFAULT_IFD0_OFFSET];
+ read(mDataAboveIfd0);
+ }
+ }
+ }
+
+ /**
+ * Parses the the given InputStream with the given options
+ *
+ * @exception IOException
+ * @exception ExifInvalidFormatException
+ */
+ protected static ExifParser parse(InputStream inputStream, int options, ExifInterface iRef)
+ throws IOException, ExifInvalidFormatException {
+ return new ExifParser(inputStream, options, iRef);
+ }
+
+ /**
+ * Parses the the given InputStream with default options; that is, every IFD
+ * and thumbnaill will be parsed.
+ *
+ * @exception IOException
+ * @exception ExifInvalidFormatException
+ * @see #parse(InputStream, int)
+ */
+ protected static ExifParser parse(InputStream inputStream, ExifInterface iRef)
+ throws IOException, ExifInvalidFormatException {
+ return new ExifParser(inputStream, OPTION_IFD_0 | OPTION_IFD_1
+ | OPTION_IFD_EXIF | OPTION_IFD_GPS | OPTION_IFD_INTEROPERABILITY
+ | OPTION_THUMBNAIL, iRef);
+ }
+
+ /**
+ * Moves the parser forward and returns the next parsing event
+ *
+ * @exception IOException
+ * @exception ExifInvalidFormatException
+ * @see #EVENT_START_OF_IFD
+ * @see #EVENT_NEW_TAG
+ * @see #EVENT_VALUE_OF_REGISTERED_TAG
+ * @see #EVENT_COMPRESSED_IMAGE
+ * @see #EVENT_UNCOMPRESSED_STRIP
+ * @see #EVENT_END
+ */
+ protected int next() throws IOException, ExifInvalidFormatException {
+ if (!mContainExifData) {
+ return EVENT_END;
+ }
+ int offset = mTiffStream.getReadByteCount();
+ int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
+ if (offset < endOfTags) {
+ mTag = readTag();
+ if (mTag == null) {
+ return next();
+ }
+ if (mNeedToParseOffsetsInCurrentIfd) {
+ checkOffsetOrImageTag(mTag);
+ }
+ return EVENT_NEW_TAG;
+ } else if (offset == endOfTags) {
+ // There is a link to ifd1 at the end of ifd0
+ if (mIfdType == IfdId.TYPE_IFD_0) {
+ long ifdOffset = readUnsignedLong();
+ if (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested()) {
+ if (ifdOffset != 0) {
+ registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
+ }
+ }
+ } else {
+ int offsetSize = 4;
+ // Some camera models use invalid length of the offset
+ if (mCorrespondingEvent.size() > 0) {
+ offsetSize = mCorrespondingEvent.firstEntry().getKey() -
+ mTiffStream.getReadByteCount();
+ }
+ if (offsetSize < 4) {
+ Log.w(TAG, "Invalid size of link to next IFD: " + offsetSize);
+ } else {
+ long ifdOffset = readUnsignedLong();
+ if (ifdOffset != 0) {
+ Log.w(TAG, "Invalid link to next IFD: " + ifdOffset);
+ }
+ }
+ }
+ }
+ while (mCorrespondingEvent.size() != 0) {
+ Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
+ Object event = entry.getValue();
+ try {
+ skipTo(entry.getKey());
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to skip to data at: " + entry.getKey() +
+ " for " + event.getClass().getName() + ", the file may be broken.");
+ continue;
+ }
+ if (event instanceof IfdEvent) {
+ mIfdType = ((IfdEvent) event).ifd;
+ mNumOfTagInIfd = mTiffStream.readUnsignedShort();
+ mIfdStartOffset = entry.getKey();
+
+ if (mNumOfTagInIfd * TAG_SIZE + mIfdStartOffset + OFFSET_SIZE > mApp1End) {
+ Log.w(TAG, "Invalid size of IFD " + mIfdType);
+ return EVENT_END;
+ }
+
+ mNeedToParseOffsetsInCurrentIfd = needToParseOffsetsInCurrentIfd();
+ if (((IfdEvent) event).isRequested) {
+ return EVENT_START_OF_IFD;
+ } else {
+ skipRemainingTagsInCurrentIfd();
+ }
+ } else if (event instanceof ImageEvent) {
+ mImageEvent = (ImageEvent) event;
+ return mImageEvent.type;
+ } else {
+ ExifTagEvent tagEvent = (ExifTagEvent) event;
+ mTag = tagEvent.tag;
+ if (mTag.getDataType() != ExifTag.TYPE_UNDEFINED) {
+ readFullTagValue(mTag);
+ checkOffsetOrImageTag(mTag);
+ }
+ if (tagEvent.isRequested) {
+ return EVENT_VALUE_OF_REGISTERED_TAG;
+ }
+ }
+ }
+ return EVENT_END;
+ }
+
+ /**
+ * Skips the tags area of current IFD, if the parser is not in the tag area,
+ * nothing will happen.
+ *
+ * @throws IOException
+ * @throws ExifInvalidFormatException
+ */
+ protected void skipRemainingTagsInCurrentIfd() throws IOException, ExifInvalidFormatException {
+ int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
+ int offset = mTiffStream.getReadByteCount();
+ if (offset > endOfTags) {
+ return;
+ }
+ if (mNeedToParseOffsetsInCurrentIfd) {
+ while (offset < endOfTags) {
+ mTag = readTag();
+ offset += TAG_SIZE;
+ if (mTag == null) {
+ continue;
+ }
+ checkOffsetOrImageTag(mTag);
+ }
+ } else {
+ skipTo(endOfTags);
+ }
+ long ifdOffset = readUnsignedLong();
+ // For ifd0, there is a link to ifd1 in the end of all tags
+ if (mIfdType == IfdId.TYPE_IFD_0
+ && (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested())) {
+ if (ifdOffset > 0) {
+ registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
+ }
+ }
+ }
+
+ private boolean needToParseOffsetsInCurrentIfd() {
+ switch (mIfdType) {
+ case IfdId.TYPE_IFD_0:
+ return isIfdRequested(IfdId.TYPE_IFD_EXIF) || isIfdRequested(IfdId.TYPE_IFD_GPS)
+ || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)
+ || isIfdRequested(IfdId.TYPE_IFD_1);
+ case IfdId.TYPE_IFD_1:
+ return isThumbnailRequested();
+ case IfdId.TYPE_IFD_EXIF:
+ // The offset to interoperability IFD is located in Exif IFD
+ return isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY);
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * If {@link #next()} return {@link #EVENT_NEW_TAG} or
+ * {@link #EVENT_VALUE_OF_REGISTERED_TAG}, call this function to get the
+ * corresponding tag.
+ * <p>
+ * For {@link #EVENT_NEW_TAG}, the tag may not contain the value if the size
+ * of the value is greater than 4 bytes. One should call
+ * {@link ExifTag#hasValue()} to check if the tag contains value. If there
+ * is no value,call {@link #registerForTagValue(ExifTag)} to have the parser
+ * emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
+ * pointed by the offset.
+ * <p>
+ * When {@link #EVENT_VALUE_OF_REGISTERED_TAG} is emitted, the value of the
+ * tag will have already been read except for tags of undefined type. For
+ * tags of undefined type, call one of the read methods to get the value.
+ *
+ * @see #registerForTagValue(ExifTag)
+ * @see #read(byte[])
+ * @see #read(byte[], int, int)
+ * @see #readLong()
+ * @see #readRational()
+ * @see #readString(int)
+ * @see #readString(int, Charset)
+ */
+ protected ExifTag getTag() {
+ return mTag;
+ }
+
+ /**
+ * Gets number of tags in the current IFD area.
+ */
+ protected int getTagCountInCurrentIfd() {
+ return mNumOfTagInIfd;
+ }
+
+ /**
+ * Gets the ID of current IFD.
+ *
+ * @see IfdId#TYPE_IFD_0
+ * @see IfdId#TYPE_IFD_1
+ * @see IfdId#TYPE_IFD_GPS
+ * @see IfdId#TYPE_IFD_INTEROPERABILITY
+ * @see IfdId#TYPE_IFD_EXIF
+ */
+ protected int getCurrentIfd() {
+ return mIfdType;
+ }
+
+ /**
+ * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
+ * get the index of this strip.
+ *
+ * @see #getStripCount()
+ */
+ protected int getStripIndex() {
+ return mImageEvent.stripIndex;
+ }
+
+ /**
+ * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
+ * get the number of strip data.
+ *
+ * @see #getStripIndex()
+ */
+ protected int getStripCount() {
+ return mStripCount;
+ }
+
+ /**
+ * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
+ * get the strip size.
+ */
+ protected int getStripSize() {
+ if (mStripSizeTag == null)
+ return 0;
+ return (int) mStripSizeTag.getValueAt(0);
+ }
+
+ /**
+ * When receiving {@link #EVENT_COMPRESSED_IMAGE}, call this function to get
+ * the image data size.
+ */
+ protected int getCompressedImageSize() {
+ if (mJpegSizeTag == null) {
+ return 0;
+ }
+ return (int) mJpegSizeTag.getValueAt(0);
+ }
+
+ private void skipTo(int offset) throws IOException {
+ mTiffStream.skipTo(offset);
+ while (!mCorrespondingEvent.isEmpty() && mCorrespondingEvent.firstKey() < offset) {
+ mCorrespondingEvent.pollFirstEntry();
+ }
+ }
+
+ /**
+ * When getting {@link #EVENT_NEW_TAG} in the tag area of IFD, the tag may
+ * not contain the value if the size of the value is greater than 4 bytes.
+ * When the value is not available here, call this method so that the parser
+ * will emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
+ * where the value is located.
+ *
+ * @see #EVENT_VALUE_OF_REGISTERED_TAG
+ */
+ protected void registerForTagValue(ExifTag tag) {
+ if (tag.getOffset() >= mTiffStream.getReadByteCount()) {
+ mCorrespondingEvent.put(tag.getOffset(), new ExifTagEvent(tag, true));
+ }
+ }
+
+ private void registerIfd(int ifdType, long offset) {
+ // Cast unsigned int to int since the offset is always smaller
+ // than the size of APP1 (65536)
+ mCorrespondingEvent.put((int) offset, new IfdEvent(ifdType, isIfdRequested(ifdType)));
+ }
+
+ private void registerCompressedImage(long offset) {
+ mCorrespondingEvent.put((int) offset, new ImageEvent(EVENT_COMPRESSED_IMAGE));
+ }
+
+ private void registerUncompressedStrip(int stripIndex, long offset) {
+ mCorrespondingEvent.put((int) offset, new ImageEvent(EVENT_UNCOMPRESSED_STRIP
+ , stripIndex));
+ }
+
+ private ExifTag readTag() throws IOException, ExifInvalidFormatException {
+ short tagId = mTiffStream.readShort();
+ short dataFormat = mTiffStream.readShort();
+ long numOfComp = mTiffStream.readUnsignedInt();
+ if (numOfComp > Integer.MAX_VALUE) {
+ throw new ExifInvalidFormatException(
+ "Number of component is larger then Integer.MAX_VALUE");
+ }
+ // Some invalid image file contains invalid data type. Ignore those tags
+ if (!ExifTag.isValidType(dataFormat)) {
+ Log.w(TAG, String.format("Tag %04x: Invalid data type %d", tagId, dataFormat));
+ mTiffStream.skip(4);
+ return null;
+ }
+ // TODO: handle numOfComp overflow
+ ExifTag tag = new ExifTag(tagId, dataFormat, (int) numOfComp, mIfdType,
+ ((int) numOfComp) != ExifTag.SIZE_UNDEFINED);
+ int dataSize = tag.getDataSize();
+ if (dataSize > 4) {
+ long offset = mTiffStream.readUnsignedInt();
+ if (offset > Integer.MAX_VALUE) {
+ throw new ExifInvalidFormatException(
+ "offset is larger then Integer.MAX_VALUE");
+ }
+ // Some invalid images put some undefined data before IFD0.
+ // Read the data here.
+ if ((offset < mIfd0Position) && (dataFormat == ExifTag.TYPE_UNDEFINED)) {
+ byte[] buf = new byte[(int) numOfComp];
+ System.arraycopy(mDataAboveIfd0, (int) offset - DEFAULT_IFD0_OFFSET,
+ buf, 0, (int) numOfComp);
+ tag.setValue(buf);
+ } else {
+ tag.setOffset((int) offset);
+ }
+ } else {
+ boolean defCount = tag.hasDefinedCount();
+ // Set defined count to 0 so we can add \0 to non-terminated strings
+ tag.setHasDefinedCount(false);
+ // Read value
+ readFullTagValue(tag);
+ tag.setHasDefinedCount(defCount);
+ mTiffStream.skip(4 - dataSize);
+ // Set the offset to the position of value.
+ tag.setOffset(mTiffStream.getReadByteCount() - 4);
+ }
+ return tag;
+ }
+
+ /**
+ * Check the tag, if the tag is one of the offset tag that points to the IFD
+ * or image the caller is interested in, register the IFD or image.
+ */
+ private void checkOffsetOrImageTag(ExifTag tag) {
+ // Some invalid formattd image contains tag with 0 size.
+ if (tag.getComponentCount() == 0) {
+ return;
+ }
+ short tid = tag.getTagId();
+ int ifd = tag.getIfd();
+ if (tid == TAG_EXIF_IFD && checkAllowed(ifd, ExifInterface.TAG_EXIF_IFD)) {
+ if (isIfdRequested(IfdId.TYPE_IFD_EXIF)
+ || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
+ registerIfd(IfdId.TYPE_IFD_EXIF, tag.getValueAt(0));
+ }
+ } else if (tid == TAG_GPS_IFD && checkAllowed(ifd, ExifInterface.TAG_GPS_IFD)) {
+ if (isIfdRequested(IfdId.TYPE_IFD_GPS)) {
+ registerIfd(IfdId.TYPE_IFD_GPS, tag.getValueAt(0));
+ }
+ } else if (tid == TAG_INTEROPERABILITY_IFD
+ && checkAllowed(ifd, ExifInterface.TAG_INTEROPERABILITY_IFD)) {
+ if (isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
+ registerIfd(IfdId.TYPE_IFD_INTEROPERABILITY, tag.getValueAt(0));
+ }
+ } else if (tid == TAG_JPEG_INTERCHANGE_FORMAT
+ && checkAllowed(ifd, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT)) {
+ if (isThumbnailRequested()) {
+ registerCompressedImage(tag.getValueAt(0));
+ }
+ } else if (tid == TAG_JPEG_INTERCHANGE_FORMAT_LENGTH
+ && checkAllowed(ifd, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH)) {
+ if (isThumbnailRequested()) {
+ mJpegSizeTag = tag;
+ }
+ } else if (tid == TAG_STRIP_OFFSETS && checkAllowed(ifd, ExifInterface.TAG_STRIP_OFFSETS)) {
+ if (isThumbnailRequested()) {
+ if (tag.hasValue()) {
+ for (int i = 0; i < tag.getComponentCount(); i++) {
+ if (tag.getDataType() == ExifTag.TYPE_UNSIGNED_SHORT) {
+ registerUncompressedStrip(i, tag.getValueAt(i));
+ } else {
+ registerUncompressedStrip(i, tag.getValueAt(i));
+ }
+ }
+ } else {
+ mCorrespondingEvent.put(tag.getOffset(), new ExifTagEvent(tag, false));
+ }
+ }
+ } else if (tid == TAG_STRIP_BYTE_COUNTS
+ && checkAllowed(ifd, ExifInterface.TAG_STRIP_BYTE_COUNTS)
+ &&isThumbnailRequested() && tag.hasValue()) {
+ mStripSizeTag = tag;
+ }
+ }
+
+ private boolean checkAllowed(int ifd, int tagId) {
+ int info = mInterface.getTagInfo().get(tagId);
+ if (info == ExifInterface.DEFINITION_NULL) {
+ return false;
+ }
+ return ExifInterface.isIfdAllowed(info, ifd);
+ }
+
+ protected void readFullTagValue(ExifTag tag) throws IOException {
+ // Some invalid images contains tags with wrong size, check it here
+ short type = tag.getDataType();
+ if (type == ExifTag.TYPE_ASCII || type == ExifTag.TYPE_UNDEFINED ||
+ type == ExifTag.TYPE_UNSIGNED_BYTE) {
+ int size = tag.getComponentCount();
+ if (mCorrespondingEvent.size() > 0) {
+ if (mCorrespondingEvent.firstEntry().getKey() < mTiffStream.getReadByteCount()
+ + size) {
+ Object event = mCorrespondingEvent.firstEntry().getValue();
+ if (event instanceof ImageEvent) {
+ // Tag value overlaps thumbnail, ignore thumbnail.
+ Log.w(TAG, "Thumbnail overlaps value for tag: \n" + tag.toString());
+ Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
+ Log.w(TAG, "Invalid thumbnail offset: " + entry.getKey());
+ } else {
+ // Tag value overlaps another tag, shorten count
+ if (event instanceof IfdEvent) {
+ Log.w(TAG, "Ifd " + ((IfdEvent) event).ifd
+ + " overlaps value for tag: \n" + tag.toString());
+ } else if (event instanceof ExifTagEvent) {
+ Log.w(TAG, "Tag value for tag: \n"
+ + ((ExifTagEvent) event).tag.toString()
+ + " overlaps value for tag: \n" + tag.toString());
+ }
+ size = mCorrespondingEvent.firstEntry().getKey()
+ - mTiffStream.getReadByteCount();
+ Log.w(TAG, "Invalid size of tag: \n" + tag.toString()
+ + " setting count to: " + size);
+ tag.forceSetComponentCount(size);
+ }
+ }
+ }
+ }
+ switch (tag.getDataType()) {
+ case ExifTag.TYPE_UNSIGNED_BYTE:
+ case ExifTag.TYPE_UNDEFINED: {
+ byte buf[] = new byte[tag.getComponentCount()];
+ read(buf);
+ tag.setValue(buf);
+ }
+ break;
+ case ExifTag.TYPE_ASCII:
+ tag.setValue(readString(tag.getComponentCount()));
+ break;
+ case ExifTag.TYPE_UNSIGNED_LONG: {
+ long value[] = new long[tag.getComponentCount()];
+ for (int i = 0, n = value.length; i < n; i++) {
+ value[i] = readUnsignedLong();
+ }
+ tag.setValue(value);
+ }
+ break;
+ case ExifTag.TYPE_UNSIGNED_RATIONAL: {
+ Rational value[] = new Rational[tag.getComponentCount()];
+ for (int i = 0, n = value.length; i < n; i++) {
+ value[i] = readUnsignedRational();
+ }
+ tag.setValue(value);
+ }
+ break;
+ case ExifTag.TYPE_UNSIGNED_SHORT: {
+ int value[] = new int[tag.getComponentCount()];
+ for (int i = 0, n = value.length; i < n; i++) {
+ value[i] = readUnsignedShort();
+ }
+ tag.setValue(value);
+ }
+ break;
+ case ExifTag.TYPE_LONG: {
+ int value[] = new int[tag.getComponentCount()];
+ for (int i = 0, n = value.length; i < n; i++) {
+ value[i] = readLong();
+ }
+ tag.setValue(value);
+ }
+ break;
+ case ExifTag.TYPE_RATIONAL: {
+ Rational value[] = new Rational[tag.getComponentCount()];
+ for (int i = 0, n = value.length; i < n; i++) {
+ value[i] = readRational();
+ }
+ tag.setValue(value);
+ }
+ break;
+ }
+ if (LOGV) {
+ Log.v(TAG, "\n" + tag.toString());
+ }
+ }
+
+ private void parseTiffHeader() throws IOException,
+ ExifInvalidFormatException {
+ short byteOrder = mTiffStream.readShort();
+ if (LITTLE_ENDIAN_TAG == byteOrder) {
+ mTiffStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
+ } else if (BIG_ENDIAN_TAG == byteOrder) {
+ mTiffStream.setByteOrder(ByteOrder.BIG_ENDIAN);
+ } else {
+ throw new ExifInvalidFormatException("Invalid TIFF header");
+ }
+
+ if (mTiffStream.readShort() != TIFF_HEADER_TAIL) {
+ throw new ExifInvalidFormatException("Invalid TIFF header");
+ }
+ }
+
+ private boolean seekTiffData(InputStream inputStream) throws IOException,
+ ExifInvalidFormatException {
+ CountedDataInputStream dataStream = new CountedDataInputStream(inputStream);
+ if (dataStream.readShort() != JpegHeader.SOI) {
+ throw new ExifInvalidFormatException("Invalid JPEG format");
+ }
+
+ short marker = dataStream.readShort();
+ while (marker != JpegHeader.EOI
+ && !JpegHeader.isSofMarker(marker)) {
+ int length = dataStream.readUnsignedShort();
+ // Some invalid formatted image contains multiple APP1,
+ // try to find the one with Exif data.
+ if (marker == JpegHeader.APP1) {
+ int header = 0;
+ short headerTail = 0;
+ if (length >= 8) {
+ header = dataStream.readInt();
+ headerTail = dataStream.readShort();
+ length -= 6;
+ if (header == EXIF_HEADER && headerTail == EXIF_HEADER_TAIL) {
+ mTiffStartPosition = dataStream.getReadByteCount();
+ mApp1End = length;
+ mOffsetToApp1EndFromSOF = mTiffStartPosition + mApp1End;
+ return true;
+ }
+ }
+ }
+ if (length < 2 || (length - 2) != dataStream.skip(length - 2)) {
+ Log.w(TAG, "Invalid JPEG format.");
+ return false;
+ }
+ marker = dataStream.readShort();
+ }
+ return false;
+ }
+
+ protected int getOffsetToExifEndFromSOF() {
+ return mOffsetToApp1EndFromSOF;
+ }
+
+ protected int getTiffStartPosition() {
+ return mTiffStartPosition;
+ }
+
+ /**
+ * Reads bytes from the InputStream.
+ */
+ protected int read(byte[] buffer, int offset, int length) throws IOException {
+ return mTiffStream.read(buffer, offset, length);
+ }
+
+ /**
+ * Equivalent to read(buffer, 0, buffer.length).
+ */
+ protected int read(byte[] buffer) throws IOException {
+ return mTiffStream.read(buffer);
+ }
+
+ /**
+ * Reads a String from the InputStream with US-ASCII charset. The parser
+ * will read n bytes and convert it to ascii string. This is used for
+ * reading values of type {@link ExifTag#TYPE_ASCII}.
+ */
+ protected String readString(int n) throws IOException {
+ return readString(n, US_ASCII);
+ }
+
+ /**
+ * Reads a String from the InputStream with the given charset. The parser
+ * will read n bytes and convert it to string. This is used for reading
+ * values of type {@link ExifTag#TYPE_ASCII}.
+ */
+ protected String readString(int n, Charset charset) throws IOException {
+ if (n > 0) {
+ return mTiffStream.readString(n, charset);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Reads value of type {@link ExifTag#TYPE_UNSIGNED_SHORT} from the
+ * InputStream.
+ */
+ protected int readUnsignedShort() throws IOException {
+ return mTiffStream.readShort() & 0xffff;
+ }
+
+ /**
+ * Reads value of type {@link ExifTag#TYPE_UNSIGNED_LONG} from the
+ * InputStream.
+ */
+ protected long readUnsignedLong() throws IOException {
+ return readLong() & 0xffffffffL;
+ }
+
+ /**
+ * Reads value of type {@link ExifTag#TYPE_UNSIGNED_RATIONAL} from the
+ * InputStream.
+ */
+ protected Rational readUnsignedRational() throws IOException {
+ long nomi = readUnsignedLong();
+ long denomi = readUnsignedLong();
+ return new Rational(nomi, denomi);
+ }
+
+ /**
+ * Reads value of type {@link ExifTag#TYPE_LONG} from the InputStream.
+ */
+ protected int readLong() throws IOException {
+ return mTiffStream.readInt();
+ }
+
+ /**
+ * Reads value of type {@link ExifTag#TYPE_RATIONAL} from the InputStream.
+ */
+ protected Rational readRational() throws IOException {
+ int nomi = readLong();
+ int denomi = readLong();
+ return new Rational(nomi, denomi);
+ }
+
+ private static class ImageEvent {
+ int stripIndex;
+ int type;
+
+ ImageEvent(int type) {
+ this.stripIndex = 0;
+ this.type = type;
+ }
+
+ ImageEvent(int type, int stripIndex) {
+ this.type = type;
+ this.stripIndex = stripIndex;
+ }
+ }
+
+ private static class IfdEvent {
+ int ifd;
+ boolean isRequested;
+
+ IfdEvent(int ifd, boolean isInterestedIfd) {
+ this.ifd = ifd;
+ this.isRequested = isInterestedIfd;
+ }
+ }
+
+ private static class ExifTagEvent {
+ ExifTag tag;
+ boolean isRequested;
+
+ ExifTagEvent(ExifTag tag, boolean isRequireByUser) {
+ this.tag = tag;
+ this.isRequested = isRequireByUser;
+ }
+ }
+
+ /**
+ * Gets the byte order of the current InputStream.
+ */
+ protected ByteOrder getByteOrder() {
+ return mTiffStream.getByteOrder();
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifReader.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifReader.java
new file mode 100644
index 0000000..68e972f
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifReader.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This class reads the EXIF header of a JPEG file and stores it in
+ * {@link ExifData}.
+ */
+class ExifReader {
+ private static final String TAG = "ExifReader";
+
+ private final ExifInterface mInterface;
+
+ ExifReader(ExifInterface iRef) {
+ mInterface = iRef;
+ }
+
+ /**
+ * Parses the inputStream and and returns the EXIF data in an
+ * {@link ExifData}.
+ *
+ * @throws ExifInvalidFormatException
+ * @throws IOException
+ */
+ protected ExifData read(InputStream inputStream) throws ExifInvalidFormatException,
+ IOException {
+ ExifParser parser = ExifParser.parse(inputStream, mInterface);
+ ExifData exifData = new ExifData(parser.getByteOrder());
+ ExifTag tag = null;
+
+ int event = parser.next();
+ while (event != ExifParser.EVENT_END) {
+ switch (event) {
+ case ExifParser.EVENT_START_OF_IFD:
+ exifData.addIfdData(new IfdData(parser.getCurrentIfd()));
+ break;
+ case ExifParser.EVENT_NEW_TAG:
+ tag = parser.getTag();
+ if (!tag.hasValue()) {
+ parser.registerForTagValue(tag);
+ } else {
+ exifData.getIfdData(tag.getIfd()).setTag(tag);
+ }
+ break;
+ case ExifParser.EVENT_VALUE_OF_REGISTERED_TAG:
+ tag = parser.getTag();
+ if (tag.getDataType() == ExifTag.TYPE_UNDEFINED) {
+ parser.readFullTagValue(tag);
+ }
+ exifData.getIfdData(tag.getIfd()).setTag(tag);
+ break;
+ case ExifParser.EVENT_COMPRESSED_IMAGE:
+ byte buf[] = new byte[parser.getCompressedImageSize()];
+ if (buf.length == parser.read(buf)) {
+ exifData.setCompressedThumbnail(buf);
+ } else {
+ Log.w(TAG, "Failed to read the compressed thumbnail");
+ }
+ break;
+ case ExifParser.EVENT_UNCOMPRESSED_STRIP:
+ buf = new byte[parser.getStripSize()];
+ if (buf.length == parser.read(buf)) {
+ exifData.setStripBytes(parser.getStripIndex(), buf);
+ } else {
+ Log.w(TAG, "Failed to read the strip bytes");
+ }
+ break;
+ }
+ event = parser.next();
+ }
+ return exifData;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifTag.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifTag.java
new file mode 100644
index 0000000..b8b3872
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifTag.java
@@ -0,0 +1,1008 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import java.nio.charset.Charset;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+
+/**
+ * This class stores information of an EXIF tag. For more information about
+ * defined EXIF tags, please read the Jeita EXIF 2.2 standard. Tags should be
+ * instantiated using {@link ExifInterface#buildTag}.
+ *
+ * @see ExifInterface
+ */
+public class ExifTag {
+ /**
+ * The BYTE type in the EXIF standard. An 8-bit unsigned integer.
+ */
+ public static final short TYPE_UNSIGNED_BYTE = 1;
+ /**
+ * The ASCII type in the EXIF standard. An 8-bit byte containing one 7-bit
+ * ASCII code. The final byte is terminated with NULL.
+ */
+ public static final short TYPE_ASCII = 2;
+ /**
+ * The SHORT type in the EXIF standard. A 16-bit (2-byte) unsigned integer
+ */
+ public static final short TYPE_UNSIGNED_SHORT = 3;
+ /**
+ * The LONG type in the EXIF standard. A 32-bit (4-byte) unsigned integer
+ */
+ public static final short TYPE_UNSIGNED_LONG = 4;
+ /**
+ * The RATIONAL type of EXIF standard. It consists of two LONGs. The first
+ * one is the numerator and the second one expresses the denominator.
+ */
+ public static final short TYPE_UNSIGNED_RATIONAL = 5;
+ /**
+ * The UNDEFINED type in the EXIF standard. An 8-bit byte that can take any
+ * value depending on the field definition.
+ */
+ public static final short TYPE_UNDEFINED = 7;
+ /**
+ * The SLONG type in the EXIF standard. A 32-bit (4-byte) signed integer
+ * (2's complement notation).
+ */
+ public static final short TYPE_LONG = 9;
+ /**
+ * The SRATIONAL type of EXIF standard. It consists of two SLONGs. The first
+ * one is the numerator and the second one is the denominator.
+ */
+ public static final short TYPE_RATIONAL = 10;
+
+ private static Charset US_ASCII = Charset.forName("US-ASCII");
+ private static final int TYPE_TO_SIZE_MAP[] = new int[11];
+ private static final int UNSIGNED_SHORT_MAX = 65535;
+ private static final long UNSIGNED_LONG_MAX = 4294967295L;
+ private static final long LONG_MAX = Integer.MAX_VALUE;
+ private static final long LONG_MIN = Integer.MIN_VALUE;
+
+ static {
+ TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_BYTE] = 1;
+ TYPE_TO_SIZE_MAP[TYPE_ASCII] = 1;
+ TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_SHORT] = 2;
+ TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_LONG] = 4;
+ TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_RATIONAL] = 8;
+ TYPE_TO_SIZE_MAP[TYPE_UNDEFINED] = 1;
+ TYPE_TO_SIZE_MAP[TYPE_LONG] = 4;
+ TYPE_TO_SIZE_MAP[TYPE_RATIONAL] = 8;
+ }
+
+ static final int SIZE_UNDEFINED = 0;
+
+ // Exif TagId
+ private final short mTagId;
+ // Exif Tag Type
+ private final short mDataType;
+ // If tag has defined count
+ private boolean mHasDefinedDefaultComponentCount;
+ // Actual data count in tag (should be number of elements in value array)
+ private int mComponentCountActual;
+ // The ifd that this tag should be put in
+ private int mIfd;
+ // The value (array of elements of type Tag Type)
+ private Object mValue;
+ // Value offset in exif header.
+ private int mOffset;
+
+ private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("yyyy:MM:dd kk:mm:ss");
+
+ /**
+ * Returns true if the given IFD is a valid IFD.
+ */
+ public static boolean isValidIfd(int ifdId) {
+ return ifdId == IfdId.TYPE_IFD_0 || ifdId == IfdId.TYPE_IFD_1
+ || ifdId == IfdId.TYPE_IFD_EXIF || ifdId == IfdId.TYPE_IFD_INTEROPERABILITY
+ || ifdId == IfdId.TYPE_IFD_GPS;
+ }
+
+ /**
+ * Returns true if a given type is a valid tag type.
+ */
+ public static boolean isValidType(short type) {
+ return type == TYPE_UNSIGNED_BYTE || type == TYPE_ASCII ||
+ type == TYPE_UNSIGNED_SHORT || type == TYPE_UNSIGNED_LONG ||
+ type == TYPE_UNSIGNED_RATIONAL || type == TYPE_UNDEFINED ||
+ type == TYPE_LONG || type == TYPE_RATIONAL;
+ }
+
+ // Use builtTag in ExifInterface instead of constructor.
+ ExifTag(short tagId, short type, int componentCount, int ifd,
+ boolean hasDefinedComponentCount) {
+ mTagId = tagId;
+ mDataType = type;
+ mComponentCountActual = componentCount;
+ mHasDefinedDefaultComponentCount = hasDefinedComponentCount;
+ mIfd = ifd;
+ mValue = null;
+ }
+
+ /**
+ * Gets the element size of the given data type in bytes.
+ *
+ * @see #TYPE_ASCII
+ * @see #TYPE_LONG
+ * @see #TYPE_RATIONAL
+ * @see #TYPE_UNDEFINED
+ * @see #TYPE_UNSIGNED_BYTE
+ * @see #TYPE_UNSIGNED_LONG
+ * @see #TYPE_UNSIGNED_RATIONAL
+ * @see #TYPE_UNSIGNED_SHORT
+ */
+ public static int getElementSize(short type) {
+ return TYPE_TO_SIZE_MAP[type];
+ }
+
+ /**
+ * Returns the ID of the IFD this tag belongs to.
+ *
+ * @see IfdId#TYPE_IFD_0
+ * @see IfdId#TYPE_IFD_1
+ * @see IfdId#TYPE_IFD_EXIF
+ * @see IfdId#TYPE_IFD_GPS
+ * @see IfdId#TYPE_IFD_INTEROPERABILITY
+ */
+ public int getIfd() {
+ return mIfd;
+ }
+
+ protected void setIfd(int ifdId) {
+ mIfd = ifdId;
+ }
+
+ /**
+ * Gets the TID of this tag.
+ */
+ public short getTagId() {
+ return mTagId;
+ }
+
+ /**
+ * Gets the data type of this tag
+ *
+ * @see #TYPE_ASCII
+ * @see #TYPE_LONG
+ * @see #TYPE_RATIONAL
+ * @see #TYPE_UNDEFINED
+ * @see #TYPE_UNSIGNED_BYTE
+ * @see #TYPE_UNSIGNED_LONG
+ * @see #TYPE_UNSIGNED_RATIONAL
+ * @see #TYPE_UNSIGNED_SHORT
+ */
+ public short getDataType() {
+ return mDataType;
+ }
+
+ /**
+ * Gets the total data size in bytes of the value of this tag.
+ */
+ public int getDataSize() {
+ return getComponentCount() * getElementSize(getDataType());
+ }
+
+ /**
+ * Gets the component count of this tag.
+ */
+
+ // TODO: fix integer overflows with this
+ public int getComponentCount() {
+ return mComponentCountActual;
+ }
+
+ /**
+ * Sets the component count of this tag. Call this function before
+ * setValue() if the length of value does not match the component count.
+ */
+ protected void forceSetComponentCount(int count) {
+ mComponentCountActual = count;
+ }
+
+ /**
+ * Returns true if this ExifTag contains value; otherwise, this tag will
+ * contain an offset value that is determined when the tag is written.
+ */
+ public boolean hasValue() {
+ return mValue != null;
+ }
+
+ /**
+ * Sets integer values into this tag. This method should be used for tags of
+ * type {@link #TYPE_UNSIGNED_SHORT}. This method will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_SHORT},
+ * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_LONG}.</li>
+ * <li>The value overflows.</li>
+ * <li>The value.length does NOT match the component count in the definition
+ * for this tag.</li>
+ * </ul>
+ */
+ public boolean setValue(int[] value) {
+ if (checkBadComponentCount(value.length)) {
+ return false;
+ }
+ if (mDataType != TYPE_UNSIGNED_SHORT && mDataType != TYPE_LONG &&
+ mDataType != TYPE_UNSIGNED_LONG) {
+ return false;
+ }
+ if (mDataType == TYPE_UNSIGNED_SHORT && checkOverflowForUnsignedShort(value)) {
+ return false;
+ } else if (mDataType == TYPE_UNSIGNED_LONG && checkOverflowForUnsignedLong(value)) {
+ return false;
+ }
+
+ long[] data = new long[value.length];
+ for (int i = 0; i < value.length; i++) {
+ data[i] = value[i];
+ }
+ mValue = data;
+ mComponentCountActual = value.length;
+ return true;
+ }
+
+ /**
+ * Sets integer value into this tag. This method should be used for tags of
+ * type {@link #TYPE_UNSIGNED_SHORT}, or {@link #TYPE_LONG}. This method
+ * will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_SHORT},
+ * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_LONG}.</li>
+ * <li>The value overflows.</li>
+ * <li>The component count in the definition of this tag is not 1.</li>
+ * </ul>
+ */
+ public boolean setValue(int value) {
+ return setValue(new int[] {
+ value
+ });
+ }
+
+ /**
+ * Sets long values into this tag. This method should be used for tags of
+ * type {@link #TYPE_UNSIGNED_LONG}. This method will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_LONG}.</li>
+ * <li>The value overflows.</li>
+ * <li>The value.length does NOT match the component count in the definition
+ * for this tag.</li>
+ * </ul>
+ */
+ public boolean setValue(long[] value) {
+ if (checkBadComponentCount(value.length) || mDataType != TYPE_UNSIGNED_LONG) {
+ return false;
+ }
+ if (checkOverflowForUnsignedLong(value)) {
+ return false;
+ }
+ mValue = value;
+ mComponentCountActual = value.length;
+ return true;
+ }
+
+ /**
+ * Sets long values into this tag. This method should be used for tags of
+ * type {@link #TYPE_UNSIGNED_LONG}. This method will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_LONG}.</li>
+ * <li>The value overflows.</li>
+ * <li>The component count in the definition for this tag is not 1.</li>
+ * </ul>
+ */
+ public boolean setValue(long value) {
+ return setValue(new long[] {
+ value
+ });
+ }
+
+ /**
+ * Sets a string value into this tag. This method should be used for tags of
+ * type {@link #TYPE_ASCII}. The string is converted to an ASCII string.
+ * Characters that cannot be converted are replaced with '?'. The length of
+ * the string must be equal to either (component count -1) or (component
+ * count). The final byte will be set to the string null terminator '\0',
+ * overwriting the last character in the string if the value.length is equal
+ * to the component count. This method will fail if:
+ * <ul>
+ * <li>The data type is not {@link #TYPE_ASCII} or {@link #TYPE_UNDEFINED}.</li>
+ * <li>The length of the string is not equal to (component count -1) or
+ * (component count) in the definition for this tag.</li>
+ * </ul>
+ */
+ public boolean setValue(String value) {
+ if (mDataType != TYPE_ASCII && mDataType != TYPE_UNDEFINED) {
+ return false;
+ }
+
+ byte[] buf = value.getBytes(US_ASCII);
+ byte[] finalBuf = buf;
+ if (buf.length > 0) {
+ finalBuf = (buf[buf.length - 1] == 0 || mDataType == TYPE_UNDEFINED) ? buf : Arrays
+ .copyOf(buf, buf.length + 1);
+ } else if (mDataType == TYPE_ASCII && mComponentCountActual == 1) {
+ finalBuf = new byte[] { 0 };
+ }
+ int count = finalBuf.length;
+ if (checkBadComponentCount(count)) {
+ return false;
+ }
+ mComponentCountActual = count;
+ mValue = finalBuf;
+ return true;
+ }
+
+ /**
+ * Sets Rational values into this tag. This method should be used for tags
+ * of type {@link #TYPE_UNSIGNED_RATIONAL}, or {@link #TYPE_RATIONAL}. This
+ * method will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_RATIONAL}
+ * or {@link #TYPE_RATIONAL}.</li>
+ * <li>The value overflows.</li>
+ * <li>The value.length does NOT match the component count in the definition
+ * for this tag.</li>
+ * </ul>
+ *
+ * @see Rational
+ */
+ public boolean setValue(Rational[] value) {
+ if (checkBadComponentCount(value.length)) {
+ return false;
+ }
+ if (mDataType != TYPE_UNSIGNED_RATIONAL && mDataType != TYPE_RATIONAL) {
+ return false;
+ }
+ if (mDataType == TYPE_UNSIGNED_RATIONAL && checkOverflowForUnsignedRational(value)) {
+ return false;
+ } else if (mDataType == TYPE_RATIONAL && checkOverflowForRational(value)) {
+ return false;
+ }
+
+ mValue = value;
+ mComponentCountActual = value.length;
+ return true;
+ }
+
+ /**
+ * Sets a Rational value into this tag. This method should be used for tags
+ * of type {@link #TYPE_UNSIGNED_RATIONAL}, or {@link #TYPE_RATIONAL}. This
+ * method will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_RATIONAL}
+ * or {@link #TYPE_RATIONAL}.</li>
+ * <li>The value overflows.</li>
+ * <li>The component count in the definition for this tag is not 1.</li>
+ * </ul>
+ *
+ * @see Rational
+ */
+ public boolean setValue(Rational value) {
+ return setValue(new Rational[] {
+ value
+ });
+ }
+
+ /**
+ * Sets byte values into this tag. This method should be used for tags of
+ * type {@link #TYPE_UNSIGNED_BYTE} or {@link #TYPE_UNDEFINED}. This method
+ * will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_BYTE} or
+ * {@link #TYPE_UNDEFINED} .</li>
+ * <li>The length does NOT match the component count in the definition for
+ * this tag.</li>
+ * </ul>
+ */
+ public boolean setValue(byte[] value, int offset, int length) {
+ if (checkBadComponentCount(length)) {
+ return false;
+ }
+ if (mDataType != TYPE_UNSIGNED_BYTE && mDataType != TYPE_UNDEFINED) {
+ return false;
+ }
+ mValue = new byte[length];
+ System.arraycopy(value, offset, mValue, 0, length);
+ mComponentCountActual = length;
+ return true;
+ }
+
+ /**
+ * Equivalent to setValue(value, 0, value.length).
+ */
+ public boolean setValue(byte[] value) {
+ return setValue(value, 0, value.length);
+ }
+
+ /**
+ * Sets byte value into this tag. This method should be used for tags of
+ * type {@link #TYPE_UNSIGNED_BYTE} or {@link #TYPE_UNDEFINED}. This method
+ * will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_BYTE} or
+ * {@link #TYPE_UNDEFINED} .</li>
+ * <li>The component count in the definition for this tag is not 1.</li>
+ * </ul>
+ */
+ public boolean setValue(byte value) {
+ return setValue(new byte[] {
+ value
+ });
+ }
+
+ /**
+ * Sets the value for this tag using an appropriate setValue method for the
+ * given object. This method will fail if:
+ * <ul>
+ * <li>The corresponding setValue method for the class of the object passed
+ * in would fail.</li>
+ * <li>There is no obvious way to cast the object passed in into an EXIF tag
+ * type.</li>
+ * </ul>
+ */
+ public boolean setValue(Object obj) {
+ if (obj == null) {
+ return false;
+ } else if (obj instanceof Short) {
+ return setValue(((Short) obj).shortValue() & 0x0ffff);
+ } else if (obj instanceof String) {
+ return setValue((String) obj);
+ } else if (obj instanceof int[]) {
+ return setValue((int[]) obj);
+ } else if (obj instanceof long[]) {
+ return setValue((long[]) obj);
+ } else if (obj instanceof Rational) {
+ return setValue((Rational) obj);
+ } else if (obj instanceof Rational[]) {
+ return setValue((Rational[]) obj);
+ } else if (obj instanceof byte[]) {
+ return setValue((byte[]) obj);
+ } else if (obj instanceof Integer) {
+ return setValue(((Integer) obj).intValue());
+ } else if (obj instanceof Long) {
+ return setValue(((Long) obj).longValue());
+ } else if (obj instanceof Byte) {
+ return setValue(((Byte) obj).byteValue());
+ } else if (obj instanceof Short[]) {
+ // Nulls in this array are treated as zeroes.
+ Short[] arr = (Short[]) obj;
+ int[] fin = new int[arr.length];
+ for (int i = 0; i < arr.length; i++) {
+ fin[i] = (arr[i] == null) ? 0 : arr[i].shortValue() & 0x0ffff;
+ }
+ return setValue(fin);
+ } else if (obj instanceof Integer[]) {
+ // Nulls in this array are treated as zeroes.
+ Integer[] arr = (Integer[]) obj;
+ int[] fin = new int[arr.length];
+ for (int i = 0; i < arr.length; i++) {
+ fin[i] = (arr[i] == null) ? 0 : arr[i].intValue();
+ }
+ return setValue(fin);
+ } else if (obj instanceof Long[]) {
+ // Nulls in this array are treated as zeroes.
+ Long[] arr = (Long[]) obj;
+ long[] fin = new long[arr.length];
+ for (int i = 0; i < arr.length; i++) {
+ fin[i] = (arr[i] == null) ? 0 : arr[i].longValue();
+ }
+ return setValue(fin);
+ } else if (obj instanceof Byte[]) {
+ // Nulls in this array are treated as zeroes.
+ Byte[] arr = (Byte[]) obj;
+ byte[] fin = new byte[arr.length];
+ for (int i = 0; i < arr.length; i++) {
+ fin[i] = (arr[i] == null) ? 0 : arr[i].byteValue();
+ }
+ return setValue(fin);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Sets a timestamp to this tag. The method converts the timestamp with the
+ * format of "yyyy:MM:dd kk:mm:ss" and calls {@link #setValue(String)}. This
+ * method will fail if the data type is not {@link #TYPE_ASCII} or the
+ * component count of this tag is not 20 or undefined.
+ *
+ * @param time the number of milliseconds since Jan. 1, 1970 GMT
+ * @return true on success
+ */
+ public boolean setTimeValue(long time) {
+ // synchronized on TIME_FORMAT as SimpleDateFormat is not thread safe
+ synchronized (TIME_FORMAT) {
+ return setValue(TIME_FORMAT.format(new Date(time)));
+ }
+ }
+
+ /**
+ * Gets the value as a String. This method should be used for tags of type
+ * {@link #TYPE_ASCII}.
+ *
+ * @return the value as a String, or null if the tag's value does not exist
+ * or cannot be converted to a String.
+ */
+ public String getValueAsString() {
+ if (mValue == null) {
+ return null;
+ } else if (mValue instanceof String) {
+ return (String) mValue;
+ } else if (mValue instanceof byte[]) {
+ return new String((byte[]) mValue, US_ASCII);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the value as a String. This method should be used for tags of type
+ * {@link #TYPE_ASCII}.
+ *
+ * @param defaultValue the String to return if the tag's value does not
+ * exist or cannot be converted to a String.
+ * @return the tag's value as a String, or the defaultValue.
+ */
+ public String getValueAsString(String defaultValue) {
+ String s = getValueAsString();
+ if (s == null) {
+ return defaultValue;
+ }
+ return s;
+ }
+
+ /**
+ * Gets the value as a byte array. This method should be used for tags of
+ * type {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE}.
+ *
+ * @return the value as a byte array, or null if the tag's value does not
+ * exist or cannot be converted to a byte array.
+ */
+ public byte[] getValueAsBytes() {
+ if (mValue instanceof byte[]) {
+ return (byte[]) mValue;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the value as a byte. If there are more than 1 bytes in this value,
+ * gets the first byte. This method should be used for tags of type
+ * {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE}.
+ *
+ * @param defaultValue the byte to return if tag's value does not exist or
+ * cannot be converted to a byte.
+ * @return the tag's value as a byte, or the defaultValue.
+ */
+ public byte getValueAsByte(byte defaultValue) {
+ byte[] b = getValueAsBytes();
+ if (b == null || b.length < 1) {
+ return defaultValue;
+ }
+ return b[0];
+ }
+
+ /**
+ * Gets the value as an array of Rationals. This method should be used for
+ * tags of type {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+ *
+ * @return the value as as an array of Rationals, or null if the tag's value
+ * does not exist or cannot be converted to an array of Rationals.
+ */
+ public Rational[] getValueAsRationals() {
+ if (mValue instanceof Rational[]) {
+ return (Rational[]) mValue;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the value as a Rational. If there are more than 1 Rationals in this
+ * value, gets the first one. This method should be used for tags of type
+ * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+ *
+ * @param defaultValue the Rational to return if tag's value does not exist
+ * or cannot be converted to a Rational.
+ * @return the tag's value as a Rational, or the defaultValue.
+ */
+ public Rational getValueAsRational(Rational defaultValue) {
+ Rational[] r = getValueAsRationals();
+ if (r == null || r.length < 1) {
+ return defaultValue;
+ }
+ return r[0];
+ }
+
+ /**
+ * Gets the value as a Rational. If there are more than 1 Rationals in this
+ * value, gets the first one. This method should be used for tags of type
+ * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+ *
+ * @param defaultValue the numerator of the Rational to return if tag's
+ * value does not exist or cannot be converted to a Rational (the
+ * denominator will be 1).
+ * @return the tag's value as a Rational, or the defaultValue.
+ */
+ public Rational getValueAsRational(long defaultValue) {
+ Rational defaultVal = new Rational(defaultValue, 1);
+ return getValueAsRational(defaultVal);
+ }
+
+ /**
+ * Gets the value as an array of ints. This method should be used for tags
+ * of type {@link #TYPE_UNSIGNED_SHORT}, {@link #TYPE_UNSIGNED_LONG}.
+ *
+ * @return the value as as an array of ints, or null if the tag's value does
+ * not exist or cannot be converted to an array of ints.
+ */
+ public int[] getValueAsInts() {
+ if (mValue == null) {
+ return null;
+ } else if (mValue instanceof long[]) {
+ long[] val = (long[]) mValue;
+ int[] arr = new int[val.length];
+ for (int i = 0; i < val.length; i++) {
+ arr[i] = (int) val[i]; // Truncates
+ }
+ return arr;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the value as an int. If there are more than 1 ints in this value,
+ * gets the first one. This method should be used for tags of type
+ * {@link #TYPE_UNSIGNED_SHORT}, {@link #TYPE_UNSIGNED_LONG}.
+ *
+ * @param defaultValue the int to return if tag's value does not exist or
+ * cannot be converted to an int.
+ * @return the tag's value as a int, or the defaultValue.
+ */
+ public int getValueAsInt(int defaultValue) {
+ int[] i = getValueAsInts();
+ if (i == null || i.length < 1) {
+ return defaultValue;
+ }
+ return i[0];
+ }
+
+ /**
+ * Gets the value as an array of longs. This method should be used for tags
+ * of type {@link #TYPE_UNSIGNED_LONG}.
+ *
+ * @return the value as as an array of longs, or null if the tag's value
+ * does not exist or cannot be converted to an array of longs.
+ */
+ public long[] getValueAsLongs() {
+ if (mValue instanceof long[]) {
+ return (long[]) mValue;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the value or null if none exists. If there are more than 1 longs in
+ * this value, gets the first one. This method should be used for tags of
+ * type {@link #TYPE_UNSIGNED_LONG}.
+ *
+ * @param defaultValue the long to return if tag's value does not exist or
+ * cannot be converted to a long.
+ * @return the tag's value as a long, or the defaultValue.
+ */
+ public long getValueAsLong(long defaultValue) {
+ long[] l = getValueAsLongs();
+ if (l == null || l.length < 1) {
+ return defaultValue;
+ }
+ return l[0];
+ }
+
+ /**
+ * Gets the tag's value or null if none exists.
+ */
+ public Object getValue() {
+ return mValue;
+ }
+
+ /**
+ * Gets a long representation of the value.
+ *
+ * @param defaultValue value to return if there is no value or value is a
+ * rational with a denominator of 0.
+ * @return the tag's value as a long, or defaultValue if no representation
+ * exists.
+ */
+ public long forceGetValueAsLong(long defaultValue) {
+ long[] l = getValueAsLongs();
+ if (l != null && l.length >= 1) {
+ return l[0];
+ }
+ byte[] b = getValueAsBytes();
+ if (b != null && b.length >= 1) {
+ return b[0];
+ }
+ Rational[] r = getValueAsRationals();
+ if (r != null && r.length >= 1 && r[0].getDenominator() != 0) {
+ return (long) r[0].toDouble();
+ }
+ return defaultValue;
+ }
+
+ /**
+ * Gets a string representation of the value.
+ */
+ public String forceGetValueAsString() {
+ if (mValue == null) {
+ return "";
+ } else if (mValue instanceof byte[]) {
+ if (mDataType == TYPE_ASCII) {
+ return new String((byte[]) mValue, US_ASCII);
+ } else {
+ return Arrays.toString((byte[]) mValue);
+ }
+ } else if (mValue instanceof long[]) {
+ if (((long[]) mValue).length == 1) {
+ return String.valueOf(((long[]) mValue)[0]);
+ } else {
+ return Arrays.toString((long[]) mValue);
+ }
+ } else if (mValue instanceof Object[]) {
+ if (((Object[]) mValue).length == 1) {
+ Object val = ((Object[]) mValue)[0];
+ if (val == null) {
+ return "";
+ } else {
+ return val.toString();
+ }
+ } else {
+ return Arrays.toString((Object[]) mValue);
+ }
+ } else {
+ return mValue.toString();
+ }
+ }
+
+ /**
+ * Gets the value for type {@link #TYPE_ASCII}, {@link #TYPE_LONG},
+ * {@link #TYPE_UNDEFINED}, {@link #TYPE_UNSIGNED_BYTE},
+ * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_UNSIGNED_SHORT}. For
+ * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}, call
+ * {@link #getRational(int)} instead.
+ *
+ * @exception IllegalArgumentException if the data type is
+ * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+ */
+ protected long getValueAt(int index) {
+ if (mValue instanceof long[]) {
+ return ((long[]) mValue)[index];
+ } else if (mValue instanceof byte[]) {
+ return ((byte[]) mValue)[index];
+ }
+ throw new IllegalArgumentException("Cannot get integer value from "
+ + convertTypeToString(mDataType));
+ }
+
+ /**
+ * Gets the {@link #TYPE_ASCII} data.
+ *
+ * @exception IllegalArgumentException If the type is NOT
+ * {@link #TYPE_ASCII}.
+ */
+ protected String getString() {
+ if (mDataType != TYPE_ASCII) {
+ throw new IllegalArgumentException("Cannot get ASCII value from "
+ + convertTypeToString(mDataType));
+ }
+ return new String((byte[]) mValue, US_ASCII);
+ }
+
+ /*
+ * Get the converted ascii byte. Used by ExifOutputStream.
+ */
+ protected byte[] getStringByte() {
+ return (byte[]) mValue;
+ }
+
+ /**
+ * Gets the {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL} data.
+ *
+ * @exception IllegalArgumentException If the type is NOT
+ * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+ */
+ protected Rational getRational(int index) {
+ if ((mDataType != TYPE_RATIONAL) && (mDataType != TYPE_UNSIGNED_RATIONAL)) {
+ throw new IllegalArgumentException("Cannot get RATIONAL value from "
+ + convertTypeToString(mDataType));
+ }
+ return ((Rational[]) mValue)[index];
+ }
+
+ /**
+ * Equivalent to getBytes(buffer, 0, buffer.length).
+ */
+ protected void getBytes(byte[] buf) {
+ getBytes(buf, 0, buf.length);
+ }
+
+ /**
+ * Gets the {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE} data.
+ *
+ * @param buf the byte array in which to store the bytes read.
+ * @param offset the initial position in buffer to store the bytes.
+ * @param length the maximum number of bytes to store in buffer. If length >
+ * component count, only the valid bytes will be stored.
+ * @exception IllegalArgumentException If the type is NOT
+ * {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE}.
+ */
+ protected void getBytes(byte[] buf, int offset, int length) {
+ if ((mDataType != TYPE_UNDEFINED) && (mDataType != TYPE_UNSIGNED_BYTE)) {
+ throw new IllegalArgumentException("Cannot get BYTE value from "
+ + convertTypeToString(mDataType));
+ }
+ System.arraycopy(mValue, 0, buf, offset,
+ (length > mComponentCountActual) ? mComponentCountActual : length);
+ }
+
+ /**
+ * Gets the offset of this tag. This is only valid if this data size > 4 and
+ * contains an offset to the location of the actual value.
+ */
+ protected int getOffset() {
+ return mOffset;
+ }
+
+ /**
+ * Sets the offset of this tag.
+ */
+ protected void setOffset(int offset) {
+ mOffset = offset;
+ }
+
+ protected void setHasDefinedCount(boolean d) {
+ mHasDefinedDefaultComponentCount = d;
+ }
+
+ protected boolean hasDefinedCount() {
+ return mHasDefinedDefaultComponentCount;
+ }
+
+ private boolean checkBadComponentCount(int count) {
+ if (mHasDefinedDefaultComponentCount && (mComponentCountActual != count)) {
+ return true;
+ }
+ return false;
+ }
+
+ private static String convertTypeToString(short type) {
+ switch (type) {
+ case TYPE_UNSIGNED_BYTE:
+ return "UNSIGNED_BYTE";
+ case TYPE_ASCII:
+ return "ASCII";
+ case TYPE_UNSIGNED_SHORT:
+ return "UNSIGNED_SHORT";
+ case TYPE_UNSIGNED_LONG:
+ return "UNSIGNED_LONG";
+ case TYPE_UNSIGNED_RATIONAL:
+ return "UNSIGNED_RATIONAL";
+ case TYPE_UNDEFINED:
+ return "UNDEFINED";
+ case TYPE_LONG:
+ return "LONG";
+ case TYPE_RATIONAL:
+ return "RATIONAL";
+ default:
+ return "";
+ }
+ }
+
+ private boolean checkOverflowForUnsignedShort(int[] value) {
+ for (int v : value) {
+ if (v > UNSIGNED_SHORT_MAX || v < 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean checkOverflowForUnsignedLong(long[] value) {
+ for (long v : value) {
+ if (v < 0 || v > UNSIGNED_LONG_MAX) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean checkOverflowForUnsignedLong(int[] value) {
+ for (int v : value) {
+ if (v < 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean checkOverflowForUnsignedRational(Rational[] value) {
+ for (Rational v : value) {
+ if (v.getNumerator() < 0 || v.getDenominator() < 0
+ || v.getNumerator() > UNSIGNED_LONG_MAX
+ || v.getDenominator() > UNSIGNED_LONG_MAX) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean checkOverflowForRational(Rational[] value) {
+ for (Rational v : value) {
+ if (v.getNumerator() < LONG_MIN || v.getDenominator() < LONG_MIN
+ || v.getNumerator() > LONG_MAX
+ || v.getDenominator() > LONG_MAX) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj instanceof ExifTag) {
+ ExifTag tag = (ExifTag) obj;
+ if (tag.mTagId != this.mTagId
+ || tag.mComponentCountActual != this.mComponentCountActual
+ || tag.mDataType != this.mDataType) {
+ return false;
+ }
+ if (mValue != null) {
+ if (tag.mValue == null) {
+ return false;
+ } else if (mValue instanceof long[]) {
+ if (!(tag.mValue instanceof long[])) {
+ return false;
+ }
+ return Arrays.equals((long[]) mValue, (long[]) tag.mValue);
+ } else if (mValue instanceof Rational[]) {
+ if (!(tag.mValue instanceof Rational[])) {
+ return false;
+ }
+ return Arrays.equals((Rational[]) mValue, (Rational[]) tag.mValue);
+ } else if (mValue instanceof byte[]) {
+ if (!(tag.mValue instanceof byte[])) {
+ return false;
+ }
+ return Arrays.equals((byte[]) mValue, (byte[]) tag.mValue);
+ } else {
+ return mValue.equals(tag.mValue);
+ }
+ } else {
+ return tag.mValue == null;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("tag id: %04X\n", mTagId) + "ifd id: " + mIfd + "\ntype: "
+ + convertTypeToString(mDataType) + "\ncount: " + mComponentCountActual
+ + "\noffset: " + mOffset + "\nvalue: " + forceGetValueAsString() + "\n";
+ }
+
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdData.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdData.java
new file mode 100644
index 0000000..093944a
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdData.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class stores all the tags in an IFD.
+ *
+ * @see ExifData
+ * @see ExifTag
+ */
+class IfdData {
+
+ private final int mIfdId;
+ private final Map<Short, ExifTag> mExifTags = new HashMap<Short, ExifTag>();
+ private int mOffsetToNextIfd = 0;
+ private static final int[] sIfds = {
+ IfdId.TYPE_IFD_0, IfdId.TYPE_IFD_1, IfdId.TYPE_IFD_EXIF,
+ IfdId.TYPE_IFD_INTEROPERABILITY, IfdId.TYPE_IFD_GPS
+ };
+ /**
+ * Creates an IfdData with given IFD ID.
+ *
+ * @see IfdId#TYPE_IFD_0
+ * @see IfdId#TYPE_IFD_1
+ * @see IfdId#TYPE_IFD_EXIF
+ * @see IfdId#TYPE_IFD_GPS
+ * @see IfdId#TYPE_IFD_INTEROPERABILITY
+ */
+ IfdData(int ifdId) {
+ mIfdId = ifdId;
+ }
+
+ static protected int[] getIfds() {
+ return sIfds;
+ }
+
+ /**
+ * Get a array the contains all {@link ExifTag} in this IFD.
+ */
+ protected ExifTag[] getAllTags() {
+ return mExifTags.values().toArray(new ExifTag[mExifTags.size()]);
+ }
+
+ /**
+ * Gets the ID of this IFD.
+ *
+ * @see IfdId#TYPE_IFD_0
+ * @see IfdId#TYPE_IFD_1
+ * @see IfdId#TYPE_IFD_EXIF
+ * @see IfdId#TYPE_IFD_GPS
+ * @see IfdId#TYPE_IFD_INTEROPERABILITY
+ */
+ protected int getId() {
+ return mIfdId;
+ }
+
+ /**
+ * Gets the {@link ExifTag} with given tag id. Return null if there is no
+ * such tag.
+ */
+ protected ExifTag getTag(short tagId) {
+ return mExifTags.get(tagId);
+ }
+
+ /**
+ * Adds or replaces a {@link ExifTag}.
+ */
+ protected ExifTag setTag(ExifTag tag) {
+ tag.setIfd(mIfdId);
+ return mExifTags.put(tag.getTagId(), tag);
+ }
+
+ protected boolean checkCollision(short tagId) {
+ return mExifTags.get(tagId) != null;
+ }
+
+ /**
+ * Removes the tag of the given ID
+ */
+ protected void removeTag(short tagId) {
+ mExifTags.remove(tagId);
+ }
+
+ /**
+ * Gets the tags count in the IFD.
+ */
+ protected int getTagCount() {
+ return mExifTags.size();
+ }
+
+ /**
+ * Sets the offset of next IFD.
+ */
+ protected void setOffsetToNextIfd(int offset) {
+ mOffsetToNextIfd = offset;
+ }
+
+ /**
+ * Gets the offset of next IFD.
+ */
+ protected int getOffsetToNextIfd() {
+ return mOffsetToNextIfd;
+ }
+
+ /**
+ * Returns true if all tags in this two IFDs are equal. Note that tags of
+ * IFDs offset or thumbnail offset will be ignored.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (obj instanceof IfdData) {
+ IfdData data = (IfdData) obj;
+ if (data.getId() == mIfdId && data.getTagCount() == getTagCount()) {
+ ExifTag[] tags = data.getAllTags();
+ for (ExifTag tag : tags) {
+ if (ExifInterface.isOffsetTag(tag.getTagId())) {
+ continue;
+ }
+ ExifTag tag2 = mExifTags.get(tag.getTagId());
+ if (!tag.equals(tag2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdId.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdId.java
new file mode 100644
index 0000000..7842edb
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdId.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+/**
+ * The constants of the IFD ID defined in EXIF spec.
+ */
+public interface IfdId {
+ public static final int TYPE_IFD_0 = 0;
+ public static final int TYPE_IFD_1 = 1;
+ public static final int TYPE_IFD_EXIF = 2;
+ public static final int TYPE_IFD_INTEROPERABILITY = 3;
+ public static final int TYPE_IFD_GPS = 4;
+ /* This is used in ExifData to allocate enough IfdData */
+ static final int TYPE_IFD_COUNT = 5;
+
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/JpegHeader.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/JpegHeader.java
new file mode 100644
index 0000000..e3e787e
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/JpegHeader.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+class JpegHeader {
+ public static final short SOI = (short) 0xFFD8;
+ public static final short APP1 = (short) 0xFFE1;
+ public static final short APP0 = (short) 0xFFE0;
+ public static final short EOI = (short) 0xFFD9;
+
+ /**
+ * SOF (start of frame). All value between SOF0 and SOF15 is SOF marker except for DHT, JPG,
+ * and DAC marker.
+ */
+ public static final short SOF0 = (short) 0xFFC0;
+ public static final short SOF15 = (short) 0xFFCF;
+ public static final short DHT = (short) 0xFFC4;
+ public static final short JPG = (short) 0xFFC8;
+ public static final short DAC = (short) 0xFFCC;
+
+ public static final boolean isSofMarker(short marker) {
+ return marker >= SOF0 && marker <= SOF15 && marker != DHT && marker != JPG
+ && marker != DAC;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/OrderedDataOutputStream.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/OrderedDataOutputStream.java
new file mode 100644
index 0000000..428e6b9
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/OrderedDataOutputStream.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+class OrderedDataOutputStream extends FilterOutputStream {
+ private final ByteBuffer mByteBuffer = ByteBuffer.allocate(4);
+
+ public OrderedDataOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ public OrderedDataOutputStream setByteOrder(ByteOrder order) {
+ mByteBuffer.order(order);
+ return this;
+ }
+
+ public OrderedDataOutputStream writeShort(short value) throws IOException {
+ mByteBuffer.rewind();
+ mByteBuffer.putShort(value);
+ out.write(mByteBuffer.array(), 0, 2);
+ return this;
+ }
+
+ public OrderedDataOutputStream writeInt(int value) throws IOException {
+ mByteBuffer.rewind();
+ mByteBuffer.putInt(value);
+ out.write(mByteBuffer.array());
+ return this;
+ }
+
+ public OrderedDataOutputStream writeRational(Rational rational) throws IOException {
+ writeInt((int) rational.getNumerator());
+ writeInt((int) rational.getDenominator());
+ return this;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/Rational.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/Rational.java
new file mode 100644
index 0000000..591d63f
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/Rational.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+/**
+ * The rational data type of EXIF tag. Contains a pair of longs representing the
+ * numerator and denominator of a Rational number.
+ */
+public class Rational {
+
+ private final long mNumerator;
+ private final long mDenominator;
+
+ /**
+ * Create a Rational with a given numerator and denominator.
+ *
+ * @param nominator
+ * @param denominator
+ */
+ public Rational(long nominator, long denominator) {
+ mNumerator = nominator;
+ mDenominator = denominator;
+ }
+
+ /**
+ * Create a copy of a Rational.
+ */
+ public Rational(Rational r) {
+ mNumerator = r.mNumerator;
+ mDenominator = r.mDenominator;
+ }
+
+ /**
+ * Gets the numerator of the rational.
+ */
+ public long getNumerator() {
+ return mNumerator;
+ }
+
+ /**
+ * Gets the denominator of the rational
+ */
+ public long getDenominator() {
+ return mDenominator;
+ }
+
+ /**
+ * Gets the rational value as type double. Will cause a divide-by-zero error
+ * if the denominator is 0.
+ */
+ public double toDouble() {
+ return mNumerator / (double) mDenominator;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof Rational) {
+ Rational data = (Rational) obj;
+ return mNumerator == data.mNumerator && mDenominator == data.mDenominator;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return mNumerator + "/" + mDenominator;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BasicTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BasicTexture.java
new file mode 100644
index 0000000..2e77b90
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BasicTexture.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.util.Log;
+
+import com.android.gallery3d.common.Utils;
+
+import java.util.WeakHashMap;
+
+// BasicTexture is a Texture corresponds to a real GL texture.
+// The state of a BasicTexture indicates whether its data is loaded to GL memory.
+// If a BasicTexture is loaded into GL memory, it has a GL texture id.
+public abstract class BasicTexture implements Texture {
+
+ @SuppressWarnings("unused")
+ private static final String TAG = "BasicTexture";
+ protected static final int UNSPECIFIED = -1;
+
+ protected static final int STATE_UNLOADED = 0;
+ protected static final int STATE_LOADED = 1;
+ protected static final int STATE_ERROR = -1;
+
+ // Log a warning if a texture is larger along a dimension
+ private static final int MAX_TEXTURE_SIZE = 4096;
+
+ protected int mId = -1;
+ protected int mState;
+
+ protected int mWidth = UNSPECIFIED;
+ protected int mHeight = UNSPECIFIED;
+
+ protected int mTextureWidth;
+ protected int mTextureHeight;
+
+ private boolean mHasBorder;
+
+ protected GLCanvas mCanvasRef = null;
+ private static WeakHashMap<BasicTexture, Object> sAllTextures
+ = new WeakHashMap<BasicTexture, Object>();
+ private static ThreadLocal sInFinalizer = new ThreadLocal();
+
+ protected BasicTexture(GLCanvas canvas, int id, int state) {
+ setAssociatedCanvas(canvas);
+ mId = id;
+ mState = state;
+ synchronized (sAllTextures) {
+ sAllTextures.put(this, null);
+ }
+ }
+
+ protected BasicTexture() {
+ this(null, 0, STATE_UNLOADED);
+ }
+
+ protected void setAssociatedCanvas(GLCanvas canvas) {
+ mCanvasRef = canvas;
+ }
+
+ /**
+ * Sets the content size of this texture. In OpenGL, the actual texture
+ * size must be of power of 2, the size of the content may be smaller.
+ */
+ public void setSize(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ mTextureWidth = width > 0 ? Utils.nextPowerOf2(width) : 0;
+ mTextureHeight = height > 0 ? Utils.nextPowerOf2(height) : 0;
+ if (mTextureWidth > MAX_TEXTURE_SIZE || mTextureHeight > MAX_TEXTURE_SIZE) {
+ Log.w(TAG, String.format("texture is too large: %d x %d",
+ mTextureWidth, mTextureHeight), new Exception());
+ }
+ }
+
+ public boolean isFlippedVertically() {
+ return false;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ @Override
+ public int getWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getHeight() {
+ return mHeight;
+ }
+
+ // Returns the width rounded to the next power of 2.
+ public int getTextureWidth() {
+ return mTextureWidth;
+ }
+
+ // Returns the height rounded to the next power of 2.
+ public int getTextureHeight() {
+ return mTextureHeight;
+ }
+
+ // Returns true if the texture has one pixel transparent border around the
+ // actual content. This is used to avoid jigged edges.
+ //
+ // The jigged edges appear because we use GL_CLAMP_TO_EDGE for texture wrap
+ // mode (GL_CLAMP is not available in OpenGL ES), so a pixel partially
+ // covered by the texture will use the color of the edge texel. If we add
+ // the transparent border, the color of the edge texel will be mixed with
+ // appropriate amount of transparent.
+ //
+ // Currently our background is black, so we can draw the thumbnails without
+ // enabling blending.
+ public boolean hasBorder() {
+ return mHasBorder;
+ }
+
+ protected void setBorder(boolean hasBorder) {
+ mHasBorder = hasBorder;
+ }
+
+ @Override
+ public void draw(GLCanvas canvas, int x, int y) {
+ canvas.drawTexture(this, x, y, getWidth(), getHeight());
+ }
+
+ @Override
+ public void draw(GLCanvas canvas, int x, int y, int w, int h) {
+ canvas.drawTexture(this, x, y, w, h);
+ }
+
+ // onBind is called before GLCanvas binds this texture.
+ // It should make sure the data is uploaded to GL memory.
+ abstract protected boolean onBind(GLCanvas canvas);
+
+ // Returns the GL texture target for this texture (e.g. GL_TEXTURE_2D).
+ abstract protected int getTarget();
+
+ public boolean isLoaded() {
+ return mState == STATE_LOADED;
+ }
+
+ // recycle() is called when the texture will never be used again,
+ // so it can free all resources.
+ public void recycle() {
+ freeResource();
+ }
+
+ // yield() is called when the texture will not be used temporarily,
+ // so it can free some resources.
+ // The default implementation unloads the texture from GL memory, so
+ // the subclass should make sure it can reload the texture to GL memory
+ // later, or it will have to override this method.
+ public void yield() {
+ freeResource();
+ }
+
+ private void freeResource() {
+ GLCanvas canvas = mCanvasRef;
+ if (canvas != null && mId != -1) {
+ canvas.unloadTexture(this);
+ mId = -1; // Don't free it again.
+ }
+ mState = STATE_UNLOADED;
+ setAssociatedCanvas(null);
+ }
+
+ @Override
+ protected void finalize() {
+ sInFinalizer.set(BasicTexture.class);
+ recycle();
+ sInFinalizer.set(null);
+ }
+
+ // This is for deciding if we can call Bitmap's recycle().
+ // We cannot call Bitmap's recycle() in finalizer because at that point
+ // the finalizer of Bitmap may already be called so recycle() will crash.
+ public static boolean inFinalizer() {
+ return sInFinalizer.get() != null;
+ }
+
+ public static void yieldAllTextures() {
+ synchronized (sAllTextures) {
+ for (BasicTexture t : sAllTextures.keySet()) {
+ t.yield();
+ }
+ }
+ }
+
+ public static void invalidateAllTextures() {
+ synchronized (sAllTextures) {
+ for (BasicTexture t : sAllTextures.keySet()) {
+ t.mState = STATE_UNLOADED;
+ t.setAssociatedCanvas(null);
+ }
+ }
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
new file mode 100644
index 0000000..100b0b3b
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.graphics.Bitmap;
+
+import junit.framework.Assert;
+
+// BitmapTexture is a texture whose content is specified by a fixed Bitmap.
+//
+// The texture does not own the Bitmap. The user should make sure the Bitmap
+// is valid during the texture's lifetime. When the texture is recycled, it
+// does not free the Bitmap.
+public class BitmapTexture extends UploadedTexture {
+ protected Bitmap mContentBitmap;
+
+ public BitmapTexture(Bitmap bitmap) {
+ this(bitmap, false);
+ }
+
+ public BitmapTexture(Bitmap bitmap, boolean hasBorder) {
+ super(hasBorder);
+ Assert.assertTrue(bitmap != null && !bitmap.isRecycled());
+ mContentBitmap = bitmap;
+ }
+
+ @Override
+ protected void onFreeBitmap(Bitmap bitmap) {
+ // Do nothing.
+ }
+
+ @Override
+ protected Bitmap onGetBitmap() {
+ return mContentBitmap;
+ }
+
+ public Bitmap getBitmap() {
+ return mContentBitmap;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLCanvas.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLCanvas.java
new file mode 100644
index 0000000..305e905
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLCanvas.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+import javax.microedition.khronos.opengles.GL11;
+
+//
+// GLCanvas gives a convenient interface to draw using OpenGL.
+//
+// When a rectangle is specified in this interface, it means the region
+// [x, x+width) * [y, y+height)
+//
+public interface GLCanvas {
+
+ public GLId getGLId();
+
+ // Tells GLCanvas the size of the underlying GL surface. This should be
+ // called before first drawing and when the size of GL surface is changed.
+ // This is called by GLRoot and should not be called by the clients
+ // who only want to draw on the GLCanvas. Both width and height must be
+ // nonnegative.
+ public abstract void setSize(int width, int height);
+
+ // Clear the drawing buffers. This should only be used by GLRoot.
+ public abstract void clearBuffer();
+
+ public abstract void clearBuffer(float[] argb);
+
+ // Sets and gets the current alpha, alpha must be in [0, 1].
+ public abstract void setAlpha(float alpha);
+
+ public abstract float getAlpha();
+
+ // (current alpha) = (current alpha) * alpha
+ public abstract void multiplyAlpha(float alpha);
+
+ // Change the current transform matrix.
+ public abstract void translate(float x, float y, float z);
+
+ public abstract void translate(float x, float y);
+
+ public abstract void scale(float sx, float sy, float sz);
+
+ public abstract void rotate(float angle, float x, float y, float z);
+
+ public abstract void multiplyMatrix(float[] mMatrix, int offset);
+
+ // Pushes the configuration state (matrix, and alpha) onto
+ // a private stack.
+ public abstract void save();
+
+ // Same as save(), but only save those specified in saveFlags.
+ public abstract void save(int saveFlags);
+
+ public static final int SAVE_FLAG_ALL = 0xFFFFFFFF;
+ public static final int SAVE_FLAG_ALPHA = 0x01;
+ public static final int SAVE_FLAG_MATRIX = 0x02;
+
+ // Pops from the top of the stack as current configuration state (matrix,
+ // alpha, and clip). This call balances a previous call to save(), and is
+ // used to remove all modifications to the configuration state since the
+ // last save call.
+ public abstract void restore();
+
+ // Draws a line using the specified paint from (x1, y1) to (x2, y2).
+ // (Both end points are included).
+ public abstract void drawLine(float x1, float y1, float x2, float y2, GLPaint paint);
+
+ // Draws a rectangle using the specified paint from (x1, y1) to (x2, y2).
+ // (Both end points are included).
+ public abstract void drawRect(float x1, float y1, float x2, float y2, GLPaint paint);
+
+ // Fills the specified rectangle with the specified color.
+ public abstract void fillRect(float x, float y, float width, float height, int color);
+
+ // Draws a texture to the specified rectangle.
+ public abstract void drawTexture(
+ BasicTexture texture, int x, int y, int width, int height);
+
+ public abstract void drawMesh(BasicTexture tex, int x, int y, int xyBuffer,
+ int uvBuffer, int indexBuffer, int indexCount);
+
+ // Draws the source rectangle part of the texture to the target rectangle.
+ public abstract void drawTexture(BasicTexture texture, RectF source, RectF target);
+
+ // Draw a texture with a specified texture transform.
+ public abstract void drawTexture(BasicTexture texture, float[] mTextureTransform,
+ int x, int y, int w, int h);
+
+ // Draw two textures to the specified rectangle. The actual texture used is
+ // from * (1 - ratio) + to * ratio
+ // The two textures must have the same size.
+ public abstract void drawMixed(BasicTexture from, int toColor,
+ float ratio, int x, int y, int w, int h);
+
+ // Draw a region of a texture and a specified color to the specified
+ // rectangle. The actual color used is from * (1 - ratio) + to * ratio.
+ // The region of the texture is defined by parameter "src". The target
+ // rectangle is specified by parameter "target".
+ public abstract void drawMixed(BasicTexture from, int toColor,
+ float ratio, RectF src, RectF target);
+
+ // Unloads the specified texture from the canvas. The resource allocated
+ // to draw the texture will be released. The specified texture will return
+ // to the unloaded state. This function should be called only from
+ // BasicTexture or its descendant
+ public abstract boolean unloadTexture(BasicTexture texture);
+
+ // Delete the specified buffer object, similar to unloadTexture.
+ public abstract void deleteBuffer(int bufferId);
+
+ // Delete the textures and buffers in GL side. This function should only be
+ // called in the GL thread.
+ public abstract void deleteRecycledResources();
+
+ // Dump statistics information and clear the counters. For debug only.
+ public abstract void dumpStatisticsAndClear();
+
+ public abstract void beginRenderTarget(RawTexture texture);
+
+ public abstract void endRenderTarget();
+
+ /**
+ * Sets texture parameters to use GL_CLAMP_TO_EDGE for both
+ * GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T. Sets texture parameters to be
+ * GL_LINEAR for GL_TEXTURE_MIN_FILTER and GL_TEXTURE_MAG_FILTER.
+ * bindTexture() must be called prior to this.
+ *
+ * @param texture The texture to set parameters on.
+ */
+ public abstract void setTextureParameters(BasicTexture texture);
+
+ /**
+ * Initializes the texture to a size by calling texImage2D on it.
+ *
+ * @param texture The texture to initialize the size.
+ * @param format The texture format (e.g. GL_RGBA)
+ * @param type The texture type (e.g. GL_UNSIGNED_BYTE)
+ */
+ public abstract void initializeTextureSize(BasicTexture texture, int format, int type);
+
+ /**
+ * Initializes the texture to a size by calling texImage2D on it.
+ *
+ * @param texture The texture to initialize the size.
+ * @param bitmap The bitmap to initialize the bitmap with.
+ */
+ public abstract void initializeTexture(BasicTexture texture, Bitmap bitmap);
+
+ /**
+ * Calls glTexSubImage2D to upload a bitmap to the texture.
+ *
+ * @param texture The target texture to write to.
+ * @param xOffset Specifies a texel offset in the x direction within the
+ * texture array.
+ * @param yOffset Specifies a texel offset in the y direction within the
+ * texture array.
+ * @param format The texture format (e.g. GL_RGBA)
+ * @param type The texture type (e.g. GL_UNSIGNED_BYTE)
+ */
+ public abstract void texSubImage2D(BasicTexture texture, int xOffset, int yOffset,
+ Bitmap bitmap,
+ int format, int type);
+
+ /**
+ * Generates buffers and uploads the buffer data.
+ *
+ * @param buffer The buffer to upload
+ * @return The buffer ID that was generated.
+ */
+ public abstract int uploadBuffer(java.nio.FloatBuffer buffer);
+
+ /**
+ * Generates buffers and uploads the element array buffer data.
+ *
+ * @param buffer The buffer to upload
+ * @return The buffer ID that was generated.
+ */
+ public abstract int uploadBuffer(java.nio.ByteBuffer buffer);
+
+ /**
+ * After LightCycle makes GL calls, this method is called to restore the GL
+ * configuration to the one expected by GLCanvas.
+ */
+ public abstract void recoverFromLightCycle();
+
+ /**
+ * Gets the bounds given by x, y, width, and height as well as the internal
+ * matrix state. There is no special handling for non-90-degree rotations.
+ * It only considers the lower-left and upper-right corners as the bounds.
+ *
+ * @param bounds The output bounds to write to.
+ * @param x The left side of the input rectangle.
+ * @param y The bottom of the input rectangle.
+ * @param width The width of the input rectangle.
+ * @param height The height of the input rectangle.
+ */
+ public abstract void getBounds(Rect bounds, int x, int y, int width, int height);
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20Canvas.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
new file mode 100644
index 0000000..4ead131
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
@@ -0,0 +1,1009 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.gallery3d.glrenderer;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.opengl.GLES20;
+import android.opengl.GLUtils;
+import android.opengl.Matrix;
+import android.util.Log;
+
+import com.android.gallery3d.util.IntArray;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class GLES20Canvas implements GLCanvas {
+ // ************** Constants **********************
+ private static final String TAG = GLES20Canvas.class.getSimpleName();
+ private static final int FLOAT_SIZE = Float.SIZE / Byte.SIZE;
+ private static final float OPAQUE_ALPHA = 0.95f;
+
+ private static final int COORDS_PER_VERTEX = 2;
+ private static final int VERTEX_STRIDE = COORDS_PER_VERTEX * FLOAT_SIZE;
+
+ private static final int COUNT_FILL_VERTEX = 4;
+ private static final int COUNT_LINE_VERTEX = 2;
+ private static final int COUNT_RECT_VERTEX = 4;
+ private static final int OFFSET_FILL_RECT = 0;
+ private static final int OFFSET_DRAW_LINE = OFFSET_FILL_RECT + COUNT_FILL_VERTEX;
+ private static final int OFFSET_DRAW_RECT = OFFSET_DRAW_LINE + COUNT_LINE_VERTEX;
+
+ private static final float[] BOX_COORDINATES = {
+ 0, 0, // Fill rectangle
+ 1, 0,
+ 0, 1,
+ 1, 1,
+ 0, 0, // Draw line
+ 1, 1,
+ 0, 0, // Draw rectangle outline
+ 0, 1,
+ 1, 1,
+ 1, 0,
+ };
+
+ private static final float[] BOUNDS_COORDINATES = {
+ 0, 0, 0, 1,
+ 1, 1, 0, 1,
+ };
+
+ private static final String POSITION_ATTRIBUTE = "aPosition";
+ private static final String COLOR_UNIFORM = "uColor";
+ private static final String MATRIX_UNIFORM = "uMatrix";
+ private static final String TEXTURE_MATRIX_UNIFORM = "uTextureMatrix";
+ private static final String TEXTURE_SAMPLER_UNIFORM = "uTextureSampler";
+ private static final String ALPHA_UNIFORM = "uAlpha";
+ private static final String TEXTURE_COORD_ATTRIBUTE = "aTextureCoordinate";
+
+ private static final String DRAW_VERTEX_SHADER = ""
+ + "uniform mat4 " + MATRIX_UNIFORM + ";\n"
+ + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n"
+ + "void main() {\n"
+ + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n"
+ + " gl_Position = " + MATRIX_UNIFORM + " * pos;\n"
+ + "}\n";
+
+ private static final String DRAW_FRAGMENT_SHADER = ""
+ + "precision mediump float;\n"
+ + "uniform vec4 " + COLOR_UNIFORM + ";\n"
+ + "void main() {\n"
+ + " gl_FragColor = " + COLOR_UNIFORM + ";\n"
+ + "}\n";
+
+ private static final String TEXTURE_VERTEX_SHADER = ""
+ + "uniform mat4 " + MATRIX_UNIFORM + ";\n"
+ + "uniform mat4 " + TEXTURE_MATRIX_UNIFORM + ";\n"
+ + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n"
+ + "varying vec2 vTextureCoord;\n"
+ + "void main() {\n"
+ + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n"
+ + " gl_Position = " + MATRIX_UNIFORM + " * pos;\n"
+ + " vTextureCoord = (" + TEXTURE_MATRIX_UNIFORM + " * pos).xy;\n"
+ + "}\n";
+
+ private static final String MESH_VERTEX_SHADER = ""
+ + "uniform mat4 " + MATRIX_UNIFORM + ";\n"
+ + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n"
+ + "attribute vec2 " + TEXTURE_COORD_ATTRIBUTE + ";\n"
+ + "varying vec2 vTextureCoord;\n"
+ + "void main() {\n"
+ + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n"
+ + " gl_Position = " + MATRIX_UNIFORM + " * pos;\n"
+ + " vTextureCoord = " + TEXTURE_COORD_ATTRIBUTE + ";\n"
+ + "}\n";
+
+ private static final String TEXTURE_FRAGMENT_SHADER = ""
+ + "precision mediump float;\n"
+ + "varying vec2 vTextureCoord;\n"
+ + "uniform float " + ALPHA_UNIFORM + ";\n"
+ + "uniform sampler2D " + TEXTURE_SAMPLER_UNIFORM + ";\n"
+ + "void main() {\n"
+ + " gl_FragColor = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", vTextureCoord);\n"
+ + " gl_FragColor *= " + ALPHA_UNIFORM + ";\n"
+ + "}\n";
+
+ private static final String OES_TEXTURE_FRAGMENT_SHADER = ""
+ + "#extension GL_OES_EGL_image_external : require\n"
+ + "precision mediump float;\n"
+ + "varying vec2 vTextureCoord;\n"
+ + "uniform float " + ALPHA_UNIFORM + ";\n"
+ + "uniform samplerExternalOES " + TEXTURE_SAMPLER_UNIFORM + ";\n"
+ + "void main() {\n"
+ + " gl_FragColor = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", vTextureCoord);\n"
+ + " gl_FragColor *= " + ALPHA_UNIFORM + ";\n"
+ + "}\n";
+
+ private static final int INITIAL_RESTORE_STATE_SIZE = 8;
+ private static final int MATRIX_SIZE = 16;
+
+ // Keep track of restore state
+ private float[] mMatrices = new float[INITIAL_RESTORE_STATE_SIZE * MATRIX_SIZE];
+ private float[] mAlphas = new float[INITIAL_RESTORE_STATE_SIZE];
+ private IntArray mSaveFlags = new IntArray();
+
+ private int mCurrentAlphaIndex = 0;
+ private int mCurrentMatrixIndex = 0;
+
+ // Viewport size
+ private int mWidth;
+ private int mHeight;
+
+ // Projection matrix
+ private float[] mProjectionMatrix = new float[MATRIX_SIZE];
+
+ // Screen size for when we aren't bound to a texture
+ private int mScreenWidth;
+ private int mScreenHeight;
+
+ // GL programs
+ private int mDrawProgram;
+ private int mTextureProgram;
+ private int mOesTextureProgram;
+ private int mMeshProgram;
+
+ // GL buffer containing BOX_COORDINATES
+ private int mBoxCoordinates;
+
+ // Handle indices -- common
+ private static final int INDEX_POSITION = 0;
+ private static final int INDEX_MATRIX = 1;
+
+ // Handle indices -- draw
+ private static final int INDEX_COLOR = 2;
+
+ // Handle indices -- texture
+ private static final int INDEX_TEXTURE_MATRIX = 2;
+ private static final int INDEX_TEXTURE_SAMPLER = 3;
+ private static final int INDEX_ALPHA = 4;
+
+ // Handle indices -- mesh
+ private static final int INDEX_TEXTURE_COORD = 2;
+
+ private abstract static class ShaderParameter {
+ public int handle;
+ protected final String mName;
+
+ public ShaderParameter(String name) {
+ mName = name;
+ }
+
+ public abstract void loadHandle(int program);
+ }
+
+ private static class UniformShaderParameter extends ShaderParameter {
+ public UniformShaderParameter(String name) {
+ super(name);
+ }
+
+ @Override
+ public void loadHandle(int program) {
+ handle = GLES20.glGetUniformLocation(program, mName);
+ checkError();
+ }
+ }
+
+ private static class AttributeShaderParameter extends ShaderParameter {
+ public AttributeShaderParameter(String name) {
+ super(name);
+ }
+
+ @Override
+ public void loadHandle(int program) {
+ handle = GLES20.glGetAttribLocation(program, mName);
+ checkError();
+ }
+ }
+
+ ShaderParameter[] mDrawParameters = {
+ new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
+ new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
+ new UniformShaderParameter(COLOR_UNIFORM), // INDEX_COLOR
+ };
+ ShaderParameter[] mTextureParameters = {
+ new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
+ new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
+ new UniformShaderParameter(TEXTURE_MATRIX_UNIFORM), // INDEX_TEXTURE_MATRIX
+ new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
+ new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
+ };
+ ShaderParameter[] mOesTextureParameters = {
+ new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
+ new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
+ new UniformShaderParameter(TEXTURE_MATRIX_UNIFORM), // INDEX_TEXTURE_MATRIX
+ new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
+ new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
+ };
+ ShaderParameter[] mMeshParameters = {
+ new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
+ new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
+ new AttributeShaderParameter(TEXTURE_COORD_ATTRIBUTE), // INDEX_TEXTURE_COORD
+ new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
+ new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
+ };
+
+ private final IntArray mUnboundTextures = new IntArray();
+ private final IntArray mDeleteBuffers = new IntArray();
+
+ // Keep track of statistics for debugging
+ private int mCountDrawMesh = 0;
+ private int mCountTextureRect = 0;
+ private int mCountFillRect = 0;
+ private int mCountDrawLine = 0;
+
+ // Buffer for framebuffer IDs -- we keep track so we can switch the attached
+ // texture.
+ private int[] mFrameBuffer = new int[1];
+
+ // Bound textures.
+ private ArrayList<RawTexture> mTargetTextures = new ArrayList<RawTexture>();
+
+ // Temporary variables used within calculations
+ private final float[] mTempMatrix = new float[32];
+ private final float[] mTempColor = new float[4];
+ private final RectF mTempSourceRect = new RectF();
+ private final RectF mTempTargetRect = new RectF();
+ private final float[] mTempTextureMatrix = new float[MATRIX_SIZE];
+ private final int[] mTempIntArray = new int[1];
+
+ private static final GLId mGLId = new GLES20IdImpl();
+
+ public GLES20Canvas() {
+ Matrix.setIdentityM(mTempTextureMatrix, 0);
+ Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex);
+ mAlphas[mCurrentAlphaIndex] = 1f;
+ mTargetTextures.add(null);
+
+ FloatBuffer boxBuffer = createBuffer(BOX_COORDINATES);
+ mBoxCoordinates = uploadBuffer(boxBuffer);
+
+ int drawVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, DRAW_VERTEX_SHADER);
+ int textureVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, TEXTURE_VERTEX_SHADER);
+ int meshVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, MESH_VERTEX_SHADER);
+ int drawFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, DRAW_FRAGMENT_SHADER);
+ int textureFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, TEXTURE_FRAGMENT_SHADER);
+ int oesTextureFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
+ OES_TEXTURE_FRAGMENT_SHADER);
+
+ mDrawProgram = assembleProgram(drawVertexShader, drawFragmentShader, mDrawParameters);
+ mTextureProgram = assembleProgram(textureVertexShader, textureFragmentShader,
+ mTextureParameters);
+ mOesTextureProgram = assembleProgram(textureVertexShader, oesTextureFragmentShader,
+ mOesTextureParameters);
+ mMeshProgram = assembleProgram(meshVertexShader, textureFragmentShader, mMeshParameters);
+ GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
+ checkError();
+ }
+
+ private static FloatBuffer createBuffer(float[] values) {
+ // First create an nio buffer, then create a VBO from it.
+ int size = values.length * FLOAT_SIZE;
+ FloatBuffer buffer = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder())
+ .asFloatBuffer();
+ buffer.put(values, 0, values.length).position(0);
+ return buffer;
+ }
+
+ private int assembleProgram(int vertexShader, int fragmentShader, ShaderParameter[] params) {
+ int program = GLES20.glCreateProgram();
+ checkError();
+ if (program == 0) {
+ throw new RuntimeException("Cannot create GL program: " + GLES20.glGetError());
+ }
+ GLES20.glAttachShader(program, vertexShader);
+ checkError();
+ GLES20.glAttachShader(program, fragmentShader);
+ checkError();
+ GLES20.glLinkProgram(program);
+ checkError();
+ int[] mLinkStatus = mTempIntArray;
+ GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, mLinkStatus, 0);
+ if (mLinkStatus[0] != GLES20.GL_TRUE) {
+ Log.e(TAG, "Could not link program: ");
+ Log.e(TAG, GLES20.glGetProgramInfoLog(program));
+ GLES20.glDeleteProgram(program);
+ program = 0;
+ }
+ for (int i = 0; i < params.length; i++) {
+ params[i].loadHandle(program);
+ }
+ return program;
+ }
+
+ private static int loadShader(int type, String shaderCode) {
+ // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
+ // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
+ int shader = GLES20.glCreateShader(type);
+
+ // add the source code to the shader and compile it
+ GLES20.glShaderSource(shader, shaderCode);
+ checkError();
+ GLES20.glCompileShader(shader);
+ checkError();
+
+ return shader;
+ }
+
+ @Override
+ public void setSize(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ GLES20.glViewport(0, 0, mWidth, mHeight);
+ checkError();
+ Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex);
+ Matrix.orthoM(mProjectionMatrix, 0, 0, width, 0, height, -1, 1);
+ if (getTargetTexture() == null) {
+ mScreenWidth = width;
+ mScreenHeight = height;
+ Matrix.translateM(mMatrices, mCurrentMatrixIndex, 0, height, 0);
+ Matrix.scaleM(mMatrices, mCurrentMatrixIndex, 1, -1, 1);
+ }
+ }
+
+ @Override
+ public void clearBuffer() {
+ GLES20.glClearColor(0f, 0f, 0f, 1f);
+ checkError();
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ checkError();
+ }
+
+ @Override
+ public void clearBuffer(float[] argb) {
+ GLES20.glClearColor(argb[1], argb[2], argb[3], argb[0]);
+ checkError();
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ checkError();
+ }
+
+ @Override
+ public float getAlpha() {
+ return mAlphas[mCurrentAlphaIndex];
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ mAlphas[mCurrentAlphaIndex] = alpha;
+ }
+
+ @Override
+ public void multiplyAlpha(float alpha) {
+ setAlpha(getAlpha() * alpha);
+ }
+
+ @Override
+ public void translate(float x, float y, float z) {
+ Matrix.translateM(mMatrices, mCurrentMatrixIndex, x, y, z);
+ }
+
+ // This is a faster version of translate(x, y, z) because
+ // (1) we knows z = 0, (2) we inline the Matrix.translateM call,
+ // (3) we unroll the loop
+ @Override
+ public void translate(float x, float y) {
+ int index = mCurrentMatrixIndex;
+ float[] m = mMatrices;
+ m[index + 12] += m[index + 0] * x + m[index + 4] * y;
+ m[index + 13] += m[index + 1] * x + m[index + 5] * y;
+ m[index + 14] += m[index + 2] * x + m[index + 6] * y;
+ m[index + 15] += m[index + 3] * x + m[index + 7] * y;
+ }
+
+ @Override
+ public void scale(float sx, float sy, float sz) {
+ Matrix.scaleM(mMatrices, mCurrentMatrixIndex, sx, sy, sz);
+ }
+
+ @Override
+ public void rotate(float angle, float x, float y, float z) {
+ if (angle == 0f) {
+ return;
+ }
+ float[] temp = mTempMatrix;
+ Matrix.setRotateM(temp, 0, angle, x, y, z);
+ float[] matrix = mMatrices;
+ int index = mCurrentMatrixIndex;
+ Matrix.multiplyMM(temp, MATRIX_SIZE, matrix, index, temp, 0);
+ System.arraycopy(temp, MATRIX_SIZE, matrix, index, MATRIX_SIZE);
+ }
+
+ @Override
+ public void multiplyMatrix(float[] matrix, int offset) {
+ float[] temp = mTempMatrix;
+ float[] currentMatrix = mMatrices;
+ int index = mCurrentMatrixIndex;
+ Matrix.multiplyMM(temp, 0, currentMatrix, index, matrix, offset);
+ System.arraycopy(temp, 0, currentMatrix, index, 16);
+ }
+
+ @Override
+ public void save() {
+ save(SAVE_FLAG_ALL);
+ }
+
+ @Override
+ public void save(int saveFlags) {
+ boolean saveAlpha = (saveFlags & SAVE_FLAG_ALPHA) == SAVE_FLAG_ALPHA;
+ if (saveAlpha) {
+ float currentAlpha = getAlpha();
+ mCurrentAlphaIndex++;
+ if (mAlphas.length <= mCurrentAlphaIndex) {
+ mAlphas = Arrays.copyOf(mAlphas, mAlphas.length * 2);
+ }
+ mAlphas[mCurrentAlphaIndex] = currentAlpha;
+ }
+ boolean saveMatrix = (saveFlags & SAVE_FLAG_MATRIX) == SAVE_FLAG_MATRIX;
+ if (saveMatrix) {
+ int currentIndex = mCurrentMatrixIndex;
+ mCurrentMatrixIndex += MATRIX_SIZE;
+ if (mMatrices.length <= mCurrentMatrixIndex) {
+ mMatrices = Arrays.copyOf(mMatrices, mMatrices.length * 2);
+ }
+ System.arraycopy(mMatrices, currentIndex, mMatrices, mCurrentMatrixIndex, MATRIX_SIZE);
+ }
+ mSaveFlags.add(saveFlags);
+ }
+
+ @Override
+ public void restore() {
+ int restoreFlags = mSaveFlags.removeLast();
+ boolean restoreAlpha = (restoreFlags & SAVE_FLAG_ALPHA) == SAVE_FLAG_ALPHA;
+ if (restoreAlpha) {
+ mCurrentAlphaIndex--;
+ }
+ boolean restoreMatrix = (restoreFlags & SAVE_FLAG_MATRIX) == SAVE_FLAG_MATRIX;
+ if (restoreMatrix) {
+ mCurrentMatrixIndex -= MATRIX_SIZE;
+ }
+ }
+
+ @Override
+ public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint) {
+ draw(GLES20.GL_LINE_STRIP, OFFSET_DRAW_LINE, COUNT_LINE_VERTEX, x1, y1, x2 - x1, y2 - y1,
+ paint);
+ mCountDrawLine++;
+ }
+
+ @Override
+ public void drawRect(float x, float y, float width, float height, GLPaint paint) {
+ draw(GLES20.GL_LINE_LOOP, OFFSET_DRAW_RECT, COUNT_RECT_VERTEX, x, y, width, height, paint);
+ mCountDrawLine++;
+ }
+
+ private void draw(int type, int offset, int count, float x, float y, float width, float height,
+ GLPaint paint) {
+ draw(type, offset, count, x, y, width, height, paint.getColor(), paint.getLineWidth());
+ }
+
+ private void draw(int type, int offset, int count, float x, float y, float width, float height,
+ int color, float lineWidth) {
+ prepareDraw(offset, color, lineWidth);
+ draw(mDrawParameters, type, count, x, y, width, height);
+ }
+
+ private void prepareDraw(int offset, int color, float lineWidth) {
+ GLES20.glUseProgram(mDrawProgram);
+ checkError();
+ if (lineWidth > 0) {
+ GLES20.glLineWidth(lineWidth);
+ checkError();
+ }
+ float[] colorArray = getColor(color);
+ boolean blendingEnabled = (colorArray[3] < 1f);
+ enableBlending(blendingEnabled);
+ if (blendingEnabled) {
+ GLES20.glBlendColor(colorArray[0], colorArray[1], colorArray[2], colorArray[3]);
+ checkError();
+ }
+
+ GLES20.glUniform4fv(mDrawParameters[INDEX_COLOR].handle, 1, colorArray, 0);
+ setPosition(mDrawParameters, offset);
+ checkError();
+ }
+
+ private float[] getColor(int color) {
+ float alpha = ((color >>> 24) & 0xFF) / 255f * getAlpha();
+ float red = ((color >>> 16) & 0xFF) / 255f * alpha;
+ float green = ((color >>> 8) & 0xFF) / 255f * alpha;
+ float blue = (color & 0xFF) / 255f * alpha;
+ mTempColor[0] = red;
+ mTempColor[1] = green;
+ mTempColor[2] = blue;
+ mTempColor[3] = alpha;
+ return mTempColor;
+ }
+
+ private void enableBlending(boolean enableBlending) {
+ if (enableBlending) {
+ GLES20.glEnable(GLES20.GL_BLEND);
+ checkError();
+ } else {
+ GLES20.glDisable(GLES20.GL_BLEND);
+ checkError();
+ }
+ }
+
+ private void setPosition(ShaderParameter[] params, int offset) {
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mBoxCoordinates);
+ checkError();
+ GLES20.glVertexAttribPointer(params[INDEX_POSITION].handle, COORDS_PER_VERTEX,
+ GLES20.GL_FLOAT, false, VERTEX_STRIDE, offset * VERTEX_STRIDE);
+ checkError();
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+ checkError();
+ }
+
+ private void draw(ShaderParameter[] params, int type, int count, float x, float y, float width,
+ float height) {
+ setMatrix(params, x, y, width, height);
+ int positionHandle = params[INDEX_POSITION].handle;
+ GLES20.glEnableVertexAttribArray(positionHandle);
+ checkError();
+ GLES20.glDrawArrays(type, 0, count);
+ checkError();
+ GLES20.glDisableVertexAttribArray(positionHandle);
+ checkError();
+ }
+
+ private void setMatrix(ShaderParameter[] params, float x, float y, float width, float height) {
+ Matrix.translateM(mTempMatrix, 0, mMatrices, mCurrentMatrixIndex, x, y, 0f);
+ Matrix.scaleM(mTempMatrix, 0, width, height, 1f);
+ Matrix.multiplyMM(mTempMatrix, MATRIX_SIZE, mProjectionMatrix, 0, mTempMatrix, 0);
+ GLES20.glUniformMatrix4fv(params[INDEX_MATRIX].handle, 1, false, mTempMatrix, MATRIX_SIZE);
+ checkError();
+ }
+
+ @Override
+ public void fillRect(float x, float y, float width, float height, int color) {
+ draw(GLES20.GL_TRIANGLE_STRIP, OFFSET_FILL_RECT, COUNT_FILL_VERTEX, x, y, width, height,
+ color, 0f);
+ mCountFillRect++;
+ }
+
+ @Override
+ public void drawTexture(BasicTexture texture, int x, int y, int width, int height) {
+ if (width <= 0 || height <= 0) {
+ return;
+ }
+ copyTextureCoordinates(texture, mTempSourceRect);
+ mTempTargetRect.set(x, y, x + width, y + height);
+ convertCoordinate(mTempSourceRect, mTempTargetRect, texture);
+ drawTextureRect(texture, mTempSourceRect, mTempTargetRect);
+ }
+
+ private static void copyTextureCoordinates(BasicTexture texture, RectF outRect) {
+ int left = 0;
+ int top = 0;
+ int right = texture.getWidth();
+ int bottom = texture.getHeight();
+ if (texture.hasBorder()) {
+ left = 1;
+ top = 1;
+ right -= 1;
+ bottom -= 1;
+ }
+ outRect.set(left, top, right, bottom);
+ }
+
+ @Override
+ public void drawTexture(BasicTexture texture, RectF source, RectF target) {
+ if (target.width() <= 0 || target.height() <= 0) {
+ return;
+ }
+ mTempSourceRect.set(source);
+ mTempTargetRect.set(target);
+
+ convertCoordinate(mTempSourceRect, mTempTargetRect, texture);
+ drawTextureRect(texture, mTempSourceRect, mTempTargetRect);
+ }
+
+ @Override
+ public void drawTexture(BasicTexture texture, float[] textureTransform, int x, int y, int w,
+ int h) {
+ if (w <= 0 || h <= 0) {
+ return;
+ }
+ mTempTargetRect.set(x, y, x + w, y + h);
+ drawTextureRect(texture, textureTransform, mTempTargetRect);
+ }
+
+ private void drawTextureRect(BasicTexture texture, RectF source, RectF target) {
+ setTextureMatrix(source);
+ drawTextureRect(texture, mTempTextureMatrix, target);
+ }
+
+ private void setTextureMatrix(RectF source) {
+ mTempTextureMatrix[0] = source.width();
+ mTempTextureMatrix[5] = source.height();
+ mTempTextureMatrix[12] = source.left;
+ mTempTextureMatrix[13] = source.top;
+ }
+
+ // This function changes the source coordinate to the texture coordinates.
+ // It also clips the source and target coordinates if it is beyond the
+ // bound of the texture.
+ private static void convertCoordinate(RectF source, RectF target, BasicTexture texture) {
+ int width = texture.getWidth();
+ int height = texture.getHeight();
+ int texWidth = texture.getTextureWidth();
+ int texHeight = texture.getTextureHeight();
+ // Convert to texture coordinates
+ source.left /= texWidth;
+ source.right /= texWidth;
+ source.top /= texHeight;
+ source.bottom /= texHeight;
+
+ // Clip if the rendering range is beyond the bound of the texture.
+ float xBound = (float) width / texWidth;
+ if (source.right > xBound) {
+ target.right = target.left + target.width() * (xBound - source.left) / source.width();
+ source.right = xBound;
+ }
+ float yBound = (float) height / texHeight;
+ if (source.bottom > yBound) {
+ target.bottom = target.top + target.height() * (yBound - source.top) / source.height();
+ source.bottom = yBound;
+ }
+ }
+
+ private void drawTextureRect(BasicTexture texture, float[] textureMatrix, RectF target) {
+ ShaderParameter[] params = prepareTexture(texture);
+ setPosition(params, OFFSET_FILL_RECT);
+ GLES20.glUniformMatrix4fv(params[INDEX_TEXTURE_MATRIX].handle, 1, false, textureMatrix, 0);
+ checkError();
+ if (texture.isFlippedVertically()) {
+ save(SAVE_FLAG_MATRIX);
+ translate(0, target.centerY());
+ scale(1, -1, 1);
+ translate(0, -target.centerY());
+ }
+ draw(params, GLES20.GL_TRIANGLE_STRIP, COUNT_FILL_VERTEX, target.left, target.top,
+ target.width(), target.height());
+ if (texture.isFlippedVertically()) {
+ restore();
+ }
+ mCountTextureRect++;
+ }
+
+ private ShaderParameter[] prepareTexture(BasicTexture texture) {
+ ShaderParameter[] params;
+ int program;
+ if (texture.getTarget() == GLES20.GL_TEXTURE_2D) {
+ params = mTextureParameters;
+ program = mTextureProgram;
+ } else {
+ params = mOesTextureParameters;
+ program = mOesTextureProgram;
+ }
+ prepareTexture(texture, program, params);
+ return params;
+ }
+
+ private void prepareTexture(BasicTexture texture, int program, ShaderParameter[] params) {
+ GLES20.glUseProgram(program);
+ checkError();
+ enableBlending(!texture.isOpaque() || getAlpha() < OPAQUE_ALPHA);
+ GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+ checkError();
+ texture.onBind(this);
+ GLES20.glBindTexture(texture.getTarget(), texture.getId());
+ checkError();
+ GLES20.glUniform1i(params[INDEX_TEXTURE_SAMPLER].handle, 0);
+ checkError();
+ GLES20.glUniform1f(params[INDEX_ALPHA].handle, getAlpha());
+ checkError();
+ }
+
+ @Override
+ public void drawMesh(BasicTexture texture, int x, int y, int xyBuffer, int uvBuffer,
+ int indexBuffer, int indexCount) {
+ prepareTexture(texture, mMeshProgram, mMeshParameters);
+
+ GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
+ checkError();
+
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, xyBuffer);
+ checkError();
+ int positionHandle = mMeshParameters[INDEX_POSITION].handle;
+ GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false,
+ VERTEX_STRIDE, 0);
+ checkError();
+
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, uvBuffer);
+ checkError();
+ int texCoordHandle = mMeshParameters[INDEX_TEXTURE_COORD].handle;
+ GLES20.glVertexAttribPointer(texCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
+ false, VERTEX_STRIDE, 0);
+ checkError();
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+ checkError();
+
+ GLES20.glEnableVertexAttribArray(positionHandle);
+ checkError();
+ GLES20.glEnableVertexAttribArray(texCoordHandle);
+ checkError();
+
+ setMatrix(mMeshParameters, x, y, 1, 1);
+ GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, indexCount, GLES20.GL_UNSIGNED_BYTE, 0);
+ checkError();
+
+ GLES20.glDisableVertexAttribArray(positionHandle);
+ checkError();
+ GLES20.glDisableVertexAttribArray(texCoordHandle);
+ checkError();
+ GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
+ checkError();
+ mCountDrawMesh++;
+ }
+
+ @Override
+ public void drawMixed(BasicTexture texture, int toColor, float ratio, int x, int y, int w, int h) {
+ copyTextureCoordinates(texture, mTempSourceRect);
+ mTempTargetRect.set(x, y, x + w, y + h);
+ drawMixed(texture, toColor, ratio, mTempSourceRect, mTempTargetRect);
+ }
+
+ @Override
+ public void drawMixed(BasicTexture texture, int toColor, float ratio, RectF source, RectF target) {
+ if (target.width() <= 0 || target.height() <= 0) {
+ return;
+ }
+ save(SAVE_FLAG_ALPHA);
+
+ float currentAlpha = getAlpha();
+ float cappedRatio = Math.min(1f, Math.max(0f, ratio));
+
+ float textureAlpha = (1f - cappedRatio) * currentAlpha;
+ setAlpha(textureAlpha);
+ drawTexture(texture, source, target);
+
+ float colorAlpha = cappedRatio * currentAlpha;
+ setAlpha(colorAlpha);
+ fillRect(target.left, target.top, target.width(), target.height(), toColor);
+
+ restore();
+ }
+
+ @Override
+ public boolean unloadTexture(BasicTexture texture) {
+ boolean unload = texture.isLoaded();
+ if (unload) {
+ synchronized (mUnboundTextures) {
+ mUnboundTextures.add(texture.getId());
+ }
+ }
+ return unload;
+ }
+
+ @Override
+ public void deleteBuffer(int bufferId) {
+ synchronized (mUnboundTextures) {
+ mDeleteBuffers.add(bufferId);
+ }
+ }
+
+ @Override
+ public void deleteRecycledResources() {
+ synchronized (mUnboundTextures) {
+ IntArray ids = mUnboundTextures;
+ if (mUnboundTextures.size() > 0) {
+ mGLId.glDeleteTextures(null, ids.size(), ids.getInternalArray(), 0);
+ ids.clear();
+ }
+
+ ids = mDeleteBuffers;
+ if (ids.size() > 0) {
+ mGLId.glDeleteBuffers(null, ids.size(), ids.getInternalArray(), 0);
+ ids.clear();
+ }
+ }
+ }
+
+ @Override
+ public void dumpStatisticsAndClear() {
+ String line = String.format("MESH:%d, TEX_RECT:%d, FILL_RECT:%d, LINE:%d", mCountDrawMesh,
+ mCountTextureRect, mCountFillRect, mCountDrawLine);
+ mCountDrawMesh = 0;
+ mCountTextureRect = 0;
+ mCountFillRect = 0;
+ mCountDrawLine = 0;
+ Log.d(TAG, line);
+ }
+
+ @Override
+ public void endRenderTarget() {
+ RawTexture oldTexture = mTargetTextures.remove(mTargetTextures.size() - 1);
+ RawTexture texture = getTargetTexture();
+ setRenderTarget(oldTexture, texture);
+ restore(); // restore matrix and alpha
+ }
+
+ @Override
+ public void beginRenderTarget(RawTexture texture) {
+ save(); // save matrix and alpha and blending
+ RawTexture oldTexture = getTargetTexture();
+ mTargetTextures.add(texture);
+ setRenderTarget(oldTexture, texture);
+ }
+
+ private RawTexture getTargetTexture() {
+ return mTargetTextures.get(mTargetTextures.size() - 1);
+ }
+
+ private void setRenderTarget(BasicTexture oldTexture, RawTexture texture) {
+ if (oldTexture == null && texture != null) {
+ GLES20.glGenFramebuffers(1, mFrameBuffer, 0);
+ checkError();
+ GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffer[0]);
+ checkError();
+ } else if (oldTexture != null && texture == null) {
+ GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
+ checkError();
+ GLES20.glDeleteFramebuffers(1, mFrameBuffer, 0);
+ checkError();
+ }
+
+ if (texture == null) {
+ setSize(mScreenWidth, mScreenHeight);
+ } else {
+ setSize(texture.getWidth(), texture.getHeight());
+
+ if (!texture.isLoaded()) {
+ texture.prepare(this);
+ }
+
+ GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
+ texture.getTarget(), texture.getId(), 0);
+ checkError();
+
+ checkFramebufferStatus();
+ }
+ }
+
+ private static void checkFramebufferStatus() {
+ int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
+ if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) {
+ String msg = "";
+ switch (status) {
+ case GLES20.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+ msg = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
+ break;
+ case GLES20.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+ msg = "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
+ break;
+ case GLES20.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+ msg = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
+ break;
+ case GLES20.GL_FRAMEBUFFER_UNSUPPORTED:
+ msg = "GL_FRAMEBUFFER_UNSUPPORTED";
+ break;
+ }
+ throw new RuntimeException(msg + ":" + Integer.toHexString(status));
+ }
+ }
+
+ @Override
+ public void setTextureParameters(BasicTexture texture) {
+ int target = texture.getTarget();
+ GLES20.glBindTexture(target, texture.getId());
+ checkError();
+ GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
+ GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
+ GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
+ GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
+ }
+
+ @Override
+ public void initializeTextureSize(BasicTexture texture, int format, int type) {
+ int target = texture.getTarget();
+ GLES20.glBindTexture(target, texture.getId());
+ checkError();
+ int width = texture.getTextureWidth();
+ int height = texture.getTextureHeight();
+ GLES20.glTexImage2D(target, 0, format, width, height, 0, format, type, null);
+ }
+
+ @Override
+ public void initializeTexture(BasicTexture texture, Bitmap bitmap) {
+ int target = texture.getTarget();
+ GLES20.glBindTexture(target, texture.getId());
+ checkError();
+ GLUtils.texImage2D(target, 0, bitmap, 0);
+ }
+
+ @Override
+ public void texSubImage2D(BasicTexture texture, int xOffset, int yOffset, Bitmap bitmap,
+ int format, int type) {
+ int target = texture.getTarget();
+ GLES20.glBindTexture(target, texture.getId());
+ checkError();
+ GLUtils.texSubImage2D(target, 0, xOffset, yOffset, bitmap, format, type);
+ }
+
+ @Override
+ public int uploadBuffer(FloatBuffer buf) {
+ return uploadBuffer(buf, FLOAT_SIZE);
+ }
+
+ @Override
+ public int uploadBuffer(ByteBuffer buf) {
+ return uploadBuffer(buf, 1);
+ }
+
+ private int uploadBuffer(Buffer buffer, int elementSize) {
+ mGLId.glGenBuffers(1, mTempIntArray, 0);
+ checkError();
+ int bufferId = mTempIntArray[0];
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferId);
+ checkError();
+ GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, buffer.capacity() * elementSize, buffer,
+ GLES20.GL_STATIC_DRAW);
+ checkError();
+ return bufferId;
+ }
+
+ public static void checkError() {
+ int error = GLES20.glGetError();
+ if (error != 0) {
+ Throwable t = new Throwable();
+ Log.e(TAG, "GL error: " + error, t);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static void printMatrix(String message, float[] m, int offset) {
+ StringBuilder b = new StringBuilder(message);
+ for (int i = 0; i < MATRIX_SIZE; i++) {
+ b.append(' ');
+ if (i % 4 == 0) {
+ b.append('\n');
+ }
+ b.append(m[offset + i]);
+ }
+ Log.v(TAG, b.toString());
+ }
+
+ @Override
+ public void recoverFromLightCycle() {
+ GLES20.glViewport(0, 0, mWidth, mHeight);
+ GLES20.glDisable(GLES20.GL_DEPTH_TEST);
+ GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
+ checkError();
+ }
+
+ @Override
+ public void getBounds(Rect bounds, int x, int y, int width, int height) {
+ Matrix.translateM(mTempMatrix, 0, mMatrices, mCurrentMatrixIndex, x, y, 0f);
+ Matrix.scaleM(mTempMatrix, 0, width, height, 1f);
+ Matrix.multiplyMV(mTempMatrix, MATRIX_SIZE, mTempMatrix, 0, BOUNDS_COORDINATES, 0);
+ Matrix.multiplyMV(mTempMatrix, MATRIX_SIZE + 4, mTempMatrix, 0, BOUNDS_COORDINATES, 4);
+ bounds.left = Math.round(mTempMatrix[MATRIX_SIZE]);
+ bounds.right = Math.round(mTempMatrix[MATRIX_SIZE + 4]);
+ bounds.top = Math.round(mTempMatrix[MATRIX_SIZE + 1]);
+ bounds.bottom = Math.round(mTempMatrix[MATRIX_SIZE + 5]);
+ bounds.sort();
+ }
+
+ @Override
+ public GLId getGLId() {
+ return mGLId;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20IdImpl.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20IdImpl.java
new file mode 100644
index 0000000..6cd7149
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20IdImpl.java
@@ -0,0 +1,42 @@
+package com.android.gallery3d.glrenderer;
+
+import android.opengl.GLES20;
+
+import javax.microedition.khronos.opengles.GL11;
+import javax.microedition.khronos.opengles.GL11ExtensionPack;
+
+public class GLES20IdImpl implements GLId {
+ private final int[] mTempIntArray = new int[1];
+
+ @Override
+ public int generateTexture() {
+ GLES20.glGenTextures(1, mTempIntArray, 0);
+ GLES20Canvas.checkError();
+ return mTempIntArray[0];
+ }
+
+ @Override
+ public void glGenBuffers(int n, int[] buffers, int offset) {
+ GLES20.glGenBuffers(n, buffers, offset);
+ GLES20Canvas.checkError();
+ }
+
+ @Override
+ public void glDeleteTextures(GL11 gl, int n, int[] textures, int offset) {
+ GLES20.glDeleteTextures(n, textures, offset);
+ GLES20Canvas.checkError();
+ }
+
+
+ @Override
+ public void glDeleteBuffers(GL11 gl, int n, int[] buffers, int offset) {
+ GLES20.glDeleteBuffers(n, buffers, offset);
+ GLES20Canvas.checkError();
+ }
+
+ @Override
+ public void glDeleteFramebuffers(GL11ExtensionPack gl11ep, int n, int[] buffers, int offset) {
+ GLES20.glDeleteFramebuffers(n, buffers, offset);
+ GLES20Canvas.checkError();
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLId.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLId.java
new file mode 100644
index 0000000..3cec558
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLId.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import javax.microedition.khronos.opengles.GL11;
+import javax.microedition.khronos.opengles.GL11ExtensionPack;
+
+// This mimics corresponding GL functions.
+public interface GLId {
+ public int generateTexture();
+
+ public void glGenBuffers(int n, int[] buffers, int offset);
+
+ public void glDeleteTextures(GL11 gl, int n, int[] textures, int offset);
+
+ public void glDeleteBuffers(GL11 gl, int n, int[] buffers, int offset);
+
+ public void glDeleteFramebuffers(GL11ExtensionPack gl11ep, int n, int[] buffers, int offset);
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
new file mode 100644
index 0000000..16b2206
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import junit.framework.Assert;
+
+public class GLPaint {
+ private float mLineWidth = 1f;
+ private int mColor = 0;
+
+ public void setColor(int color) {
+ mColor = color;
+ }
+
+ public int getColor() {
+ return mColor;
+ }
+
+ public void setLineWidth(float width) {
+ Assert.assertTrue(width >= 0);
+ mLineWidth = width;
+ }
+
+ public float getLineWidth() {
+ return mLineWidth;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/RawTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/RawTexture.java
new file mode 100644
index 0000000..93f0fdf
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/RawTexture.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.util.Log;
+
+import javax.microedition.khronos.opengles.GL11;
+
+public class RawTexture extends BasicTexture {
+ private static final String TAG = "RawTexture";
+
+ private final boolean mOpaque;
+ private boolean mIsFlipped;
+
+ public RawTexture(int width, int height, boolean opaque) {
+ mOpaque = opaque;
+ setSize(width, height);
+ }
+
+ @Override
+ public boolean isOpaque() {
+ return mOpaque;
+ }
+
+ @Override
+ public boolean isFlippedVertically() {
+ return mIsFlipped;
+ }
+
+ public void setIsFlippedVertically(boolean isFlipped) {
+ mIsFlipped = isFlipped;
+ }
+
+ protected void prepare(GLCanvas canvas) {
+ GLId glId = canvas.getGLId();
+ mId = glId.generateTexture();
+ canvas.initializeTextureSize(this, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE);
+ canvas.setTextureParameters(this);
+ mState = STATE_LOADED;
+ setAssociatedCanvas(canvas);
+ }
+
+ @Override
+ protected boolean onBind(GLCanvas canvas) {
+ if (isLoaded()) return true;
+ Log.w(TAG, "lost the content due to context change");
+ return false;
+ }
+
+ @Override
+ public void yield() {
+ // we cannot free the texture because we have no backup.
+ }
+
+ @Override
+ protected int getTarget() {
+ return GL11.GL_TEXTURE_2D;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/Texture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/Texture.java
new file mode 100644
index 0000000..3dcae4a
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/Texture.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+
+// Texture is a rectangular image which can be drawn on GLCanvas.
+// The isOpaque() function gives a hint about whether the texture is opaque,
+// so the drawing can be done faster.
+//
+// This is the current texture hierarchy:
+//
+// Texture
+// -- ColorTexture
+// -- FadeInTexture
+// -- BasicTexture
+// -- UploadedTexture
+// -- BitmapTexture
+// -- Tile
+// -- ResourceTexture
+// -- NinePatchTexture
+// -- CanvasTexture
+// -- StringTexture
+//
+public interface Texture {
+ public int getWidth();
+ public int getHeight();
+ public void draw(GLCanvas canvas, int x, int y);
+ public void draw(GLCanvas canvas, int x, int y, int w, int h);
+ public boolean isOpaque();
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
new file mode 100644
index 0000000..f41a979
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.opengl.GLUtils;
+
+import junit.framework.Assert;
+
+import java.util.HashMap;
+
+import javax.microedition.khronos.opengles.GL11;
+
+// UploadedTextures use a Bitmap for the content of the texture.
+//
+// Subclasses should implement onGetBitmap() to provide the Bitmap and
+// implement onFreeBitmap(mBitmap) which will be called when the Bitmap
+// is not needed anymore.
+//
+// isContentValid() is meaningful only when the isLoaded() returns true.
+// It means whether the content needs to be updated.
+//
+// The user of this class should call recycle() when the texture is not
+// needed anymore.
+//
+// By default an UploadedTexture is opaque (so it can be drawn faster without
+// blending). The user or subclass can override it using setOpaque().
+public abstract class UploadedTexture extends BasicTexture {
+
+ // To prevent keeping allocation the borders, we store those used borders here.
+ // Since the length will be power of two, it won't use too much memory.
+ private static HashMap<BorderKey, Bitmap> sBorderLines =
+ new HashMap<BorderKey, Bitmap>();
+ private static BorderKey sBorderKey = new BorderKey();
+
+ @SuppressWarnings("unused")
+ private static final String TAG = "Texture";
+ private boolean mContentValid = true;
+
+ // indicate this textures is being uploaded in background
+ private boolean mIsUploading = false;
+ private boolean mOpaque = true;
+ private boolean mThrottled = false;
+ private static int sUploadedCount;
+ private static final int UPLOAD_LIMIT = 100;
+
+ protected Bitmap mBitmap;
+ private int mBorder;
+
+ protected UploadedTexture() {
+ this(false);
+ }
+
+ protected UploadedTexture(boolean hasBorder) {
+ super(null, 0, STATE_UNLOADED);
+ if (hasBorder) {
+ setBorder(true);
+ mBorder = 1;
+ }
+ }
+
+ protected void setIsUploading(boolean uploading) {
+ mIsUploading = uploading;
+ }
+
+ public boolean isUploading() {
+ return mIsUploading;
+ }
+
+ private static class BorderKey implements Cloneable {
+ public boolean vertical;
+ public Config config;
+ public int length;
+
+ @Override
+ public int hashCode() {
+ int x = config.hashCode() ^ length;
+ return vertical ? x : -x;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof BorderKey)) return false;
+ BorderKey o = (BorderKey) object;
+ return vertical == o.vertical
+ && config == o.config && length == o.length;
+ }
+
+ @Override
+ public BorderKey clone() {
+ try {
+ return (BorderKey) super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
+ }
+
+ protected void setThrottled(boolean throttled) {
+ mThrottled = throttled;
+ }
+
+ private static Bitmap getBorderLine(
+ boolean vertical, Config config, int length) {
+ BorderKey key = sBorderKey;
+ key.vertical = vertical;
+ key.config = config;
+ key.length = length;
+ Bitmap bitmap = sBorderLines.get(key);
+ if (bitmap == null) {
+ bitmap = vertical
+ ? Bitmap.createBitmap(1, length, config)
+ : Bitmap.createBitmap(length, 1, config);
+ sBorderLines.put(key.clone(), bitmap);
+ }
+ return bitmap;
+ }
+
+ private Bitmap getBitmap() {
+ if (mBitmap == null) {
+ mBitmap = onGetBitmap();
+ int w = mBitmap.getWidth() + mBorder * 2;
+ int h = mBitmap.getHeight() + mBorder * 2;
+ if (mWidth == UNSPECIFIED) {
+ setSize(w, h);
+ }
+ }
+ return mBitmap;
+ }
+
+ private void freeBitmap() {
+ Assert.assertTrue(mBitmap != null);
+ onFreeBitmap(mBitmap);
+ mBitmap = null;
+ }
+
+ @Override
+ public int getWidth() {
+ if (mWidth == UNSPECIFIED) getBitmap();
+ return mWidth;
+ }
+
+ @Override
+ public int getHeight() {
+ if (mWidth == UNSPECIFIED) getBitmap();
+ return mHeight;
+ }
+
+ protected abstract Bitmap onGetBitmap();
+
+ protected abstract void onFreeBitmap(Bitmap bitmap);
+
+ protected void invalidateContent() {
+ if (mBitmap != null) freeBitmap();
+ mContentValid = false;
+ mWidth = UNSPECIFIED;
+ mHeight = UNSPECIFIED;
+ }
+
+ /**
+ * Whether the content on GPU is valid.
+ */
+ public boolean isContentValid() {
+ return isLoaded() && mContentValid;
+ }
+
+ /**
+ * Updates the content on GPU's memory.
+ * @param canvas
+ */
+ public void updateContent(GLCanvas canvas) {
+ if (!isLoaded()) {
+ if (mThrottled && ++sUploadedCount > UPLOAD_LIMIT) {
+ return;
+ }
+ uploadToCanvas(canvas);
+ } else if (!mContentValid) {
+ Bitmap bitmap = getBitmap();
+ int format = GLUtils.getInternalFormat(bitmap);
+ int type = GLUtils.getType(bitmap);
+ canvas.texSubImage2D(this, mBorder, mBorder, bitmap, format, type);
+ freeBitmap();
+ mContentValid = true;
+ }
+ }
+
+ public static void resetUploadLimit() {
+ sUploadedCount = 0;
+ }
+
+ public static boolean uploadLimitReached() {
+ return sUploadedCount > UPLOAD_LIMIT;
+ }
+
+ private void uploadToCanvas(GLCanvas canvas) {
+
+ Bitmap bitmap = getBitmap();
+ if (bitmap != null) {
+ try {
+ int bWidth = bitmap.getWidth();
+ int bHeight = bitmap.getHeight();
+ int width = bWidth + mBorder * 2;
+ int height = bHeight + mBorder * 2;
+ int texWidth = getTextureWidth();
+ int texHeight = getTextureHeight();
+
+ Assert.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
+
+ // Upload the bitmap to a new texture.
+ mId = canvas.getGLId().generateTexture();
+ canvas.setTextureParameters(this);
+
+ if (bWidth == texWidth && bHeight == texHeight) {
+ canvas.initializeTexture(this, bitmap);
+ } else {
+ int format = GLUtils.getInternalFormat(bitmap);
+ int type = GLUtils.getType(bitmap);
+ Config config = bitmap.getConfig();
+
+ canvas.initializeTextureSize(this, format, type);
+ canvas.texSubImage2D(this, mBorder, mBorder, bitmap, format, type);
+
+ if (mBorder > 0) {
+ // Left border
+ Bitmap line = getBorderLine(true, config, texHeight);
+ canvas.texSubImage2D(this, 0, 0, line, format, type);
+
+ // Top border
+ line = getBorderLine(false, config, texWidth);
+ canvas.texSubImage2D(this, 0, 0, line, format, type);
+ }
+
+ // Right border
+ if (mBorder + bWidth < texWidth) {
+ Bitmap line = getBorderLine(true, config, texHeight);
+ canvas.texSubImage2D(this, mBorder + bWidth, 0, line, format, type);
+ }
+
+ // Bottom border
+ if (mBorder + bHeight < texHeight) {
+ Bitmap line = getBorderLine(false, config, texWidth);
+ canvas.texSubImage2D(this, 0, mBorder + bHeight, line, format, type);
+ }
+ }
+ } finally {
+ freeBitmap();
+ }
+ // Update texture state.
+ setAssociatedCanvas(canvas);
+ mState = STATE_LOADED;
+ mContentValid = true;
+ } else {
+ mState = STATE_ERROR;
+ throw new RuntimeException("Texture load fail, no bitmap");
+ }
+ }
+
+ @Override
+ protected boolean onBind(GLCanvas canvas) {
+ updateContent(canvas);
+ return isContentValid();
+ }
+
+ @Override
+ protected int getTarget() {
+ return GL11.GL_TEXTURE_2D;
+ }
+
+ public void setOpaque(boolean isOpaque) {
+ mOpaque = isOpaque;
+ }
+
+ @Override
+ public boolean isOpaque() {
+ return mOpaque;
+ }
+
+ @Override
+ public void recycle() {
+ super.recycle();
+ if (mBitmap != null) freeBitmap();
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/util/IntArray.java b/packages/WallpaperCropper/src/com/android/gallery3d/util/IntArray.java
new file mode 100644
index 0000000..2c4dc2c
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/util/IntArray.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.util;
+
+public class IntArray {
+ private static final int INIT_CAPACITY = 8;
+
+ private int mData[] = new int[INIT_CAPACITY];
+ private int mSize = 0;
+
+ public void add(int value) {
+ if (mData.length == mSize) {
+ int temp[] = new int[mSize + mSize];
+ System.arraycopy(mData, 0, temp, 0, mSize);
+ mData = temp;
+ }
+ mData[mSize++] = value;
+ }
+
+ public int removeLast() {
+ mSize--;
+ return mData[mSize];
+ }
+
+ public int size() {
+ return mSize;
+ }
+
+ // For testing only
+ public int[] toArray(int[] result) {
+ if (result == null || result.length < mSize) {
+ result = new int[mSize];
+ }
+ System.arraycopy(mData, 0, result, 0, mSize);
+ return result;
+ }
+
+ public int[] getInternalArray() {
+ return mData;
+ }
+
+ public void clear() {
+ mSize = 0;
+ if (mData.length != INIT_CAPACITY) mData = new int[INIT_CAPACITY];
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java b/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java
new file mode 100644
index 0000000..5f64018
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.photos;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
+import android.util.Log;
+
+import com.android.gallery3d.common.BitmapUtils;
+import com.android.gallery3d.glrenderer.BasicTexture;
+import com.android.gallery3d.glrenderer.BitmapTexture;
+import com.android.photos.views.TiledImageRenderer;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A {@link com.android.photos.views.TiledImageRenderer.TileSource} using
+ * {@link BitmapRegionDecoder} to wrap a local file
+ */
+@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
+public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
+
+ private static final String TAG = "BitmapRegionTileSource";
+
+ private static final boolean REUSE_BITMAP =
+ Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN;
+ private static final int GL_SIZE_LIMIT = 2048;
+ // This must be no larger than half the size of the GL_SIZE_LIMIT
+ // due to decodePreview being allowed to be up to 2x the size of the target
+ private static final int MAX_PREVIEW_SIZE = 1024;
+
+ BitmapRegionDecoder mDecoder;
+ int mWidth;
+ int mHeight;
+ int mTileSize;
+ private BasicTexture mPreview;
+ private final int mRotation;
+
+ // For use only by getTile
+ private Rect mWantRegion = new Rect();
+ private Rect mOverlapRegion = new Rect();
+ private BitmapFactory.Options mOptions;
+ private Canvas mCanvas;
+
+ public BitmapRegionTileSource(Context context, String path, int previewSize, int rotation) {
+ this(null, context, path, null, 0, previewSize, rotation);
+ }
+
+ public BitmapRegionTileSource(Context context, Uri uri, int previewSize, int rotation) {
+ this(null, context, null, uri, 0, previewSize, rotation);
+ }
+
+ public BitmapRegionTileSource(Resources res,
+ Context context, int resId, int previewSize, int rotation) {
+ this(res, context, null, null, resId, previewSize, rotation);
+ }
+
+ private BitmapRegionTileSource(Resources res,
+ Context context, String path, Uri uri, int resId, int previewSize, int rotation) {
+ mTileSize = TiledImageRenderer.suggestedTileSize(context);
+ mRotation = rotation;
+ try {
+ if (path != null) {
+ mDecoder = BitmapRegionDecoder.newInstance(path, true);
+ } else if (uri != null) {
+ InputStream is = context.getContentResolver().openInputStream(uri);
+ BufferedInputStream bis = new BufferedInputStream(is);
+ mDecoder = BitmapRegionDecoder.newInstance(bis, true);
+ } else {
+ InputStream is = res.openRawResource(resId);
+ BufferedInputStream bis = new BufferedInputStream(is);
+ mDecoder = BitmapRegionDecoder.newInstance(bis, true);
+ }
+ mWidth = mDecoder.getWidth();
+ mHeight = mDecoder.getHeight();
+ } catch (IOException e) {
+ Log.w("BitmapRegionTileSource", "ctor failed", e);
+ }
+ mOptions = new BitmapFactory.Options();
+ mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ mOptions.inPreferQualityOverSpeed = true;
+ mOptions.inTempStorage = new byte[16 * 1024];
+ if (previewSize != 0) {
+ previewSize = Math.min(previewSize, MAX_PREVIEW_SIZE);
+ // Although this is the same size as the Bitmap that is likely already
+ // loaded, the lifecycle is different and interactions are on a different
+ // thread. Thus to simplify, this source will decode its own bitmap.
+ Bitmap preview = decodePreview(res, context, path, uri, resId, previewSize);
+ if (preview.getWidth() <= GL_SIZE_LIMIT && preview.getHeight() <= GL_SIZE_LIMIT) {
+ mPreview = new BitmapTexture(preview);
+ } else {
+ Log.w(TAG, String.format(
+ "Failed to create preview of apropriate size! "
+ + " in: %dx%d, out: %dx%d",
+ mWidth, mHeight,
+ preview.getWidth(), preview.getHeight()));
+ }
+ }
+ }
+
+ @Override
+ public int getTileSize() {
+ return mTileSize;
+ }
+
+ @Override
+ public int getImageWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getImageHeight() {
+ return mHeight;
+ }
+
+ @Override
+ public BasicTexture getPreview() {
+ return mPreview;
+ }
+
+ @Override
+ public int getRotation() {
+ return mRotation;
+ }
+
+ @Override
+ public Bitmap getTile(int level, int x, int y, Bitmap bitmap) {
+ int tileSize = getTileSize();
+ if (!REUSE_BITMAP) {
+ return getTileWithoutReusingBitmap(level, x, y, tileSize);
+ }
+
+ int t = tileSize << level;
+ mWantRegion.set(x, y, x + t, y + t);
+
+ if (bitmap == null) {
+ bitmap = Bitmap.createBitmap(tileSize, tileSize, Bitmap.Config.ARGB_8888);
+ }
+
+ mOptions.inSampleSize = (1 << level);
+ mOptions.inBitmap = bitmap;
+
+ try {
+ bitmap = mDecoder.decodeRegion(mWantRegion, mOptions);
+ } finally {
+ if (mOptions.inBitmap != bitmap && mOptions.inBitmap != null) {
+ mOptions.inBitmap = null;
+ }
+ }
+
+ if (bitmap == null) {
+ Log.w("BitmapRegionTileSource", "fail in decoding region");
+ }
+ return bitmap;
+ }
+
+ private Bitmap getTileWithoutReusingBitmap(
+ int level, int x, int y, int tileSize) {
+
+ int t = tileSize << level;
+ mWantRegion.set(x, y, x + t, y + t);
+
+ mOverlapRegion.set(0, 0, mWidth, mHeight);
+
+ mOptions.inSampleSize = (1 << level);
+ Bitmap bitmap = mDecoder.decodeRegion(mOverlapRegion, mOptions);
+
+ if (bitmap == null) {
+ Log.w(TAG, "fail in decoding region");
+ }
+
+ if (mWantRegion.equals(mOverlapRegion)) {
+ return bitmap;
+ }
+
+ Bitmap result = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888);
+ if (mCanvas == null) {
+ mCanvas = new Canvas();
+ }
+ mCanvas.setBitmap(result);
+ mCanvas.drawBitmap(bitmap,
+ (mOverlapRegion.left - mWantRegion.left) >> level,
+ (mOverlapRegion.top - mWantRegion.top) >> level, null);
+ mCanvas.setBitmap(null);
+ return result;
+ }
+
+ /**
+ * Note that the returned bitmap may have a long edge that's longer
+ * than the targetSize, but it will always be less than 2x the targetSize
+ */
+ private Bitmap decodePreview(
+ Resources res, Context context, String file, Uri uri, int resId, int targetSize) {
+ float scale = (float) targetSize / Math.max(mWidth, mHeight);
+ mOptions.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale);
+ mOptions.inJustDecodeBounds = false;
+
+ Bitmap result = null;
+ if (file != null) {
+ result = BitmapFactory.decodeFile(file, mOptions);
+ } else if (uri != null) {
+ try {
+ InputStream is = context.getContentResolver().openInputStream(uri);
+ BufferedInputStream bis = new BufferedInputStream(is);
+ result = BitmapFactory.decodeStream(bis, null, mOptions);
+ } catch (IOException e) {
+ Log.w("BitmapRegionTileSource", "getting preview failed", e);
+ }
+ } else {
+ result = BitmapFactory.decodeResource(res, resId, mOptions);
+ }
+ if (result == null) {
+ return null;
+ }
+
+ // We need to resize down if the decoder does not support inSampleSize
+ // or didn't support the specified inSampleSize (some decoders only do powers of 2)
+ scale = (float) targetSize / (float) (Math.max(result.getWidth(), result.getHeight()));
+
+ if (scale <= 0.5) {
+ result = BitmapUtils.resizeBitmapByScale(result, scale, true);
+ }
+ return ensureGLCompatibleBitmap(result);
+ }
+
+ private static Bitmap ensureGLCompatibleBitmap(Bitmap bitmap) {
+ if (bitmap == null || bitmap.getConfig() != null) {
+ return bitmap;
+ }
+ Bitmap newBitmap = bitmap.copy(Config.ARGB_8888, false);
+ bitmap.recycle();
+ return newBitmap;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/BlockingGLTextureView.java b/packages/WallpaperCropper/src/com/android/photos/views/BlockingGLTextureView.java
new file mode 100644
index 0000000..8a05051
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/photos/views/BlockingGLTextureView.java
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.photos.views;
+
+import android.content.Context;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLSurfaceView.Renderer;
+import android.opengl.GLUtils;
+import android.util.Log;
+import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * A TextureView that supports blocking rendering for synchronous drawing
+ */
+public class BlockingGLTextureView extends TextureView
+ implements SurfaceTextureListener {
+
+ private RenderThread mRenderThread;
+
+ public BlockingGLTextureView(Context context) {
+ super(context);
+ setSurfaceTextureListener(this);
+ }
+
+ public void setRenderer(Renderer renderer) {
+ if (mRenderThread != null) {
+ throw new IllegalArgumentException("Renderer already set");
+ }
+ mRenderThread = new RenderThread(renderer);
+ }
+
+ public void render() {
+ mRenderThread.render();
+ }
+
+ public void destroy() {
+ if (mRenderThread != null) {
+ mRenderThread.finish();
+ mRenderThread = null;
+ }
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
+ int height) {
+ mRenderThread.setSurface(surface);
+ mRenderThread.setSize(width, height);
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,
+ int height) {
+ mRenderThread.setSize(width, height);
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ if (mRenderThread != null) {
+ mRenderThread.setSurface(null);
+ }
+ return false;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ destroy();
+ } catch (Throwable t) {
+ // Ignore
+ }
+ super.finalize();
+ }
+
+ /**
+ * An EGL helper class.
+ */
+
+ private static class EglHelper {
+ private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ private static final int EGL_OPENGL_ES2_BIT = 4;
+
+ EGL10 mEgl;
+ EGLDisplay mEglDisplay;
+ EGLSurface mEglSurface;
+ EGLConfig mEglConfig;
+ EGLContext mEglContext;
+
+ private EGLConfig chooseEglConfig() {
+ int[] configsCount = new int[1];
+ EGLConfig[] configs = new EGLConfig[1];
+ int[] configSpec = getConfig();
+ if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
+ throw new IllegalArgumentException("eglChooseConfig failed " +
+ GLUtils.getEGLErrorString(mEgl.eglGetError()));
+ } else if (configsCount[0] > 0) {
+ return configs[0];
+ }
+ return null;
+ }
+
+ private static int[] getConfig() {
+ return new int[] {
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_RED_SIZE, 8,
+ EGL10.EGL_GREEN_SIZE, 8,
+ EGL10.EGL_BLUE_SIZE, 8,
+ EGL10.EGL_ALPHA_SIZE, 8,
+ EGL10.EGL_DEPTH_SIZE, 0,
+ EGL10.EGL_STENCIL_SIZE, 0,
+ EGL10.EGL_NONE
+ };
+ }
+
+ EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+ int[] attribList = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+ return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attribList);
+ }
+
+ /**
+ * Initialize EGL for a given configuration spec.
+ */
+ public void start() {
+ /*
+ * Get an EGL instance
+ */
+ mEgl = (EGL10) EGLContext.getEGL();
+
+ /*
+ * Get to the default display.
+ */
+ mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+
+ if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
+ throw new RuntimeException("eglGetDisplay failed");
+ }
+
+ /*
+ * We can now initialize EGL for that display
+ */
+ int[] version = new int[2];
+ if (!mEgl.eglInitialize(mEglDisplay, version)) {
+ throw new RuntimeException("eglInitialize failed");
+ }
+ mEglConfig = chooseEglConfig();
+
+ /*
+ * Create an EGL context. We want to do this as rarely as we can, because an
+ * EGL context is a somewhat heavy object.
+ */
+ mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+
+ if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
+ mEglContext = null;
+ throwEglException("createContext");
+ }
+
+ mEglSurface = null;
+ }
+
+ /**
+ * Create an egl surface for the current SurfaceTexture surface. If a surface
+ * already exists, destroy it before creating the new surface.
+ *
+ * @return true if the surface was created successfully.
+ */
+ public boolean createSurface(SurfaceTexture surface) {
+ /*
+ * Check preconditions.
+ */
+ if (mEgl == null) {
+ throw new RuntimeException("egl not initialized");
+ }
+ if (mEglDisplay == null) {
+ throw new RuntimeException("eglDisplay not initialized");
+ }
+ if (mEglConfig == null) {
+ throw new RuntimeException("mEglConfig not initialized");
+ }
+
+ /*
+ * The window size has changed, so we need to create a new
+ * surface.
+ */
+ destroySurfaceImp();
+
+ /*
+ * Create an EGL surface we can render into.
+ */
+ if (surface != null) {
+ mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surface, null);
+ } else {
+ mEglSurface = null;
+ }
+
+ if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
+ int error = mEgl.eglGetError();
+ if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
+ Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+ }
+ return false;
+ }
+
+ /*
+ * Before we can issue GL commands, we need to make sure
+ * the context is current and bound to a surface.
+ */
+ if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+ /*
+ * Could not make the context current, probably because the underlying
+ * SurfaceView surface has been destroyed.
+ */
+ logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Create a GL object for the current EGL context.
+ */
+ public GL10 createGL() {
+ return (GL10) mEglContext.getGL();
+ }
+
+ /**
+ * Display the current render surface.
+ * @return the EGL error code from eglSwapBuffers.
+ */
+ public int swap() {
+ if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
+ return mEgl.eglGetError();
+ }
+ return EGL10.EGL_SUCCESS;
+ }
+
+ public void destroySurface() {
+ destroySurfaceImp();
+ }
+
+ private void destroySurfaceImp() {
+ if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
+ mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
+ EGL10.EGL_NO_SURFACE,
+ EGL10.EGL_NO_CONTEXT);
+ mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+ mEglSurface = null;
+ }
+ }
+
+ public void finish() {
+ if (mEglContext != null) {
+ mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+ mEglContext = null;
+ }
+ if (mEglDisplay != null) {
+ mEgl.eglTerminate(mEglDisplay);
+ mEglDisplay = null;
+ }
+ }
+
+ private void throwEglException(String function) {
+ throwEglException(function, mEgl.eglGetError());
+ }
+
+ public static void throwEglException(String function, int error) {
+ String message = formatEglError(function, error);
+ throw new RuntimeException(message);
+ }
+
+ public static void logEglErrorAsWarning(String tag, String function, int error) {
+ Log.w(tag, formatEglError(function, error));
+ }
+
+ public static String formatEglError(String function, int error) {
+ return function + " failed: " + error;
+ }
+
+ }
+
+ private static class RenderThread extends Thread {
+ private static final int INVALID = -1;
+ private static final int RENDER = 1;
+ private static final int CHANGE_SURFACE = 2;
+ private static final int RESIZE_SURFACE = 3;
+ private static final int FINISH = 4;
+
+ private EglHelper mEglHelper = new EglHelper();
+
+ private Object mLock = new Object();
+ private int mExecMsgId = INVALID;
+ private SurfaceTexture mSurface;
+ private Renderer mRenderer;
+ private int mWidth, mHeight;
+
+ private boolean mFinished = false;
+ private GL10 mGL;
+
+ public RenderThread(Renderer renderer) {
+ super("RenderThread");
+ mRenderer = renderer;
+ start();
+ }
+
+ private void checkRenderer() {
+ if (mRenderer == null) {
+ throw new IllegalArgumentException("Renderer is null!");
+ }
+ }
+
+ private void checkSurface() {
+ if (mSurface == null) {
+ throw new IllegalArgumentException("surface is null!");
+ }
+ }
+
+ public void setSurface(SurfaceTexture surface) {
+ // If the surface is null we're being torn down, don't need a
+ // renderer then
+ if (surface != null) {
+ checkRenderer();
+ }
+ mSurface = surface;
+ exec(CHANGE_SURFACE);
+ }
+
+ public void setSize(int width, int height) {
+ checkRenderer();
+ checkSurface();
+ mWidth = width;
+ mHeight = height;
+ exec(RESIZE_SURFACE);
+ }
+
+ public void render() {
+ checkRenderer();
+ if (mSurface != null) {
+ exec(RENDER);
+ mSurface.updateTexImage();
+ }
+ }
+
+ public void finish() {
+ mSurface = null;
+ exec(FINISH);
+ try {
+ join();
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+
+ private void exec(int msgid) {
+ synchronized (mLock) {
+ if (mExecMsgId != INVALID) {
+ throw new IllegalArgumentException(
+ "Message already set - multithreaded access?");
+ }
+ mExecMsgId = msgid;
+ mLock.notify();
+ try {
+ mLock.wait();
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ }
+
+ private void handleMessageLocked(int what) {
+ switch (what) {
+ case CHANGE_SURFACE:
+ if (mEglHelper.createSurface(mSurface)) {
+ mGL = mEglHelper.createGL();
+ mRenderer.onSurfaceCreated(mGL, mEglHelper.mEglConfig);
+ }
+ break;
+ case RESIZE_SURFACE:
+ mRenderer.onSurfaceChanged(mGL, mWidth, mHeight);
+ break;
+ case RENDER:
+ mRenderer.onDrawFrame(mGL);
+ mEglHelper.swap();
+ break;
+ case FINISH:
+ mEglHelper.destroySurface();
+ mEglHelper.finish();
+ mFinished = true;
+ break;
+ }
+ }
+
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ mEglHelper.start();
+ while (!mFinished) {
+ while (mExecMsgId == INVALID) {
+ try {
+ mLock.wait();
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ handleMessageLocked(mExecMsgId);
+ mExecMsgId = INVALID;
+ mLock.notify();
+ }
+ mExecMsgId = FINISH;
+ }
+ }
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
new file mode 100644
index 0000000..c4e493b
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
@@ -0,0 +1,825 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.photos.views;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.support.v4.util.LongSparseArray;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.Pools.Pool;
+import android.util.Pools.SynchronizedPool;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.glrenderer.BasicTexture;
+import com.android.gallery3d.glrenderer.GLCanvas;
+import com.android.gallery3d.glrenderer.UploadedTexture;
+
+/**
+ * Handles laying out, decoding, and drawing of tiles in GL
+ */
+public class TiledImageRenderer {
+ public static final int SIZE_UNKNOWN = -1;
+
+ private static final String TAG = "TiledImageRenderer";
+ private static final int UPLOAD_LIMIT = 1;
+
+ /*
+ * This is the tile state in the CPU side.
+ * Life of a Tile:
+ * ACTIVATED (initial state)
+ * --> IN_QUEUE - by queueForDecode()
+ * --> RECYCLED - by recycleTile()
+ * IN_QUEUE --> DECODING - by decodeTile()
+ * --> RECYCLED - by recycleTile)
+ * DECODING --> RECYCLING - by recycleTile()
+ * --> DECODED - by decodeTile()
+ * --> DECODE_FAIL - by decodeTile()
+ * RECYCLING --> RECYCLED - by decodeTile()
+ * DECODED --> ACTIVATED - (after the decoded bitmap is uploaded)
+ * DECODED --> RECYCLED - by recycleTile()
+ * DECODE_FAIL -> RECYCLED - by recycleTile()
+ * RECYCLED --> ACTIVATED - by obtainTile()
+ */
+ private static final int STATE_ACTIVATED = 0x01;
+ private static final int STATE_IN_QUEUE = 0x02;
+ private static final int STATE_DECODING = 0x04;
+ private static final int STATE_DECODED = 0x08;
+ private static final int STATE_DECODE_FAIL = 0x10;
+ private static final int STATE_RECYCLING = 0x20;
+ private static final int STATE_RECYCLED = 0x40;
+
+ private static Pool<Bitmap> sTilePool = new SynchronizedPool<Bitmap>(64);
+
+ // TILE_SIZE must be 2^N
+ private int mTileSize;
+
+ private TileSource mModel;
+ private BasicTexture mPreview;
+ protected int mLevelCount; // cache the value of mScaledBitmaps.length
+
+ // The mLevel variable indicates which level of bitmap we should use.
+ // Level 0 means the original full-sized bitmap, and a larger value means
+ // a smaller scaled bitmap (The width and height of each scaled bitmap is
+ // half size of the previous one). If the value is in [0, mLevelCount), we
+ // use the bitmap in mScaledBitmaps[mLevel] for display, otherwise the value
+ // is mLevelCount
+ private int mLevel = 0;
+
+ private int mOffsetX;
+ private int mOffsetY;
+
+ private int mUploadQuota;
+ private boolean mRenderComplete;
+
+ private final RectF mSourceRect = new RectF();
+ private final RectF mTargetRect = new RectF();
+
+ private final LongSparseArray<Tile> mActiveTiles = new LongSparseArray<Tile>();
+
+ // The following three queue are guarded by mQueueLock
+ private final Object mQueueLock = new Object();
+ private final TileQueue mRecycledQueue = new TileQueue();
+ private final TileQueue mUploadQueue = new TileQueue();
+ private final TileQueue mDecodeQueue = new TileQueue();
+
+ // The width and height of the full-sized bitmap
+ protected int mImageWidth = SIZE_UNKNOWN;
+ protected int mImageHeight = SIZE_UNKNOWN;
+
+ protected int mCenterX;
+ protected int mCenterY;
+ protected float mScale;
+ protected int mRotation;
+
+ private boolean mLayoutTiles;
+
+ // Temp variables to avoid memory allocation
+ private final Rect mTileRange = new Rect();
+ private final Rect mActiveRange[] = {new Rect(), new Rect()};
+
+ private TileDecoder mTileDecoder;
+ private boolean mBackgroundTileUploaded;
+
+ private int mViewWidth, mViewHeight;
+ private View mParent;
+
+ /**
+ * Interface for providing tiles to a {@link TiledImageRenderer}
+ */
+ public static interface TileSource {
+
+ /**
+ * If the source does not care about the tile size, it should use
+ * {@link TiledImageRenderer#suggestedTileSize(Context)}
+ */
+ public int getTileSize();
+ public int getImageWidth();
+ public int getImageHeight();
+ public int getRotation();
+
+ /**
+ * Return a Preview image if available. This will be used as the base layer
+ * if higher res tiles are not yet available
+ */
+ public BasicTexture getPreview();
+
+ /**
+ * The tile returned by this method can be specified this way: Assuming
+ * the image size is (width, height), first take the intersection of (0,
+ * 0) - (width, height) and (x, y) - (x + tileSize, y + tileSize). If
+ * in extending the region, we found some part of the region is outside
+ * the image, those pixels are filled with black.
+ *
+ * If level > 0, it does the same operation on a down-scaled version of
+ * the original image (down-scaled by a factor of 2^level), but (x, y)
+ * still refers to the coordinate on the original image.
+ *
+ * The method would be called by the decoder thread.
+ */
+ public Bitmap getTile(int level, int x, int y, Bitmap reuse);
+ }
+
+ public static int suggestedTileSize(Context context) {
+ return isHighResolution(context) ? 512 : 256;
+ }
+
+ private static boolean isHighResolution(Context context) {
+ DisplayMetrics metrics = new DisplayMetrics();
+ WindowManager wm = (WindowManager)
+ context.getSystemService(Context.WINDOW_SERVICE);
+ wm.getDefaultDisplay().getMetrics(metrics);
+ return metrics.heightPixels > 2048 || metrics.widthPixels > 2048;
+ }
+
+ public TiledImageRenderer(View parent) {
+ mParent = parent;
+ mTileDecoder = new TileDecoder();
+ mTileDecoder.start();
+ }
+
+ public int getViewWidth() {
+ return mViewWidth;
+ }
+
+ public int getViewHeight() {
+ return mViewHeight;
+ }
+
+ private void invalidate() {
+ mParent.postInvalidate();
+ }
+
+ public void setModel(TileSource model, int rotation) {
+ if (mModel != model) {
+ mModel = model;
+ notifyModelInvalidated();
+ }
+ if (mRotation != rotation) {
+ mRotation = rotation;
+ mLayoutTiles = true;
+ }
+ }
+
+ private void calculateLevelCount() {
+ if (mPreview != null) {
+ mLevelCount = Math.max(0, Utils.ceilLog2(
+ mImageWidth / (float) mPreview.getWidth()));
+ } else {
+ int levels = 1;
+ int maxDim = Math.max(mImageWidth, mImageHeight);
+ int t = mTileSize;
+ while (t < maxDim) {
+ t <<= 1;
+ levels++;
+ }
+ mLevelCount = levels;
+ }
+ }
+
+ public void notifyModelInvalidated() {
+ invalidateTiles();
+ if (mModel == null) {
+ mImageWidth = 0;
+ mImageHeight = 0;
+ mLevelCount = 0;
+ mPreview = null;
+ } else {
+ mImageWidth = mModel.getImageWidth();
+ mImageHeight = mModel.getImageHeight();
+ mPreview = mModel.getPreview();
+ mTileSize = mModel.getTileSize();
+ calculateLevelCount();
+ }
+ mLayoutTiles = true;
+ }
+
+ public void setViewSize(int width, int height) {
+ mViewWidth = width;
+ mViewHeight = height;
+ }
+
+ public void setPosition(int centerX, int centerY, float scale) {
+ if (mCenterX == centerX && mCenterY == centerY
+ && mScale == scale) {
+ return;
+ }
+ mCenterX = centerX;
+ mCenterY = centerY;
+ mScale = scale;
+ mLayoutTiles = true;
+ }
+
+ // Prepare the tiles we want to use for display.
+ //
+ // 1. Decide the tile level we want to use for display.
+ // 2. Decide the tile levels we want to keep as texture (in addition to
+ // the one we use for display).
+ // 3. Recycle unused tiles.
+ // 4. Activate the tiles we want.
+ private void layoutTiles() {
+ if (mViewWidth == 0 || mViewHeight == 0 || !mLayoutTiles) {
+ return;
+ }
+ mLayoutTiles = false;
+
+ // The tile levels we want to keep as texture is in the range
+ // [fromLevel, endLevel).
+ int fromLevel;
+ int endLevel;
+
+ // We want to use a texture larger than or equal to the display size.
+ mLevel = Utils.clamp(Utils.floorLog2(1f / mScale), 0, mLevelCount);
+
+ // We want to keep one more tile level as texture in addition to what
+ // we use for display. So it can be faster when the scale moves to the
+ // next level. We choose the level closest to the current scale.
+ if (mLevel != mLevelCount) {
+ Rect range = mTileRange;
+ getRange(range, mCenterX, mCenterY, mLevel, mScale, mRotation);
+ mOffsetX = Math.round(mViewWidth / 2f + (range.left - mCenterX) * mScale);
+ mOffsetY = Math.round(mViewHeight / 2f + (range.top - mCenterY) * mScale);
+ fromLevel = mScale * (1 << mLevel) > 0.75f ? mLevel - 1 : mLevel;
+ } else {
+ // Activate the tiles of the smallest two levels.
+ fromLevel = mLevel - 2;
+ mOffsetX = Math.round(mViewWidth / 2f - mCenterX * mScale);
+ mOffsetY = Math.round(mViewHeight / 2f - mCenterY * mScale);
+ }
+
+ fromLevel = Math.max(0, Math.min(fromLevel, mLevelCount - 2));
+ endLevel = Math.min(fromLevel + 2, mLevelCount);
+
+ Rect range[] = mActiveRange;
+ for (int i = fromLevel; i < endLevel; ++i) {
+ getRange(range[i - fromLevel], mCenterX, mCenterY, i, mRotation);
+ }
+
+ // If rotation is transient, don't update the tile.
+ if (mRotation % 90 != 0) {
+ return;
+ }
+
+ synchronized (mQueueLock) {
+ mDecodeQueue.clean();
+ mUploadQueue.clean();
+ mBackgroundTileUploaded = false;
+
+ // Recycle unused tiles: if the level of the active tile is outside the
+ // range [fromLevel, endLevel) or not in the visible range.
+ int n = mActiveTiles.size();
+ for (int i = 0; i < n; i++) {
+ Tile tile = mActiveTiles.valueAt(i);
+ int level = tile.mTileLevel;
+ if (level < fromLevel || level >= endLevel
+ || !range[level - fromLevel].contains(tile.mX, tile.mY)) {
+ mActiveTiles.removeAt(i);
+ i--;
+ n--;
+ recycleTile(tile);
+ }
+ }
+ }
+
+ for (int i = fromLevel; i < endLevel; ++i) {
+ int size = mTileSize << i;
+ Rect r = range[i - fromLevel];
+ for (int y = r.top, bottom = r.bottom; y < bottom; y += size) {
+ for (int x = r.left, right = r.right; x < right; x += size) {
+ activateTile(x, y, i);
+ }
+ }
+ }
+ invalidate();
+ }
+
+ private void invalidateTiles() {
+ synchronized (mQueueLock) {
+ mDecodeQueue.clean();
+ mUploadQueue.clean();
+
+ // TODO(xx): disable decoder
+ int n = mActiveTiles.size();
+ for (int i = 0; i < n; i++) {
+ Tile tile = mActiveTiles.valueAt(i);
+ recycleTile(tile);
+ }
+ mActiveTiles.clear();
+ }
+ }
+
+ private void getRange(Rect out, int cX, int cY, int level, int rotation) {
+ getRange(out, cX, cY, level, 1f / (1 << (level + 1)), rotation);
+ }
+
+ // If the bitmap is scaled by the given factor "scale", return the
+ // rectangle containing visible range. The left-top coordinate returned is
+ // aligned to the tile boundary.
+ //
+ // (cX, cY) is the point on the original bitmap which will be put in the
+ // center of the ImageViewer.
+ private void getRange(Rect out,
+ int cX, int cY, int level, float scale, int rotation) {
+
+ double radians = Math.toRadians(-rotation);
+ double w = mViewWidth;
+ double h = mViewHeight;
+
+ double cos = Math.cos(radians);
+ double sin = Math.sin(radians);
+ int width = (int) Math.ceil(Math.max(
+ Math.abs(cos * w - sin * h), Math.abs(cos * w + sin * h)));
+ int height = (int) Math.ceil(Math.max(
+ Math.abs(sin * w + cos * h), Math.abs(sin * w - cos * h)));
+
+ int left = (int) Math.floor(cX - width / (2f * scale));
+ int top = (int) Math.floor(cY - height / (2f * scale));
+ int right = (int) Math.ceil(left + width / scale);
+ int bottom = (int) Math.ceil(top + height / scale);
+
+ // align the rectangle to tile boundary
+ int size = mTileSize << level;
+ left = Math.max(0, size * (left / size));
+ top = Math.max(0, size * (top / size));
+ right = Math.min(mImageWidth, right);
+ bottom = Math.min(mImageHeight, bottom);
+
+ out.set(left, top, right, bottom);
+ }
+
+ public void freeTextures() {
+ mLayoutTiles = true;
+
+ mTileDecoder.finishAndWait();
+ synchronized (mQueueLock) {
+ mUploadQueue.clean();
+ mDecodeQueue.clean();
+ Tile tile = mRecycledQueue.pop();
+ while (tile != null) {
+ tile.recycle();
+ tile = mRecycledQueue.pop();
+ }
+ }
+
+ int n = mActiveTiles.size();
+ for (int i = 0; i < n; i++) {
+ Tile texture = mActiveTiles.valueAt(i);
+ texture.recycle();
+ }
+ mActiveTiles.clear();
+ mTileRange.set(0, 0, 0, 0);
+
+ while (sTilePool.acquire() != null) {}
+ }
+
+ public boolean draw(GLCanvas canvas) {
+ layoutTiles();
+ uploadTiles(canvas);
+
+ mUploadQuota = UPLOAD_LIMIT;
+ mRenderComplete = true;
+
+ int level = mLevel;
+ int rotation = mRotation;
+ int flags = 0;
+ if (rotation != 0) {
+ flags |= GLCanvas.SAVE_FLAG_MATRIX;
+ }
+
+ if (flags != 0) {
+ canvas.save(flags);
+ if (rotation != 0) {
+ int centerX = mViewWidth / 2, centerY = mViewHeight / 2;
+ canvas.translate(centerX, centerY);
+ canvas.rotate(rotation, 0, 0, 1);
+ canvas.translate(-centerX, -centerY);
+ }
+ }
+ try {
+ if (level != mLevelCount) {
+ int size = (mTileSize << level);
+ float length = size * mScale;
+ Rect r = mTileRange;
+
+ for (int ty = r.top, i = 0; ty < r.bottom; ty += size, i++) {
+ float y = mOffsetY + i * length;
+ for (int tx = r.left, j = 0; tx < r.right; tx += size, j++) {
+ float x = mOffsetX + j * length;
+ drawTile(canvas, tx, ty, level, x, y, length);
+ }
+ }
+ } else if (mPreview != null) {
+ mPreview.draw(canvas, mOffsetX, mOffsetY,
+ Math.round(mImageWidth * mScale),
+ Math.round(mImageHeight * mScale));
+ }
+ } finally {
+ if (flags != 0) {
+ canvas.restore();
+ }
+ }
+
+ if (mRenderComplete) {
+ if (!mBackgroundTileUploaded) {
+ uploadBackgroundTiles(canvas);
+ }
+ } else {
+ invalidate();
+ }
+ return mRenderComplete || mPreview != null;
+ }
+
+ private void uploadBackgroundTiles(GLCanvas canvas) {
+ mBackgroundTileUploaded = true;
+ int n = mActiveTiles.size();
+ for (int i = 0; i < n; i++) {
+ Tile tile = mActiveTiles.valueAt(i);
+ if (!tile.isContentValid()) {
+ queueForDecode(tile);
+ }
+ }
+ }
+
+ private void queueForDecode(Tile tile) {
+ synchronized (mQueueLock) {
+ if (tile.mTileState == STATE_ACTIVATED) {
+ tile.mTileState = STATE_IN_QUEUE;
+ if (mDecodeQueue.push(tile)) {
+ mQueueLock.notifyAll();
+ }
+ }
+ }
+ }
+
+ private void decodeTile(Tile tile) {
+ synchronized (mQueueLock) {
+ if (tile.mTileState != STATE_IN_QUEUE) {
+ return;
+ }
+ tile.mTileState = STATE_DECODING;
+ }
+ boolean decodeComplete = tile.decode();
+ synchronized (mQueueLock) {
+ if (tile.mTileState == STATE_RECYCLING) {
+ tile.mTileState = STATE_RECYCLED;
+ if (tile.mDecodedTile != null) {
+ sTilePool.release(tile.mDecodedTile);
+ tile.mDecodedTile = null;
+ }
+ mRecycledQueue.push(tile);
+ return;
+ }
+ tile.mTileState = decodeComplete ? STATE_DECODED : STATE_DECODE_FAIL;
+ if (!decodeComplete) {
+ return;
+ }
+ mUploadQueue.push(tile);
+ }
+ invalidate();
+ }
+
+ private Tile obtainTile(int x, int y, int level) {
+ synchronized (mQueueLock) {
+ Tile tile = mRecycledQueue.pop();
+ if (tile != null) {
+ tile.mTileState = STATE_ACTIVATED;
+ tile.update(x, y, level);
+ return tile;
+ }
+ return new Tile(x, y, level);
+ }
+ }
+
+ private void recycleTile(Tile tile) {
+ synchronized (mQueueLock) {
+ if (tile.mTileState == STATE_DECODING) {
+ tile.mTileState = STATE_RECYCLING;
+ return;
+ }
+ tile.mTileState = STATE_RECYCLED;
+ if (tile.mDecodedTile != null) {
+ sTilePool.release(tile.mDecodedTile);
+ tile.mDecodedTile = null;
+ }
+ mRecycledQueue.push(tile);
+ }
+ }
+
+ private void activateTile(int x, int y, int level) {
+ long key = makeTileKey(x, y, level);
+ Tile tile = mActiveTiles.get(key);
+ if (tile != null) {
+ if (tile.mTileState == STATE_IN_QUEUE) {
+ tile.mTileState = STATE_ACTIVATED;
+ }
+ return;
+ }
+ tile = obtainTile(x, y, level);
+ mActiveTiles.put(key, tile);
+ }
+
+ private Tile getTile(int x, int y, int level) {
+ return mActiveTiles.get(makeTileKey(x, y, level));
+ }
+
+ private static long makeTileKey(int x, int y, int level) {
+ long result = x;
+ result = (result << 16) | y;
+ result = (result << 16) | level;
+ return result;
+ }
+
+ private void uploadTiles(GLCanvas canvas) {
+ int quota = UPLOAD_LIMIT;
+ Tile tile = null;
+ while (quota > 0) {
+ synchronized (mQueueLock) {
+ tile = mUploadQueue.pop();
+ }
+ if (tile == null) {
+ break;
+ }
+ if (!tile.isContentValid()) {
+ if (tile.mTileState == STATE_DECODED) {
+ tile.updateContent(canvas);
+ --quota;
+ } else {
+ Log.w(TAG, "Tile in upload queue has invalid state: " + tile.mTileState);
+ }
+ }
+ }
+ if (tile != null) {
+ invalidate();
+ }
+ }
+
+ // Draw the tile to a square at canvas that locates at (x, y) and
+ // has a side length of length.
+ private void drawTile(GLCanvas canvas,
+ int tx, int ty, int level, float x, float y, float length) {
+ RectF source = mSourceRect;
+ RectF target = mTargetRect;
+ target.set(x, y, x + length, y + length);
+ source.set(0, 0, mTileSize, mTileSize);
+
+ Tile tile = getTile(tx, ty, level);
+ if (tile != null) {
+ if (!tile.isContentValid()) {
+ if (tile.mTileState == STATE_DECODED) {
+ if (mUploadQuota > 0) {
+ --mUploadQuota;
+ tile.updateContent(canvas);
+ } else {
+ mRenderComplete = false;
+ }
+ } else if (tile.mTileState != STATE_DECODE_FAIL){
+ mRenderComplete = false;
+ queueForDecode(tile);
+ }
+ }
+ if (drawTile(tile, canvas, source, target)) {
+ return;
+ }
+ }
+ if (mPreview != null) {
+ int size = mTileSize << level;
+ float scaleX = (float) mPreview.getWidth() / mImageWidth;
+ float scaleY = (float) mPreview.getHeight() / mImageHeight;
+ source.set(tx * scaleX, ty * scaleY, (tx + size) * scaleX,
+ (ty + size) * scaleY);
+ canvas.drawTexture(mPreview, source, target);
+ }
+ }
+
+ private boolean drawTile(
+ Tile tile, GLCanvas canvas, RectF source, RectF target) {
+ while (true) {
+ if (tile.isContentValid()) {
+ canvas.drawTexture(tile, source, target);
+ return true;
+ }
+
+ // Parent can be divided to four quads and tile is one of the four.
+ Tile parent = tile.getParentTile();
+ if (parent == null) {
+ return false;
+ }
+ if (tile.mX == parent.mX) {
+ source.left /= 2f;
+ source.right /= 2f;
+ } else {
+ source.left = (mTileSize + source.left) / 2f;
+ source.right = (mTileSize + source.right) / 2f;
+ }
+ if (tile.mY == parent.mY) {
+ source.top /= 2f;
+ source.bottom /= 2f;
+ } else {
+ source.top = (mTileSize + source.top) / 2f;
+ source.bottom = (mTileSize + source.bottom) / 2f;
+ }
+ tile = parent;
+ }
+ }
+
+ private class Tile extends UploadedTexture {
+ public int mX;
+ public int mY;
+ public int mTileLevel;
+ public Tile mNext;
+ public Bitmap mDecodedTile;
+ public volatile int mTileState = STATE_ACTIVATED;
+
+ public Tile(int x, int y, int level) {
+ mX = x;
+ mY = y;
+ mTileLevel = level;
+ }
+
+ @Override
+ protected void onFreeBitmap(Bitmap bitmap) {
+ sTilePool.release(bitmap);
+ }
+
+ boolean decode() {
+ // Get a tile from the original image. The tile is down-scaled
+ // by (1 << mTilelevel) from a region in the original image.
+ try {
+ Bitmap reuse = sTilePool.acquire();
+ if (reuse != null && reuse.getWidth() != mTileSize) {
+ reuse = null;
+ }
+ mDecodedTile = mModel.getTile(mTileLevel, mX, mY, reuse);
+ } catch (Throwable t) {
+ Log.w(TAG, "fail to decode tile", t);
+ }
+ return mDecodedTile != null;
+ }
+
+ @Override
+ protected Bitmap onGetBitmap() {
+ Utils.assertTrue(mTileState == STATE_DECODED);
+
+ // We need to override the width and height, so that we won't
+ // draw beyond the boundaries.
+ int rightEdge = ((mImageWidth - mX) >> mTileLevel);
+ int bottomEdge = ((mImageHeight - mY) >> mTileLevel);
+ setSize(Math.min(mTileSize, rightEdge), Math.min(mTileSize, bottomEdge));
+
+ Bitmap bitmap = mDecodedTile;
+ mDecodedTile = null;
+ mTileState = STATE_ACTIVATED;
+ return bitmap;
+ }
+
+ // We override getTextureWidth() and getTextureHeight() here, so the
+ // texture can be re-used for different tiles regardless of the actual
+ // size of the tile (which may be small because it is a tile at the
+ // boundary).
+ @Override
+ public int getTextureWidth() {
+ return mTileSize;
+ }
+
+ @Override
+ public int getTextureHeight() {
+ return mTileSize;
+ }
+
+ public void update(int x, int y, int level) {
+ mX = x;
+ mY = y;
+ mTileLevel = level;
+ invalidateContent();
+ }
+
+ public Tile getParentTile() {
+ if (mTileLevel + 1 == mLevelCount) {
+ return null;
+ }
+ int size = mTileSize << (mTileLevel + 1);
+ int x = size * (mX / size);
+ int y = size * (mY / size);
+ return getTile(x, y, mTileLevel + 1);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("tile(%s, %s, %s / %s)",
+ mX / mTileSize, mY / mTileSize, mLevel, mLevelCount);
+ }
+ }
+
+ private static class TileQueue {
+ private Tile mHead;
+
+ public Tile pop() {
+ Tile tile = mHead;
+ if (tile != null) {
+ mHead = tile.mNext;
+ }
+ return tile;
+ }
+
+ public boolean push(Tile tile) {
+ if (contains(tile)) {
+ Log.w(TAG, "Attempting to add a tile already in the queue!");
+ return false;
+ }
+ boolean wasEmpty = mHead == null;
+ tile.mNext = mHead;
+ mHead = tile;
+ return wasEmpty;
+ }
+
+ private boolean contains(Tile tile) {
+ Tile other = mHead;
+ while (other != null) {
+ if (other == tile) {
+ return true;
+ }
+ other = other.mNext;
+ }
+ return false;
+ }
+
+ public void clean() {
+ mHead = null;
+ }
+ }
+
+ private class TileDecoder extends Thread {
+
+ public void finishAndWait() {
+ interrupt();
+ try {
+ join();
+ } catch (InterruptedException e) {
+ Log.w(TAG, "Interrupted while waiting for TileDecoder thread to finish!");
+ }
+ }
+
+ private Tile waitForTile() throws InterruptedException {
+ synchronized (mQueueLock) {
+ while (true) {
+ Tile tile = mDecodeQueue.pop();
+ if (tile != null) {
+ return tile;
+ }
+ mQueueLock.wait();
+ }
+ }
+ }
+
+ @Override
+ public void run() {
+ try {
+ while (!isInterrupted()) {
+ Tile tile = waitForTile();
+ decodeTile(tile);
+ }
+ } catch (InterruptedException ex) {
+ // We were finished
+ }
+ }
+
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java
new file mode 100644
index 0000000..36cb438
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.photos.views;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.RectF;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLSurfaceView.Renderer;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.Choreographer;
+import android.view.Choreographer.FrameCallback;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.gallery3d.glrenderer.BasicTexture;
+import com.android.gallery3d.glrenderer.GLES20Canvas;
+import com.android.photos.views.TiledImageRenderer.TileSource;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * Shows an image using {@link TiledImageRenderer} using either {@link GLSurfaceView}
+ * or {@link BlockingGLTextureView}.
+ */
+public class TiledImageView extends FrameLayout {
+
+ private static final boolean USE_TEXTURE_VIEW = false;
+ private static final boolean IS_SUPPORTED =
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
+ private static final boolean USE_CHOREOGRAPHER =
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
+
+ private BlockingGLTextureView mTextureView;
+ private GLSurfaceView mGLSurfaceView;
+ private boolean mInvalPending = false;
+ private FrameCallback mFrameCallback;
+
+ protected static class ImageRendererWrapper {
+ // Guarded by locks
+ public float scale;
+ public int centerX, centerY;
+ int rotation;
+ public TileSource source;
+ Runnable isReadyCallback;
+
+ // GL thread only
+ TiledImageRenderer image;
+ }
+
+ private float[] mValues = new float[9];
+
+ // -------------------------
+ // Guarded by mLock
+ // -------------------------
+ protected Object mLock = new Object();
+ protected ImageRendererWrapper mRenderer;
+
+ public static boolean isTilingSupported() {
+ return IS_SUPPORTED;
+ }
+
+ public TiledImageView(Context context) {
+ this(context, null);
+ }
+
+ public TiledImageView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ if (!IS_SUPPORTED) {
+ return;
+ }
+
+ mRenderer = new ImageRendererWrapper();
+ mRenderer.image = new TiledImageRenderer(this);
+ View view;
+ if (USE_TEXTURE_VIEW) {
+ mTextureView = new BlockingGLTextureView(context);
+ mTextureView.setRenderer(new TileRenderer());
+ view = mTextureView;
+ } else {
+ mGLSurfaceView = new GLSurfaceView(context);
+ mGLSurfaceView.setEGLContextClientVersion(2);
+ mGLSurfaceView.setRenderer(new TileRenderer());
+ mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+ view = mGLSurfaceView;
+ }
+ addView(view, new LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ //setTileSource(new ColoredTiles());
+ }
+
+ public void destroy() {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ if (USE_TEXTURE_VIEW) {
+ mTextureView.destroy();
+ } else {
+ mGLSurfaceView.queueEvent(mFreeTextures);
+ }
+ }
+
+ private Runnable mFreeTextures = new Runnable() {
+
+ @Override
+ public void run() {
+ mRenderer.image.freeTextures();
+ }
+ };
+
+ public void onPause() {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ if (!USE_TEXTURE_VIEW) {
+ mGLSurfaceView.onPause();
+ }
+ }
+
+ public void onResume() {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ if (!USE_TEXTURE_VIEW) {
+ mGLSurfaceView.onResume();
+ }
+ }
+
+ public void setTileSource(TileSource source, Runnable isReadyCallback) {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ synchronized (mLock) {
+ mRenderer.source = source;
+ mRenderer.isReadyCallback = isReadyCallback;
+ mRenderer.centerX = source != null ? source.getImageWidth() / 2 : 0;
+ mRenderer.centerY = source != null ? source.getImageHeight() / 2 : 0;
+ mRenderer.rotation = source != null ? source.getRotation() : 0;
+ mRenderer.scale = 0;
+ updateScaleIfNecessaryLocked(mRenderer);
+ }
+ invalidate();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right,
+ int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ synchronized (mLock) {
+ updateScaleIfNecessaryLocked(mRenderer);
+ }
+ }
+
+ private void updateScaleIfNecessaryLocked(ImageRendererWrapper renderer) {
+ if (renderer == null || renderer.source == null
+ || renderer.scale > 0 || getWidth() == 0) {
+ return;
+ }
+ renderer.scale = Math.min(
+ (float) getWidth() / (float) renderer.source.getImageWidth(),
+ (float) getHeight() / (float) renderer.source.getImageHeight());
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ if (USE_TEXTURE_VIEW) {
+ mTextureView.render();
+ }
+ super.dispatchDraw(canvas);
+ }
+
+ @SuppressLint("NewApi")
+ @Override
+ public void setTranslationX(float translationX) {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ super.setTranslationX(translationX);
+ }
+
+ @Override
+ public void invalidate() {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ if (USE_TEXTURE_VIEW) {
+ super.invalidate();
+ mTextureView.invalidate();
+ } else {
+ if (USE_CHOREOGRAPHER) {
+ invalOnVsync();
+ } else {
+ mGLSurfaceView.requestRender();
+ }
+ }
+ }
+
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+ private void invalOnVsync() {
+ if (!mInvalPending) {
+ mInvalPending = true;
+ if (mFrameCallback == null) {
+ mFrameCallback = new FrameCallback() {
+ @Override
+ public void doFrame(long frameTimeNanos) {
+ mInvalPending = false;
+ mGLSurfaceView.requestRender();
+ }
+ };
+ }
+ Choreographer.getInstance().postFrameCallback(mFrameCallback);
+ }
+ }
+
+ private RectF mTempRectF = new RectF();
+ public void positionFromMatrix(Matrix matrix) {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ if (mRenderer.source != null) {
+ final int rotation = mRenderer.source.getRotation();
+ final boolean swap = !(rotation % 180 == 0);
+ final int width = swap ? mRenderer.source.getImageHeight()
+ : mRenderer.source.getImageWidth();
+ final int height = swap ? mRenderer.source.getImageWidth()
+ : mRenderer.source.getImageHeight();
+ mTempRectF.set(0, 0, width, height);
+ matrix.mapRect(mTempRectF);
+ matrix.getValues(mValues);
+ int cx = width / 2;
+ int cy = height / 2;
+ float scale = mValues[Matrix.MSCALE_X];
+ int xoffset = Math.round((getWidth() - mTempRectF.width()) / 2 / scale);
+ int yoffset = Math.round((getHeight() - mTempRectF.height()) / 2 / scale);
+ if (rotation == 90 || rotation == 180) {
+ cx += (mTempRectF.left / scale) - xoffset;
+ } else {
+ cx -= (mTempRectF.left / scale) - xoffset;
+ }
+ if (rotation == 180 || rotation == 270) {
+ cy += (mTempRectF.top / scale) - yoffset;
+ } else {
+ cy -= (mTempRectF.top / scale) - yoffset;
+ }
+ mRenderer.scale = scale;
+ mRenderer.centerX = swap ? cy : cx;
+ mRenderer.centerY = swap ? cx : cy;
+ invalidate();
+ }
+ }
+
+ private class TileRenderer implements Renderer {
+
+ private GLES20Canvas mCanvas;
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ mCanvas = new GLES20Canvas();
+ BasicTexture.invalidateAllTextures();
+ mRenderer.image.setModel(mRenderer.source, mRenderer.rotation);
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ mCanvas.setSize(width, height);
+ mRenderer.image.setViewSize(width, height);
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ mCanvas.clearBuffer();
+ Runnable readyCallback;
+ synchronized (mLock) {
+ readyCallback = mRenderer.isReadyCallback;
+ mRenderer.image.setModel(mRenderer.source, mRenderer.rotation);
+ mRenderer.image.setPosition(mRenderer.centerX, mRenderer.centerY,
+ mRenderer.scale);
+ }
+ boolean complete = mRenderer.image.draw(mCanvas);
+ if (complete && readyCallback != null) {
+ synchronized (mLock) {
+ // Make sure we don't trample on a newly set callback/source
+ // if it changed while we were rendering
+ if (mRenderer.isReadyCallback == readyCallback) {
+ mRenderer.isReadyCallback = null;
+ }
+ }
+ if (readyCallback != null) {
+ post(readyCallback);
+ }
+ }
+ }
+
+ }
+
+ @SuppressWarnings("unused")
+ private static class ColoredTiles implements TileSource {
+ private static final int[] COLORS = new int[] {
+ Color.RED,
+ Color.BLUE,
+ Color.YELLOW,
+ Color.GREEN,
+ Color.CYAN,
+ Color.MAGENTA,
+ Color.WHITE,
+ };
+
+ private Paint mPaint = new Paint();
+ private Canvas mCanvas = new Canvas();
+
+ @Override
+ public int getTileSize() {
+ return 256;
+ }
+
+ @Override
+ public int getImageWidth() {
+ return 16384;
+ }
+
+ @Override
+ public int getImageHeight() {
+ return 8192;
+ }
+
+ @Override
+ public int getRotation() {
+ return 0;
+ }
+
+ @Override
+ public Bitmap getTile(int level, int x, int y, Bitmap bitmap) {
+ int tileSize = getTileSize();
+ if (bitmap == null) {
+ bitmap = Bitmap.createBitmap(tileSize, tileSize,
+ Bitmap.Config.ARGB_8888);
+ }
+ mCanvas.setBitmap(bitmap);
+ mCanvas.drawColor(COLORS[level]);
+ mPaint.setColor(Color.BLACK);
+ mPaint.setTextSize(20);
+ mPaint.setTextAlign(Align.CENTER);
+ mCanvas.drawText(x + "x" + y, 128, 128, mPaint);
+ tileSize <<= level;
+ x /= tileSize;
+ y /= tileSize;
+ mCanvas.drawText(x + "x" + y + " @ " + level, 128, 30, mPaint);
+ mCanvas.setBitmap(null);
+ return bitmap;
+ }
+
+ @Override
+ public BasicTexture getPreview() {
+ return null;
+ }
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
new file mode 100644
index 0000000..ecebd642
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
@@ -0,0 +1,246 @@
+/*
+ * 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.
+ */
+/* Copied from Launcher3 */
+package com.android.wallpapercropper;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import android.view.ViewConfiguration;
+import android.view.ScaleGestureDetector.OnScaleGestureListener;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+
+import com.android.photos.views.TiledImageRenderer.TileSource;
+import com.android.photos.views.TiledImageView;
+
+public class CropView extends TiledImageView implements OnScaleGestureListener {
+
+ private ScaleGestureDetector mScaleGestureDetector;
+ private long mTouchDownTime;
+ private float mFirstX, mFirstY;
+ private float mLastX, mLastY;
+ private float mMinScale;
+ private boolean mTouchEnabled = true;
+ private RectF mTempEdges = new RectF();
+ TouchCallback mTouchCallback;
+
+ public interface TouchCallback {
+ void onTouchDown();
+ void onTap();
+ }
+
+ public CropView(Context context) {
+ this(context, null);
+ }
+
+ public CropView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mScaleGestureDetector = new ScaleGestureDetector(context, this);
+ }
+
+ private void getEdgesHelper(RectF edgesOut) {
+ final float width = getWidth();
+ final float height = getHeight();
+ final float imageWidth = mRenderer.source.getImageWidth();
+ final float imageHeight = mRenderer.source.getImageHeight();
+ final float scale = mRenderer.scale;
+ float centerX = (width / 2f - mRenderer.centerX + (imageWidth - width) / 2f)
+ * scale + width / 2f;
+ float centerY = (height / 2f - mRenderer.centerY + (imageHeight - height) / 2f)
+ * scale + height / 2f;
+ float leftEdge = centerX - imageWidth / 2f * scale;
+ float rightEdge = centerX + imageWidth / 2f * scale;
+ float topEdge = centerY - imageHeight / 2f * scale;
+ float bottomEdge = centerY + imageHeight / 2f * scale;
+
+ edgesOut.left = leftEdge;
+ edgesOut.right = rightEdge;
+ edgesOut.top = topEdge;
+ edgesOut.bottom = bottomEdge;
+ }
+
+ public RectF getCrop() {
+ final RectF edges = mTempEdges;
+ getEdgesHelper(edges);
+ final float scale = mRenderer.scale;
+
+ float cropLeft = -edges.left / scale;
+ float cropTop = -edges.top / scale;
+ float cropRight = cropLeft + getWidth() / scale;
+ float cropBottom = cropTop + getHeight() / scale;
+
+ return new RectF(cropLeft, cropTop, cropRight, cropBottom);
+ }
+
+ public Point getSourceDimensions() {
+ return new Point(mRenderer.source.getImageWidth(), mRenderer.source.getImageHeight());
+ }
+
+ public void setTileSource(TileSource source, Runnable isReadyCallback) {
+ super.setTileSource(source, isReadyCallback);
+ updateMinScale(getWidth(), getHeight(), source, true);
+ }
+
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ updateMinScale(w, h, mRenderer.source, false);
+ }
+
+ public void setScale(float scale) {
+ synchronized (mLock) {
+ mRenderer.scale = scale;
+ }
+ }
+
+ private void updateMinScale(int w, int h, TileSource source, boolean resetScale) {
+ synchronized (mLock) {
+ if (resetScale) {
+ mRenderer.scale = 1;
+ }
+ if (source != null) {
+ mMinScale = Math.max(w / (float) source.getImageWidth(),
+ h / (float) source.getImageHeight());
+ mRenderer.scale = Math.max(mMinScale, mRenderer.scale);
+ }
+ }
+ }
+
+ @Override
+ public boolean onScaleBegin(ScaleGestureDetector detector) {
+ return true;
+ }
+
+ @Override
+ public boolean onScale(ScaleGestureDetector detector) {
+ // Don't need the lock because this will only fire inside of
+ // onTouchEvent
+ mRenderer.scale *= detector.getScaleFactor();
+ mRenderer.scale = Math.max(mMinScale, mRenderer.scale);
+ invalidate();
+ return true;
+ }
+
+ @Override
+ public void onScaleEnd(ScaleGestureDetector detector) {
+ }
+
+ public void moveToUpperLeft() {
+ if (getWidth() == 0 || getHeight() == 0) {
+ final ViewTreeObserver observer = getViewTreeObserver();
+ observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
+ public void onGlobalLayout() {
+ moveToUpperLeft();
+ getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ }
+ });
+ }
+ final RectF edges = mTempEdges;
+ getEdgesHelper(edges);
+ final float scale = mRenderer.scale;
+ mRenderer.centerX += Math.ceil(edges.left / scale);
+ mRenderer.centerY += Math.ceil(edges.top / scale);
+ }
+
+ public void setTouchEnabled(boolean enabled) {
+ mTouchEnabled = enabled;
+ }
+
+ public void setTouchCallback(TouchCallback cb) {
+ mTouchCallback = cb;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ int action = event.getActionMasked();
+ final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
+ final int skipIndex = pointerUp ? event.getActionIndex() : -1;
+
+ // Determine focal point
+ float sumX = 0, sumY = 0;
+ final int count = event.getPointerCount();
+ for (int i = 0; i < count; i++) {
+ if (skipIndex == i)
+ continue;
+ sumX += event.getX(i);
+ sumY += event.getY(i);
+ }
+ final int div = pointerUp ? count - 1 : count;
+ float x = sumX / div;
+ float y = sumY / div;
+
+ if (action == MotionEvent.ACTION_DOWN) {
+ mFirstX = x;
+ mFirstY = y;
+ mTouchDownTime = System.currentTimeMillis();
+ if (mTouchCallback != null) {
+ mTouchCallback.onTouchDown();
+ }
+ } else if (action == MotionEvent.ACTION_UP) {
+ ViewConfiguration config = ViewConfiguration.get(getContext());
+
+ float squaredDist = (mFirstX - x) * (mFirstX - x) + (mFirstY - y) * (mFirstY - y);
+ float slop = config.getScaledTouchSlop() * config.getScaledTouchSlop();
+ long now = System.currentTimeMillis();
+ // only do this if it's a small movement
+ if (mTouchCallback != null &&
+ squaredDist < slop &&
+ now < mTouchDownTime + ViewConfiguration.getTapTimeout()) {
+ mTouchCallback.onTap();
+ }
+ }
+
+ if (!mTouchEnabled) {
+ return true;
+ }
+
+ synchronized (mLock) {
+ mScaleGestureDetector.onTouchEvent(event);
+ switch (action) {
+ case MotionEvent.ACTION_MOVE:
+ mRenderer.centerX += (mLastX - x) / mRenderer.scale;
+ mRenderer.centerY += (mLastY - y) / mRenderer.scale;
+ invalidate();
+ break;
+ }
+ if (mRenderer.source != null) {
+ // Adjust position so that the wallpaper covers the entire area
+ // of the screen
+ final RectF edges = mTempEdges;
+ getEdgesHelper(edges);
+ final float scale = mRenderer.scale;
+ if (edges.left > 0) {
+ mRenderer.centerX += Math.ceil(edges.left / scale);
+ }
+ if (edges.right < getWidth()) {
+ mRenderer.centerX += (edges.right - getWidth()) / scale;
+ }
+ if (edges.top > 0) {
+ mRenderer.centerY += Math.ceil(edges.top / scale);
+ }
+ if (edges.bottom < getHeight()) {
+ mRenderer.centerY += (edges.bottom - getHeight()) / scale;
+ }
+ }
+ }
+
+ mLastX = x;
+ mLastY = y;
+ return true;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
new file mode 100644
index 0000000..a993ed3
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -0,0 +1,646 @@
+/*
+ * 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.
+ */
+/* Copied from Launcher3 */
+package com.android.wallpapercropper;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.gallery3d.common.Utils;
+import com.android.photos.BitmapRegionTileSource;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class WallpaperCropActivity extends Activity {
+ private static final String LOGTAG = "Launcher3.CropActivity";
+
+ protected static final String WALLPAPER_WIDTH_KEY = "wallpaper.width";
+ protected static final String WALLPAPER_HEIGHT_KEY = "wallpaper.height";
+ private static final int DEFAULT_COMPRESS_QUALITY = 90;
+ /**
+ * The maximum bitmap size we allow to be returned through the intent.
+ * Intents have a maximum of 1MB in total size. However, the Bitmap seems to
+ * have some overhead to hit so that we go way below the limit here to make
+ * sure the intent stays below 1MB.We should consider just returning a byte
+ * array instead of a Bitmap instance to avoid overhead.
+ */
+ public static final int MAX_BMAP_IN_INTENT = 750000;
+ private static final float WALLPAPER_SCREENS_SPAN = 2f;
+
+ protected CropView mCropView;
+ protected Uri mUri;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ init();
+ }
+
+ protected void init() {
+ setContentView(R.layout.wallpaper_cropper);
+
+ mCropView = (CropView) findViewById(R.id.cropView);
+
+ Intent cropIntent = this.getIntent();
+ final Uri imageUri = cropIntent.getData();
+
+ mCropView.setTileSource(new BitmapRegionTileSource(this, imageUri, 1024, 0), null);
+ mCropView.setTouchEnabled(true);
+ // Action bar
+ // Show the custom action bar view
+ final ActionBar actionBar = getActionBar();
+ actionBar.setCustomView(R.layout.actionbar_set_wallpaper);
+ actionBar.getCustomView().setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ boolean finishActivityWhenDone = true;
+ cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone);
+ }
+ });
+ }
+
+ public static String getSharedPreferencesKey() {
+ return WallpaperCropActivity.class.getName();
+ }
+
+ // As a ratio of screen height, the total distance we want the parallax effect to span
+ // horizontally
+ private static float wallpaperTravelToScreenWidthRatio(int width, int height) {
+ float aspectRatio = width / (float) height;
+
+ // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
+ // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
+ // We will use these two data points to extrapolate how much the wallpaper parallax effect
+ // to span (ie travel) at any aspect ratio:
+
+ final float ASPECT_RATIO_LANDSCAPE = 16/10f;
+ final float ASPECT_RATIO_PORTRAIT = 10/16f;
+ final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
+ final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
+
+ // To find out the desired width at different aspect ratios, we use the following two
+ // formulas, where the coefficient on x is the aspect ratio (width/height):
+ // (16/10)x + y = 1.5
+ // (10/16)x + y = 1.2
+ // We solve for x and y and end up with a final formula:
+ final float x =
+ (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
+ (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
+ final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
+ return x * aspectRatio + y;
+ }
+
+ static protected Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) {
+ Point minDims = new Point();
+ Point maxDims = new Point();
+ windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
+
+ int maxDim = Math.max(maxDims.x, maxDims.y);
+ final int minDim = Math.min(minDims.x, minDims.y);
+
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ Point realSize = new Point();
+ windowManager.getDefaultDisplay().getRealSize(realSize);
+ maxDim = Math.max(realSize.x, realSize.y);
+ }
+
+ // We need to ensure that there is enough extra space in the wallpaper
+ // for the intended
+ // parallax effects
+ final int defaultWidth, defaultHeight;
+ if (isScreenLarge(res)) {
+ defaultWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
+ defaultHeight = maxDim;
+ } else {
+ defaultWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
+ defaultHeight = maxDim;
+ }
+ return new Point(defaultWidth, defaultHeight);
+ }
+
+ protected void setWallpaper(String filePath, final boolean finishActivityWhenDone) {
+
+ BitmapCropTask cropTask = new BitmapCropTask(this,
+ filePath, null, 0, 0, true, false, null);
+ final Point bounds = cropTask.getImageBounds();
+ Runnable onEndCrop = new Runnable() {
+ public void run() {
+ updateWallpaperDimensions(bounds.x, bounds.y);
+ if (finishActivityWhenDone) {
+ setResult(Activity.RESULT_OK);
+ finish();
+ }
+ }
+ };
+ cropTask.setOnEndRunnable(onEndCrop);
+ cropTask.setNoCrop(true);
+ cropTask.execute();
+ }
+
+ protected void cropImageAndSetWallpaper(
+ Resources res, int resId, final boolean finishActivityWhenDone) {
+ // crop this image and scale it down to the default wallpaper size for
+ // this device
+ Point inSize = mCropView.getSourceDimensions();
+ Point outSize = getDefaultWallpaperSize(getResources(),
+ getWindowManager());
+ RectF crop = getMaxCropRect(
+ inSize.x, inSize.y, outSize.x, outSize.y, false);
+ Runnable onEndCrop = new Runnable() {
+ public void run() {
+ // Passing 0, 0 will cause launcher to revert to using the
+ // default wallpaper size
+ updateWallpaperDimensions(0, 0);
+ if (finishActivityWhenDone) {
+ setResult(Activity.RESULT_OK);
+ finish();
+ }
+ }
+ };
+ BitmapCropTask cropTask = new BitmapCropTask(res, resId,
+ crop, outSize.x, outSize.y,
+ true, false, onEndCrop);
+ cropTask.execute();
+ }
+
+ private static boolean isScreenLarge(Resources res) {
+ Configuration config = res.getConfiguration();
+ return config.smallestScreenWidthDp >= 720;
+ }
+
+ protected void cropImageAndSetWallpaper(Uri uri,
+ OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) {
+ // Get the crop
+ Point inSize = mCropView.getSourceDimensions();
+
+ Point minDims = new Point();
+ Point maxDims = new Point();
+ Display d = getWindowManager().getDefaultDisplay();
+ d.getCurrentSizeRange(minDims, maxDims);
+
+ Point displaySize = new Point();
+ d.getSize(displaySize);
+
+ int maxDim = Math.max(maxDims.x, maxDims.y);
+ final int minDim = Math.min(minDims.x, minDims.y);
+ int defaultWidth;
+ if (isScreenLarge(getResources())) {
+ defaultWidth = (int) (maxDim *
+ wallpaperTravelToScreenWidthRatio(maxDim, minDim));
+ } else {
+ defaultWidth = Math.max((int)
+ (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
+ }
+
+ boolean isPortrait = displaySize.x < displaySize.y;
+ int portraitHeight;
+ if (isPortrait) {
+ portraitHeight = mCropView.getHeight();
+ } else {
+ // TODO: how to actually get the proper portrait height?
+ // This is not quite right:
+ portraitHeight = Math.max(maxDims.x, maxDims.y);
+ }
+ if (android.os.Build.VERSION.SDK_INT >=
+ android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ Point realSize = new Point();
+ d.getRealSize(realSize);
+ portraitHeight = Math.max(realSize.x, realSize.y);
+ }
+ // Get the crop
+ RectF cropRect = mCropView.getCrop();
+ float cropScale = mCropView.getWidth() / (float) cropRect.width();
+
+ // ADJUST CROP WIDTH
+ // Extend the crop all the way to the right, for parallax
+ float extraSpaceToRight = inSize.x - cropRect.right;
+ // Cap the amount of extra width
+ float maxExtraSpace = defaultWidth / cropScale - cropRect.width();
+ extraSpaceToRight = Math.min(extraSpaceToRight, maxExtraSpace);
+
+ cropRect.right += extraSpaceToRight;
+
+ // ADJUST CROP HEIGHT
+ if (isPortrait) {
+ cropRect.bottom = cropRect.top + portraitHeight / cropScale;
+ } else { // LANDSCAPE
+ float extraPortraitHeight =
+ portraitHeight / cropScale - cropRect.height();
+ float expandHeight =
+ Math.min(Math.min(inSize.y - cropRect.bottom, cropRect.top),
+ extraPortraitHeight / 2);
+ cropRect.top -= expandHeight;
+ cropRect.bottom += expandHeight;
+ }
+ final int outWidth = (int) Math.round(cropRect.width() * cropScale);
+ final int outHeight = (int) Math.round(cropRect.height() * cropScale);
+
+ Runnable onEndCrop = new Runnable() {
+ public void run() {
+ updateWallpaperDimensions(outWidth, outHeight);
+ if (finishActivityWhenDone) {
+ setResult(Activity.RESULT_OK);
+ finish();
+ }
+ }
+ };
+ BitmapCropTask cropTask = new BitmapCropTask(uri,
+ cropRect, outWidth, outHeight, true, false, onEndCrop);
+ if (onBitmapCroppedHandler != null) {
+ cropTask.setOnBitmapCropped(onBitmapCroppedHandler);
+ }
+ cropTask.execute();
+ }
+
+ public interface OnBitmapCroppedHandler {
+ public void onBitmapCropped(byte[] imageBytes);
+ }
+
+ protected class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
+ Uri mInUri = null;
+ Context mContext;
+ String mInFilePath;
+ byte[] mInImageBytes;
+ int mInResId = 0;
+ InputStream mInStream;
+ RectF mCropBounds = null;
+ int mOutWidth, mOutHeight;
+ int mRotation = 0; // for now
+ protected final WallpaperManager mWPManager;
+ String mOutputFormat = "jpg"; // for now
+ boolean mSetWallpaper;
+ boolean mSaveCroppedBitmap;
+ Bitmap mCroppedBitmap;
+ Runnable mOnEndRunnable;
+ Resources mResources;
+ OnBitmapCroppedHandler mOnBitmapCroppedHandler;
+ boolean mNoCrop;
+
+ public BitmapCropTask(Context c, String filePath,
+ RectF cropBounds, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mContext = c;
+ mInFilePath = filePath;
+ mWPManager = WallpaperManager.getInstance(getApplicationContext());
+ init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ }
+
+ public BitmapCropTask(byte[] imageBytes,
+ RectF cropBounds, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mInImageBytes = imageBytes;
+ mWPManager = WallpaperManager.getInstance(getApplicationContext());
+ init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ }
+
+ public BitmapCropTask(Uri inUri,
+ RectF cropBounds, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mInUri = inUri;
+ mWPManager = WallpaperManager.getInstance(getApplicationContext());
+ init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ }
+
+ public BitmapCropTask(Resources res, int inResId,
+ RectF cropBounds, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mInResId = inResId;
+ mResources = res;
+ mWPManager = WallpaperManager.getInstance(getApplicationContext());
+ init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ }
+
+ private void init(RectF cropBounds, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mCropBounds = cropBounds;
+ mOutWidth = outWidth;
+ mOutHeight = outHeight;
+ mSetWallpaper = setWallpaper;
+ mSaveCroppedBitmap = saveCroppedBitmap;
+ mOnEndRunnable = onEndRunnable;
+ }
+
+ public void setOnBitmapCropped(OnBitmapCroppedHandler handler) {
+ mOnBitmapCroppedHandler = handler;
+ }
+
+ public void setNoCrop(boolean value) {
+ mNoCrop = value;
+ }
+
+ public void setOnEndRunnable(Runnable onEndRunnable) {
+ mOnEndRunnable = onEndRunnable;
+ }
+
+ // Helper to setup input stream
+ private void regenerateInputStream() {
+ if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) {
+ Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " +
+ "image byte array given");
+ } else {
+ Utils.closeSilently(mInStream);
+ try {
+ if (mInUri != null) {
+ mInStream = new BufferedInputStream(
+ getContentResolver().openInputStream(mInUri));
+ } else if (mInFilePath != null) {
+ mInStream = mContext.openFileInput(mInFilePath);
+ } else if (mInImageBytes != null) {
+ mInStream = new BufferedInputStream(
+ new ByteArrayInputStream(mInImageBytes));
+ } else {
+ mInStream = new BufferedInputStream(
+ mResources.openRawResource(mInResId));
+ }
+ } catch (FileNotFoundException e) {
+ Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e);
+ }
+ }
+ }
+
+ public Point getImageBounds() {
+ regenerateInputStream();
+ if (mInStream != null) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeStream(mInStream, null, options);
+ if (options.outWidth != 0 && options.outHeight != 0) {
+ return new Point(options.outWidth, options.outHeight);
+ }
+ }
+ return null;
+ }
+
+ public void setCropBounds(RectF cropBounds) {
+ mCropBounds = cropBounds;
+ }
+
+ public Bitmap getCroppedBitmap() {
+ return mCroppedBitmap;
+ }
+ public boolean cropBitmap() {
+ boolean failure = false;
+
+ regenerateInputStream();
+
+ if (mNoCrop && mInStream != null) {
+ try {
+ mWPManager.setStream(mInStream);
+ } catch (IOException e) {
+ Log.w(LOGTAG, "cannot write stream to wallpaper", e);
+ failure = true;
+ }
+ if (mOnEndRunnable != null) {
+ mOnEndRunnable.run();
+ }
+ return !failure;
+ }
+ if (mInStream != null) {
+ // Find crop bounds (scaled to original image size)
+ Rect roundedTrueCrop = new Rect();
+ mCropBounds.roundOut(roundedTrueCrop);
+
+ if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) {
+ Log.w(LOGTAG, "crop has bad values for full size image");
+ failure = true;
+ return false;
+ }
+
+ // See how much we're reducing the size of the image
+ int scaleDownSampleSize = Math.min(roundedTrueCrop.width() / mOutWidth,
+ roundedTrueCrop.height() / mOutHeight);
+
+ // Attempt to open a region decoder
+ BitmapRegionDecoder decoder = null;
+ try {
+ decoder = BitmapRegionDecoder.newInstance(mInStream, true);
+ } catch (IOException e) {
+ Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e);
+ }
+
+ Bitmap crop = null;
+ if (decoder != null) {
+ // Do region decoding to get crop bitmap
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ if (scaleDownSampleSize > 1) {
+ options.inSampleSize = scaleDownSampleSize;
+ }
+ crop = decoder.decodeRegion(roundedTrueCrop, options);
+ decoder.recycle();
+ }
+
+ if (crop == null) {
+ // BitmapRegionDecoder has failed, try to crop in-memory
+ regenerateInputStream();
+ Bitmap fullSize = null;
+ if (mInStream != null) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ if (scaleDownSampleSize > 1) {
+ options.inSampleSize = scaleDownSampleSize;
+ }
+ fullSize = BitmapFactory.decodeStream(mInStream, null, options);
+ }
+ if (fullSize != null) {
+ crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left,
+ roundedTrueCrop.top, roundedTrueCrop.width(),
+ roundedTrueCrop.height());
+ }
+ }
+
+ if (crop == null) {
+ Log.w(LOGTAG, "cannot decode file: " + mInUri.toString());
+ failure = true;
+ return false;
+ }
+ if (mOutWidth > 0 && mOutHeight > 0) {
+ Matrix m = new Matrix();
+ RectF cropRect = new RectF(0, 0, crop.getWidth(), crop.getHeight());
+ if (mRotation > 0) {
+ m.setRotate(mRotation);
+ m.mapRect(cropRect);
+ }
+ RectF returnRect = new RectF(0, 0, mOutWidth, mOutHeight);
+ m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
+ m.preRotate(mRotation);
+ Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(),
+ (int) returnRect.height(), Bitmap.Config.ARGB_8888);
+ if (tmp != null) {
+ Canvas c = new Canvas(tmp);
+ c.drawBitmap(crop, m, new Paint());
+ crop = tmp;
+ }
+ } else if (mRotation > 0) {
+ Matrix m = new Matrix();
+ m.setRotate(mRotation);
+ Bitmap tmp = Bitmap.createBitmap(crop, 0, 0, crop.getWidth(),
+ crop.getHeight(), m, true);
+ if (tmp != null) {
+ crop = tmp;
+ }
+ }
+
+ if (mSaveCroppedBitmap) {
+ mCroppedBitmap = crop;
+ }
+
+ // Get output compression format
+ CompressFormat cf =
+ convertExtensionToCompressFormat(getFileExtension(mOutputFormat));
+
+ // Compress to byte array
+ ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
+ if (crop.compress(cf, DEFAULT_COMPRESS_QUALITY, tmpOut)) {
+ // If we need to set to the wallpaper, set it
+ if (mSetWallpaper && mWPManager != null) {
+ if (mWPManager == null) {
+ Log.w(LOGTAG, "no wallpaper manager");
+ failure = true;
+ } else {
+ try {
+ byte[] outByteArray = tmpOut.toByteArray();
+ mWPManager.setStream(new ByteArrayInputStream(outByteArray));
+ if (mOnBitmapCroppedHandler != null) {
+ mOnBitmapCroppedHandler.onBitmapCropped(outByteArray);
+ }
+ } catch (IOException e) {
+ Log.w(LOGTAG, "cannot write stream to wallpaper", e);
+ failure = true;
+ }
+ }
+ }
+ if (mOnEndRunnable != null) {
+ mOnEndRunnable.run();
+ }
+ } else {
+ Log.w(LOGTAG, "cannot compress bitmap");
+ failure = true;
+ }
+ }
+ return !failure; // True if any of the operations failed
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ return cropBitmap();
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ setResult(Activity.RESULT_OK);
+ finish();
+ }
+ }
+
+ protected void updateWallpaperDimensions(int width, int height) {
+ String spKey = getSharedPreferencesKey();
+ SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sp.edit();
+ if (width != 0 && height != 0) {
+ editor.putInt(WALLPAPER_WIDTH_KEY, width);
+ editor.putInt(WALLPAPER_HEIGHT_KEY, height);
+ } else {
+ editor.remove(WALLPAPER_WIDTH_KEY);
+ editor.remove(WALLPAPER_HEIGHT_KEY);
+ }
+ editor.commit();
+
+ suggestWallpaperDimension(getResources(),
+ sp, getWindowManager(), WallpaperManager.getInstance(this));
+ }
+
+ static public void suggestWallpaperDimension(Resources res,
+ final SharedPreferences sharedPrefs,
+ WindowManager windowManager,
+ final WallpaperManager wallpaperManager) {
+ final Point defaultWallpaperSize =
+ WallpaperCropActivity.getDefaultWallpaperSize(res, windowManager);
+
+ new Thread("suggestWallpaperDimension") {
+ public void run() {
+ // If we have saved a wallpaper width/height, use that instead
+ int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, defaultWallpaperSize.x);
+ int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, defaultWallpaperSize.y);
+ wallpaperManager.suggestDesiredDimensions(savedWidth, savedHeight);
+ }
+ }.start();
+ }
+
+
+ protected static RectF getMaxCropRect(
+ int inWidth, int inHeight, int outWidth, int outHeight, boolean leftAligned) {
+ RectF cropRect = new RectF();
+ // Get a crop rect that will fit this
+ if (inWidth / (float) inHeight > outWidth / (float) outHeight) {
+ cropRect.top = 0;
+ cropRect.bottom = inHeight;
+ cropRect.left = (inWidth - (outWidth / (float) outHeight) * inHeight) / 2;
+ cropRect.right = inWidth - cropRect.left;
+ if (leftAligned) {
+ cropRect.right -= cropRect.left;
+ cropRect.left = 0;
+ }
+ } else {
+ cropRect.left = 0;
+ cropRect.right = inWidth;
+ cropRect.top = (inHeight - (outHeight / (float) outWidth) * inWidth) / 2;
+ cropRect.bottom = inHeight - cropRect.top;
+ }
+ return cropRect;
+ }
+
+ protected static CompressFormat convertExtensionToCompressFormat(String extension) {
+ return extension.equals("png") ? CompressFormat.PNG : CompressFormat.JPEG;
+ }
+
+ protected static String getFileExtension(String requestFormat) {
+ String outputFormat = (requestFormat == null)
+ ? "jpg"
+ : requestFormat;
+ outputFormat = outputFormat.toLowerCase();
+ return (outputFormat.equals("png") || outputFormat.equals("gif"))
+ ? "png" // We don't support gif compression.
+ : "jpg";
+ }
+}
diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
index 7e76025..c6b76f1 100644
--- a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
+++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
@@ -25,6 +25,9 @@
import com.android.net.IProxyService;
+import java.net.MalformedURLException;
+import java.net.URL;
+
public class PacService extends Service {
private static final String TAG = "PacService";
@@ -68,7 +71,18 @@
@Override
public String resolvePacFile(String host, String url) throws RemoteException {
- return mPacNative.makeProxyRequest(url, host);
+ try {
+ // Check for characters that could be used for an injection attack.
+ new URL(url);
+ for (char c : host.toCharArray()) {
+ if (!Character.isLetterOrDigit(c) && (c != '.') && (c != '-')) {
+ throw new RemoteException("Invalid host was passed");
+ }
+ }
+ return mPacNative.makeProxyRequest(url, host);
+ } catch (MalformedURLException e) {
+ throw new RemoteException("Invalid URL was passed");
+ }
}
@Override
diff --git a/core/res/res/values-land/refs.xml b/packages/services/Proxy/com/android/net/IProxyCallback.aidl
similarity index 75%
copy from core/res/res/values-land/refs.xml
copy to packages/services/Proxy/com/android/net/IProxyCallback.aidl
index cda38cf..26b2a3f9 100644
--- a/core/res/res/values-land/refs.xml
+++ b/packages/services/Proxy/com/android/net/IProxyCallback.aidl
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+/**
* Copyright (c) 2013, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,8 +12,11 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
-*/
--->
-<resources>
- <item type="string" name="transient_navigation_confirmation">@string/transient_navigation_confirmation_long</item>
-</resources>
\ No newline at end of file
+ */
+package com.android.net;
+
+/** @hide */
+interface IProxyCallback
+{
+ oneway void getProxyPort(IBinder callback);
+}
diff --git a/core/res/res/values-land/refs.xml b/packages/services/Proxy/com/android/net/IProxyPortListener.aidl
similarity index 75%
copy from core/res/res/values-land/refs.xml
copy to packages/services/Proxy/com/android/net/IProxyPortListener.aidl
index cda38cf..fa4caf3 100644
--- a/core/res/res/values-land/refs.xml
+++ b/packages/services/Proxy/com/android/net/IProxyPortListener.aidl
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+/**
* Copyright (c) 2013, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,8 +12,11 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
-*/
--->
-<resources>
- <item type="string" name="transient_navigation_confirmation">@string/transient_navigation_confirmation_long</item>
-</resources>
\ No newline at end of file
+ */
+package com.android.net;
+
+/** @hide */
+interface IProxyPortListener
+{
+ oneway void setProxyPort(int port);
+}
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
index 77f3c8c..4bf1db8 100644
--- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
@@ -15,8 +15,11 @@
*/
package com.android.proxyhandler;
+import android.net.ProxyProperties;
+import android.os.RemoteException;
import android.util.Log;
+import com.android.net.IProxyPortListener;
import com.google.android.collect.Lists;
import java.io.IOException;
@@ -49,6 +52,8 @@
public boolean mIsRunning = false;
private ServerSocket serverSocket;
+ private int mPort;
+ private IProxyPortListener mCallback;
private class ProxyConnection implements Runnable {
private Socket connection;
@@ -179,33 +184,59 @@
public ProxyServer() {
threadExecutor = Executors.newCachedThreadPool();
+ mPort = -1;
+ mCallback = null;
}
@Override
public void run() {
try {
- serverSocket = new ServerSocket(ProxyService.PORT);
+ serverSocket = new ServerSocket(0);
- serverSocket.setReuseAddress(true);
+ if (serverSocket != null) {
+ setPort(serverSocket.getLocalPort());
- while (mIsRunning) {
- try {
- ProxyConnection parser = new ProxyConnection(serverSocket.accept());
+ while (mIsRunning) {
+ try {
+ ProxyConnection parser = new ProxyConnection(serverSocket.accept());
- threadExecutor.execute(parser);
- } catch (IOException e) {
- e.printStackTrace();
+ threadExecutor.execute(parser);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
}
}
} catch (SocketException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
+ Log.e(TAG, "Failed to start proxy server", e);
+ } catch (IOException e1) {
+ Log.e(TAG, "Failed to start proxy server", e1);
}
mIsRunning = false;
}
+ public synchronized void setPort(int port) {
+ if (mCallback != null) {
+ try {
+ mCallback.setProxyPort(port);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Proxy failed to report port to PacManager", e);
+ }
+ }
+ mPort = port;
+ }
+
+ public synchronized void setCallback(IProxyPortListener callback) {
+ if (mPort != -1) {
+ try {
+ callback.setProxyPort(mPort);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Proxy failed to report port to PacManager", e);
+ }
+ }
+ mCallback = callback;
+ }
+
public synchronized void startServer() {
mIsRunning = true;
start();
@@ -222,4 +253,12 @@
}
}
}
+
+ public boolean isBound() {
+ return (mPort != -1);
+ }
+
+ public int getPort() {
+ return mPort;
+ }
}
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java
index cef3659..109435c 100644
--- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java
@@ -21,8 +21,12 @@
import android.net.ProxyProperties;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.RemoteException;
import android.text.TextUtils;
+import com.android.net.IProxyCallback;
+import com.android.net.IProxyPortListener;
+
/**
* @hide
*/
@@ -56,6 +60,16 @@
@Override
public IBinder onBind(Intent intent) {
- return null;
+ return new IProxyCallback.Stub() {
+ @Override
+ public void getProxyPort(IBinder callback) throws RemoteException {
+ if (server != null) {
+ IProxyPortListener portListener = IProxyPortListener.Stub.asInterface(callback);
+ if (portListener != null) {
+ server.setCallback(portListener);
+ }
+ }
+ }
+ };
}
}
\ No newline at end of file
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
index 41b2fd1..57c9675 100644
--- a/policy/src/com/android/internal/policy/impl/BarController.java
+++ b/policy/src/com/android/internal/policy/impl/BarController.java
@@ -33,7 +33,7 @@
* Controls state/behavior specific to a system bar window.
*/
public class BarController {
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final int TRANSIENT_BAR_NONE = 0;
private static final int TRANSIENT_BAR_SHOWING = 1;
@@ -106,24 +106,32 @@
mPendingShow = true;
return false;
}
- final boolean oldVis = mWin.isVisibleLw();
- final boolean oldAnim = mWin.isAnimatingLw();
- final boolean rt = show ? mWin.showLw(true) : mWin.hideLw(true);
- final int state = computeState(oldVis, oldAnim, mWin.isVisibleLw(), mWin.isAnimatingLw());
- if (state > -1 && mWin.hasDrawnLw()) {
- updateState(state);
+ final boolean wasVis = mWin.isVisibleLw();
+ final boolean wasAnim = mWin.isAnimatingLw();
+ final boolean change = show ? mWin.showLw(true) : mWin.hideLw(true);
+ final int state = computeStateLw(wasVis, wasAnim, mWin, change);
+ updateStateLw(state);
+ return change;
+ }
+
+ private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
+ if (win.hasDrawnLw()) {
+ final boolean vis = win.isVisibleLw();
+ final boolean anim = win.isAnimatingLw();
+ if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) {
+ return StatusBarManager.WINDOW_STATE_HIDDEN;
+ } else if (change) {
+ if (wasVis && vis && !wasAnim && anim) {
+ return StatusBarManager.WINDOW_STATE_HIDING;
+ } else {
+ return StatusBarManager.WINDOW_STATE_SHOWING;
+ }
+ }
}
- return rt;
+ return mState;
}
- private int computeState(boolean oldVis, boolean oldAnim, boolean newVis, boolean newAnim) {
- return (!newVis && !newAnim) ? StatusBarManager.WINDOW_STATE_HIDDEN
- : (!oldVis && newVis && newAnim) ? StatusBarManager.WINDOW_STATE_SHOWING
- : (oldVis && newVis && !oldAnim && newAnim) ? StatusBarManager.WINDOW_STATE_HIDING
- : -1;
- }
-
- private void updateState(final int state) {
+ private void updateStateLw(final int state) {
if (state != mState) {
mState = state;
if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state));
@@ -148,7 +156,7 @@
public boolean checkHiddenLw() {
if (mWin != null && mWin.hasDrawnLw()) {
if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
- updateState(StatusBarManager.WINDOW_STATE_HIDDEN);
+ updateStateLw(StatusBarManager.WINDOW_STATE_HIDDEN);
}
if (mTransientBarState == TRANSIENT_BAR_HIDING && !mWin.isVisibleLw()) {
// Finished animating out, clean up and reset style
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index a3bd785..11913ee 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -22,6 +22,7 @@
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.*;
+import android.view.ViewConfiguration;
import com.android.internal.view.RootViewSurfaceTaker;
import com.android.internal.view.StandaloneActionMode;
import com.android.internal.view.menu.ContextMenuBuilder;
@@ -540,7 +541,8 @@
@Override
public final void openPanel(int featureId, KeyEvent event) {
if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
- mActionBar.isOverflowReserved()) {
+ mActionBar.isOverflowReserved() &&
+ !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
if (mActionBar.getVisibility() == View.VISIBLE) {
mActionBar.showOverflowMenu();
}
@@ -549,7 +551,7 @@
}
}
- private void openPanel(PanelFeatureState st, KeyEvent event) {
+ private void openPanel(final PanelFeatureState st, KeyEvent event) {
// System.out.println("Open panel: isOpen=" + st.isOpen);
// Already open, return
@@ -673,7 +675,8 @@
@Override
public final void closePanel(int featureId) {
if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
- mActionBar.isOverflowReserved()) {
+ mActionBar.isOverflowReserved() &&
+ !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
mActionBar.hideOverflowMenu();
} else if (featureId == FEATURE_CONTEXT_MENU) {
closeContextMenu();
@@ -836,7 +839,8 @@
boolean playSoundEffect = false;
final PanelFeatureState st = getPanelState(featureId, true);
if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
- mActionBar.isOverflowReserved()) {
+ mActionBar.isOverflowReserved() &&
+ !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
if (mActionBar.getVisibility() == View.VISIBLE) {
if (!mActionBar.isOverflowMenuShowing()) {
if (!isDestroyed() && preparePanel(st, event)) {
@@ -1014,7 +1018,9 @@
}
private void reopenMenu(boolean toggleMenuMode) {
- if (mActionBar != null && mActionBar.isOverflowReserved()) {
+ if (mActionBar != null && mActionBar.isOverflowReserved() &&
+ (!ViewConfiguration.get(getContext()).hasPermanentMenuKey() ||
+ mActionBar.isOverflowMenuShowPending())) {
final Callback cb = getCallback();
if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) {
if (cb != null && !isDestroyed() && mActionBar.getVisibility() == View.VISIBLE) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 27bf38cc..0782cfb 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -34,7 +34,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.pm.UserInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -105,7 +104,6 @@
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.HashSet;
import static android.view.WindowManager.LayoutParams.*;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
@@ -531,7 +529,7 @@
Settings.Secure.DEFAULT_INPUT_METHOD), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
- ImmersiveModeTesting.ENABLED_SETTING), false, this,
+ Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS), false, this,
UserHandle.USER_ALL);
updateSettings();
}
@@ -947,9 +945,7 @@
}
@Override
public void onDebug() {
- if (ImmersiveModeTesting.enabled) {
- ImmersiveModeTesting.toggleForceImmersiveMode(mFocusedWindow, mContext);
- }
+ // no-op
}
});
mTransientNavigationConfirmation = new TransientNavigationConfirmation(mContext);
@@ -1168,8 +1164,9 @@
mHasSoftInput = hasSoftInput;
updateRotation = true;
}
- ImmersiveModeTesting.enabled = Settings.System.getIntForUser(resolver,
- ImmersiveModeTesting.ENABLED_SETTING, 0, UserHandle.USER_CURRENT) != 0;
+ if (mTransientNavigationConfirmation != null) {
+ mTransientNavigationConfirmation.loadSetting();
+ }
}
if (updateRotation) {
updateRotation(true);
@@ -2819,7 +2816,7 @@
// If the status bar is hidden, we don't want to cause
// windows behind it to scroll.
- if (mStatusBar.isVisibleLw() && !statusBarTransient && !statusBarTransparent) {
+ if (mStatusBar.isVisibleLw() && !statusBarTransient) {
// Status bar may go away, so the screen area it occupies
// is available to apps but just covering them when the
// status bar is visible.
@@ -3637,7 +3634,7 @@
? AudioManager.ADJUST_RAISE
: AudioManager.ADJUST_LOWER,
0,
- mContext.getBasePackageName());
+ mContext.getOpPackageName());
} catch (RemoteException e) {
Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e);
} finally {
@@ -3892,9 +3889,8 @@
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
- if (isScreenOn && isTransientNavigationAllowed(mLastSystemUiFlags)) {
- mTransientNavigationConfirmation.unconfirmLastPackage();
- }
+ mTransientNavigationConfirmation.onPowerKeyDown(isScreenOn, event.getDownTime(),
+ isTransientNavigationAllowed(mLastSystemUiFlags));
if (isScreenOn && !mPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mPowerKeyTriggered = true;
@@ -4173,6 +4169,7 @@
}
if (sb) mStatusBarController.showTransient();
if (nb) mNavigationBarController.showTransient();
+ mTransientNavigationConfirmation.confirmCurrentPrompt();
updateSystemUiVisibilityLw();
}
}
@@ -4964,7 +4961,7 @@
owningPackage = win.getOwningPackage();
} else {
owningUid = android.os.Process.myUid();
- owningPackage = mContext.getBasePackageName();
+ owningPackage = mContext.getOpPackageName();
}
if (pattern.length == 1) {
// One-shot vibration
@@ -5039,10 +5036,6 @@
}
private int updateSystemBarsLw(int oldVis, int vis) {
- if (ImmersiveModeTesting.enabled) {
- vis = ImmersiveModeTesting.applyForced(mFocusedWindow, vis);
- }
-
// prevent status bar interaction from clearing certain flags
boolean statusBarHasFocus = mFocusedWindow.getAttrs().type == TYPE_STATUS_BAR;
if (statusBarHasFocus) {
@@ -5086,8 +5079,7 @@
boolean isTransientNav = isTransientNavigationAllowed(vis);
if (mFocusedWindow != null && oldTransientNav != isTransientNav) {
final String pkg = mFocusedWindow.getOwningPackage();
- mTransientNavigationConfirmation.transientNavigationChanged(mCurrentUserId, pkg,
- isTransientNav);
+ mTransientNavigationConfirmation.transientNavigationChanged(pkg, isTransientNav);
}
vis = mNavigationBarController.updateVisibilityLw(isTransientNav, oldVis, vis);
@@ -5104,53 +5096,6 @@
&& (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
}
- // Temporary helper that allows testing immersive mode on existing apps
- // TODO remove
- private static final class ImmersiveModeTesting {
- static String ENABLED_SETTING = "immersive_mode_testing_enabled";
- static boolean enabled = false;
- private static final HashSet<String> sForced = new HashSet<String>();
-
- private static String parseActivity(WindowState win) {
- if (win != null && win.getAppToken() != null) {
- String str = win.getAppToken().toString();
- int end = str.lastIndexOf(' ');
- if (end > 0) {
- int start = str.lastIndexOf(' ', end - 1);
- if (start > -1) {
- return str.substring(start + 1, end);
- }
- }
- }
- return null;
- }
-
- public static int applyForced(WindowState focused, int vis) {
- if (sForced.contains(parseActivity(focused))) {
- vis |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_FULLSCREEN |
- View.SYSTEM_UI_FLAG_IMMERSIVE;
- }
- return vis;
- }
-
- public static void toggleForceImmersiveMode(WindowState focused, Context context) {
- String activity = parseActivity(focused);
- if (activity != null) {
- String action;
- if (sForced.contains(activity)) {
- sForced.remove(activity);
- action = "Force immersive mode disabled";
- } else {
- sForced.add(activity);
- action = "Force immersive mode enabled";
- }
- android.widget.Toast.makeText(context,
- action + " for " + activity, android.widget.Toast.LENGTH_SHORT).show();
- }
- }
- }
-
// Use this instead of checking config_showNavigationBar so that it can be consistently
// overridden by qemu.hw.mainkeys in the emulator.
@Override
diff --git a/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java b/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java
index 3c4f092..8613088 100644
--- a/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java
+++ b/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java
@@ -19,16 +19,20 @@
import android.content.Context;
import android.os.Handler;
import android.os.Message;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Slog;
import android.view.View;
import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.widget.Toast;
import com.android.internal.R;
+import java.util.Arrays;
+
/**
* Helper to manage showing/hiding a confirmation prompt when the transient navigation bar
* is hidden.
@@ -39,16 +43,22 @@
private final Context mContext;
private final H mHandler;
- private final ArraySet<String> mConfirmedUserPackages = new ArraySet<String>();
+ private final ArraySet<String> mConfirmedPackages = new ArraySet<String>();
private final long mShowDelayMs;
+ private final long mPanicThresholdMs;
private Toast mToast;
- private String mLastUserPackage;
+ private String mLastPackage;
+ private String mPromptPackage;
+ private long mPanicTime;
+ private String mPanicPackage;
public TransientNavigationConfirmation(Context context) {
mContext = context;
mHandler = new H();
mShowDelayMs = getNavBarExitDuration() * 3;
+ mPanicThresholdMs = context.getResources()
+ .getInteger(R.integer.config_transient_navigation_confirmation_panic);
}
private long getNavBarExitDuration() {
@@ -56,44 +66,97 @@
return exit != null ? exit.getDuration() : 0;
}
- public void transientNavigationChanged(int userId, String pkg, boolean isNavTransient) {
+ public void loadSetting() {
+ if (DEBUG) Slog.d(TAG, "loadSetting()");
+ mConfirmedPackages.clear();
+ String packages = null;
+ try {
+ packages = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS,
+ UserHandle.USER_CURRENT);
+ if (packages != null) {
+ mConfirmedPackages.addAll(Arrays.asList(packages.split(",")));
+ if (DEBUG) Slog.d(TAG, "Loaded mConfirmedPackages=" + mConfirmedPackages);
+ }
+ } catch (Throwable t) {
+ Slog.w(TAG, "Error loading confirmations, packages=" + packages, t);
+ }
+ }
+
+ private void saveSetting() {
+ if (DEBUG) Slog.d(TAG, "saveSetting()");
+ try {
+ final String packages = TextUtils.join(",", mConfirmedPackages);
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS,
+ packages,
+ UserHandle.USER_CURRENT);
+ if (DEBUG) Slog.d(TAG, "Saved packages=" + packages);
+ } catch (Throwable t) {
+ Slog.w(TAG, "Error saving confirmations, mConfirmedPackages=" + mConfirmedPackages, t);
+ }
+ }
+
+ public void transientNavigationChanged(String pkg, boolean isNavTransient) {
if (pkg == null) {
return;
}
- String userPkg = userId + ":" + pkg;
mHandler.removeMessages(H.SHOW);
if (isNavTransient) {
- mLastUserPackage = userPkg;
- if (!mConfirmedUserPackages.contains(userPkg)) {
- if (DEBUG) Slog.d(TAG, "Showing transient navigation confirmation for " + userPkg);
- mHandler.sendMessageDelayed(mHandler.obtainMessage(H.SHOW, userPkg), mShowDelayMs);
+ mLastPackage = pkg;
+ if (!mConfirmedPackages.contains(pkg)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(H.SHOW, pkg), mShowDelayMs);
}
} else {
- mLastUserPackage = null;
- if (DEBUG) Slog.d(TAG, "Hiding transient navigation confirmation for " + userPkg);
+ mLastPackage = null;
mHandler.sendEmptyMessage(H.HIDE);
}
}
- public void unconfirmLastPackage() {
- if (mLastUserPackage != null) {
- if (DEBUG) Slog.d(TAG, "Unconfirming transient navigation for " + mLastUserPackage);
- mConfirmedUserPackages.remove(mLastUserPackage);
+ public void onPowerKeyDown(boolean isScreenOn, long time, boolean transientNavigationAllowed) {
+ if (mPanicPackage != null && !isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
+ // turning the screen back on within the panic threshold
+ unconfirmPackage(mPanicPackage);
+ }
+ if (isScreenOn && transientNavigationAllowed) {
+ // turning the screen off, remember if we were hiding the transient nav
+ mPanicTime = time;
+ mPanicPackage = mLastPackage;
+ } else {
+ mPanicTime = 0;
+ mPanicPackage = null;
+ }
+ }
+
+ public void confirmCurrentPrompt() {
+ mHandler.post(confirmAction(mPromptPackage));
+ }
+
+ private void unconfirmPackage(String pkg) {
+ if (pkg != null) {
+ if (DEBUG) Slog.d(TAG, "Unconfirming transient navigation for " + pkg);
+ mConfirmedPackages.remove(pkg);
+ saveSetting();
}
}
private void handleHide() {
if (mToast != null) {
+ if (DEBUG) Slog.d(TAG,
+ "Hiding transient navigation confirmation for " + mPromptPackage);
mToast.cancel();
mToast = null;
}
}
- private void handleShow(String userPkg) {
+ private void handleShow(String pkg) {
+ mPromptPackage = pkg;
+ if (DEBUG) Slog.d(TAG, "Showing transient navigation confirmation for " + pkg);
+
// create the confirmation toast bar
final int msg = R.string.transient_navigation_confirmation;
mToast = Toast.makeBar(mContext, msg, Toast.LENGTH_INFINITE);
- mToast.setAction(R.string.ok, confirmAction(userPkg));
+ mToast.setAction(R.string.ok, confirmAction(pkg));
// we will be hiding the nav bar, so layout as if it's already hidden
mToast.getView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
@@ -102,11 +165,15 @@
mToast.show();
}
- private Runnable confirmAction(final String userPkg) {
+ private Runnable confirmAction(final String pkg) {
return new Runnable() {
@Override
public void run() {
- mConfirmedUserPackages.add(userPkg);
+ if (pkg != null && !mConfirmedPackages.contains(pkg)) {
+ if (DEBUG) Slog.d(TAG, "Confirming transient navigation for " + pkg);
+ mConfirmedPackages.add(pkg);
+ saveSetting();
+ }
handleHide();
}
};
diff --git a/preloaded-classes b/preloaded-classes
index 064ca3a..cb2ace3 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -663,8 +663,8 @@
android.net.wifi.WifiManager
android.net.wifi.WifiManager$ServiceHandler
android.net.wifi.WifiNative
-android.nfc.INdefPushCallback
-android.nfc.INdefPushCallback$Stub
+android.nfc.IAppCallback
+android.nfc.IAppCallback$Stub
android.nfc.INfcAdapter
android.nfc.INfcAdapter$Stub
android.nfc.INfcAdapter$Stub$Proxy
@@ -1209,13 +1209,9 @@
android.webkit.BrowserFrame$ConfigCallback
android.webkit.CallbackProxy
android.webkit.CookieManager
-android.webkit.CookieManagerClassic
android.webkit.CookieSyncManager
android.webkit.DeviceMotionAndOrientationManager
android.webkit.GeolocationPermissions
-android.webkit.GeolocationPermissionsClassic
-android.webkit.GeolocationPermissionsClassic$1
-android.webkit.GeolocationPermissionsClassic$2
android.webkit.HTML5Audio
android.webkit.HTML5VideoViewProxy
android.webkit.JWebCoreJavaBridge
@@ -1231,42 +1227,19 @@
android.webkit.ViewManager$3
android.webkit.ViewStateSerializer
android.webkit.WebBackForwardList
-android.webkit.WebBackForwardListClassic
android.webkit.WebCoreThreadWatchdog
android.webkit.WebHistoryItem
-android.webkit.WebHistoryItemClassic
android.webkit.WebIconDatabase
-android.webkit.WebIconDatabaseClassic
-android.webkit.WebIconDatabaseClassic$EventHandler
-android.webkit.WebIconDatabaseClassic$EventHandler$1
android.webkit.WebSettings
android.webkit.WebSettings$LayoutAlgorithm
android.webkit.WebSettings$PluginState
android.webkit.WebSettings$RenderPriority
android.webkit.WebSettings$ZoomDensity
-android.webkit.WebSettingsClassic
-android.webkit.WebSettingsClassic$AutoFillProfile
-android.webkit.WebSettingsClassic$EventHandler
-android.webkit.WebSettingsClassic$EventHandler$1
android.webkit.WebStorage
-android.webkit.WebStorageClassic
-android.webkit.WebStorageClassic$1
-android.webkit.WebStorageClassic$2
android.webkit.WebSyncManager
android.webkit.WebSyncManager$SyncHandler
android.webkit.WebView
android.webkit.WebView$PrivateAccess
-android.webkit.WebViewClassic
-android.webkit.WebViewClassic$Factory
-android.webkit.WebViewClassic$OnTrimMemoryListener
-android.webkit.WebViewClassic$PackageListener
-android.webkit.WebViewClassic$PageSwapDelegate
-android.webkit.WebViewClassic$PrivateHandler
-android.webkit.WebViewClassic$ProxyReceiver
-android.webkit.WebViewClassic$SelectionHandleAlpha
-android.webkit.WebViewClassic$TitleBarDelegate
-android.webkit.WebViewClassic$TrustStorageListener
-android.webkit.WebViewClassic$ViewSizeData
android.webkit.WebViewClient
android.webkit.WebViewCore$AutoFillData
android.webkit.WebViewCore$DrawData
@@ -1278,8 +1251,6 @@
android.webkit.WebViewCore$WebCoreThread
android.webkit.WebViewCore$WebCoreThread$1
android.webkit.WebViewDatabase
-android.webkit.WebViewDatabaseClassic
-android.webkit.WebViewDatabaseClassic$1
android.webkit.WebViewFactory
android.webkit.WebViewFactory$Preloader
android.webkit.WebViewFactoryProvider
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 795ab47..9e7a15d 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -3405,6 +3405,7 @@
& InputDispatcher::doNotifyANRLockedInterruptible);
commandEntry->inputApplicationHandle = applicationHandle;
commandEntry->inputWindowHandle = windowHandle;
+ commandEntry->reason = reason;
}
void InputDispatcher::doNotifyConfigurationChangedInterruptible(
@@ -3434,7 +3435,8 @@
mLock.unlock();
nsecs_t newTimeout = mPolicy->notifyANR(
- commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle);
+ commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle,
+ commandEntry->reason);
mLock.lock();
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 0273dc4..190e7b2 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -202,7 +202,8 @@
/* Notifies the system that an application is not responding.
* Returns a new timeout to continue waiting, or 0 to abort dispatch. */
virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<InputWindowHandle>& inputWindowHandle) = 0;
+ const sp<InputWindowHandle>& inputWindowHandle,
+ const String8& reason) = 0;
/* Notifies the system that an input channel is unrecoverably broken. */
virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0;
@@ -596,6 +597,7 @@
KeyEntry* keyEntry;
sp<InputApplicationHandle> inputApplicationHandle;
sp<InputWindowHandle> inputWindowHandle;
+ String8 reason;
int32_t userActivityEventType;
uint32_t seq;
bool handled;
diff --git a/services/input/tests/InputDispatcher_test.cpp b/services/input/tests/InputDispatcher_test.cpp
index ed2b4a5..26b4fab 100644
--- a/services/input/tests/InputDispatcher_test.cpp
+++ b/services/input/tests/InputDispatcher_test.cpp
@@ -50,7 +50,8 @@
}
virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<InputWindowHandle>& inputWindowHandle) {
+ const sp<InputWindowHandle>& inputWindowHandle,
+ const String8& reason) {
return 0;
}
diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java
index c6c4a94..67b2307 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/java/com/android/server/AppOpsService.java
@@ -113,7 +113,7 @@
uid = _uid;
packageName = _packageName;
op = _op;
- mode = AppOpsManager.MODE_ALLOWED;
+ mode = AppOpsManager.opToDefaultMode(op);
}
}
@@ -191,7 +191,7 @@
mHandler = new Handler();
readState();
}
-
+
public void publish(Context context) {
mContext = context;
ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
@@ -379,7 +379,7 @@
}
repCbs.addAll(cbs);
}
- if (mode == AppOpsManager.MODE_ALLOWED) {
+ if (mode == AppOpsManager.opToDefaultMode(op.op)) {
// If going into the default mode, prune this op
// if there is nothing else interesting in it.
pruneOp(op, uid, packageName);
@@ -435,8 +435,8 @@
Ops pkgOps = ent.getValue();
for (int j=pkgOps.size()-1; j>=0; j--) {
Op curOp = pkgOps.valueAt(j);
- if (curOp.mode != AppOpsManager.MODE_ALLOWED) {
- curOp.mode = AppOpsManager.MODE_ALLOWED;
+ if (curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
+ curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
changed = true;
callbacks = addCallbacks(callbacks, packageName, curOp.op,
mOpModeWatchers.get(curOp.op));
@@ -545,7 +545,7 @@
synchronized (this) {
Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false);
if (op == null) {
- return AppOpsManager.MODE_ALLOWED;
+ return AppOpsManager.opToDefaultMode(code);
}
return op.mode;
}
@@ -947,7 +947,7 @@
AppOpsManager.OpEntry op = ops.get(j);
out.startTag(null, "op");
out.attribute(null, "n", Integer.toString(op.getOp()));
- if (op.getMode() != AppOpsManager.MODE_ALLOWED) {
+ if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
out.attribute(null, "m", Integer.toString(op.getMode()));
}
long time = op.getTime();
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index c4eb7a4..f3ebdb2 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -1305,9 +1305,6 @@
mTransports.put(name, transport);
} else {
mTransports.remove(name);
- if ((mCurrentTransport != null) && mCurrentTransport.equals(name)) {
- mCurrentTransport = null;
- }
// Nothing further to do in the unregistration case
return;
}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 02a78de..3f13f3a 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -58,8 +58,8 @@
import android.net.INetworkStatsService;
import android.net.LinkAddress;
import android.net.LinkProperties;
-import android.net.LinkQualityInfo;
import android.net.LinkProperties.CompareResult;
+import android.net.LinkQualityInfo;
import android.net.MobileDataStateTracker;
import android.net.NetworkConfig;
import android.net.NetworkInfo;
@@ -89,7 +89,6 @@
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -114,7 +113,6 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
-import com.android.net.IProxyService;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.DataConnectionStats;
import com.android.server.connectivity.Nat464Xlat;
@@ -2955,8 +2953,11 @@
if (ConnectivityManager.isNetworkTypeMobile(info.getType())
&& (0 != Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0))
- && ((state == NetworkInfo.State.CONNECTED)
- || info.isConnectedToProvisioningNetwork())) {
+ && (((state == NetworkInfo.State.CONNECTED)
+ && (info.getType() == ConnectivityManager.TYPE_MOBILE))
+ || info.isConnectedToProvisioningNetwork())) {
+ log("ConnectivityChange checkMobileProvisioning for"
+ + " TYPE_MOBILE or ProvisioningNetwork");
checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS);
}
@@ -3209,12 +3210,6 @@
return mTethering.getTetheredIfaces();
}
- @Override
- public String[] getTetheredIfacePairs() {
- enforceTetherAccessPermission();
- return mTethering.getTetheredIfacePairs();
- }
-
public String[] getTetheringErroredIfaces() {
enforceTetherAccessPermission();
return mTethering.getErroredIfaces();
@@ -3471,7 +3466,7 @@
private void sendProxyBroadcast(ProxyProperties proxy) {
if (proxy == null) proxy = new ProxyProperties("", 0, "");
- mPacManager.setCurrentProxyScriptUrl(proxy);
+ if (mPacManager.setCurrentProxyScriptUrl(proxy)) return;
if (DBG) log("sending Proxy Broadcast for " + proxy);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
@@ -3995,40 +3990,6 @@
// Start off with notification off
setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null);
- // See if we've alreadying determined if we've got a provsioning connection
- // if so we don't need to do anything active
- MobileDataStateTracker mdstDefault = (MobileDataStateTracker)
- mNetTrackers[ConnectivityManager.TYPE_MOBILE];
- boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork();
-
- MobileDataStateTracker mdstHipri = (MobileDataStateTracker)
- mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
- boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork();
-
- if (isDefaultProvisioning || isHipriProvisioning) {
- if (mIsNotificationVisible) {
- if (DBG) {
- log("checkMobileProvisioning: provisioning-ignore notification is visible");
- }
- } else {
- NetworkInfo ni = null;
- if (isDefaultProvisioning) {
- ni = mdstDefault.getNetworkInfo();
- }
- if (isHipriProvisioning) {
- ni = mdstHipri.getNetworkInfo();
- }
- String url = getMobileProvisioningUrl();
- if ((ni != null) && (!TextUtils.isEmpty(url))) {
- setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), url);
- } else {
- if (DBG) log("checkMobileProvisioning: provisioning but no url, ignore");
- }
- }
- mIsCheckingMobileProvisioning.set(false);
- return timeOutMs;
- }
-
CheckMp checkMp = new CheckMp(mContext, this);
CheckMp.CallBack cb = new CheckMp.CallBack() {
@Override
@@ -4162,8 +4123,26 @@
mParams = params;
if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
- log("isMobileOk: not mobile capable");
result = CMP_RESULT_CODE_NO_CONNECTION;
+ log("isMobileOk: X not mobile capable result=" + result);
+ return result;
+ }
+
+ // See if we've already determined we've got a provisioning connection,
+ // if so we don't need to do anything active.
+ MobileDataStateTracker mdstDefault = (MobileDataStateTracker)
+ mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE];
+ boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork();
+ log("isMobileOk: isDefaultProvisioning=" + isDefaultProvisioning);
+
+ MobileDataStateTracker mdstHipri = (MobileDataStateTracker)
+ mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
+ boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork();
+ log("isMobileOk: isHipriProvisioning=" + isHipriProvisioning);
+
+ if (isDefaultProvisioning || isHipriProvisioning) {
+ result = CMP_RESULT_CODE_PROVISIONING_NETWORK;
+ log("isMobileOk: X default || hipri is provisioning result=" + result);
return result;
}
@@ -4225,8 +4204,8 @@
MobileDataStateTracker mdst = (MobileDataStateTracker)
mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
if (mdst.isProvisioningNetwork()) {
- if (DBG) log("isMobileOk: isProvisioningNetwork is true");
result = CMP_RESULT_CODE_PROVISIONING_NETWORK;
+ if (DBG) log("isMobileOk: X isProvisioningNetwork result=" + result);
return result;
} else {
if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue");
@@ -4241,8 +4220,8 @@
try {
addresses = InetAddress.getAllByName(orgUri.getHost());
} catch (UnknownHostException e) {
- log("isMobileOk: UnknownHostException");
result = CMP_RESULT_CODE_NO_DNS;
+ log("isMobileOk: X UnknownHostException result=" + result);
return result;
}
log("isMobileOk: addresses=" + inetAddressesToString(addresses));
@@ -4317,8 +4296,9 @@
if (responseCode == 204) {
// Return
- log("isMobileOk: expected responseCode=" + responseCode);
result = CMP_RESULT_CODE_CONNECTABLE;
+ log("isMobileOk: X expected responseCode=" + responseCode
+ + " result=" + result);
return result;
} else {
// Retry to be sure this was redirected, we've gotten
@@ -4336,7 +4316,7 @@
}
}
}
- log("isMobileOk: loops|timed out result=" + result);
+ log("isMobileOk: X loops|timed out result=" + result);
return result;
} catch (Exception e) {
log("isMobileOk: Exception e=" + e);
@@ -4681,6 +4661,21 @@
setProvNotificationVisible(visible, networkType, extraInfo, url);
}
+ @Override
+ public void setAirplaneMode(boolean enable) {
+ enforceConnectivityInternalPermission();
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ final ContentResolver cr = mContext.getContentResolver();
+ Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0);
+ Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ intent.putExtra("state", enable);
+ mContext.sendBroadcast(intent);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
private void onUserStart(int userId) {
synchronized(mVpns) {
Vpn userVpn = mVpns.get(userId);
diff --git a/services/java/com/android/server/ConsumerIrService.java b/services/java/com/android/server/ConsumerIrService.java
new file mode 100644
index 0000000..07f2a41
--- /dev/null
+++ b/services/java/com/android/server/ConsumerIrService.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.hardware.input.InputManager;
+import android.hardware.IConsumerIrService;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Binder;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.WorkSource;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+import android.util.Slog;
+import android.view.InputDevice;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+public class ConsumerIrService extends IConsumerIrService.Stub {
+ private static final String TAG = "ConsumerIrService";
+
+ private static final int MAX_XMIT_TIME = 2000000; /* in microseconds */
+
+ private static native int halOpen();
+ private static native int halTransmit(int halObject, int carrierFrequency, int[] pattern);
+ private static native int[] halGetCarrierFrequencies(int halObject);
+
+ private final Context mContext;
+ private final PowerManager.WakeLock mWakeLock;
+ private final int mHal;
+ private final Object mHalLock = new Object();
+
+ ConsumerIrService(Context context) {
+ mContext = context;
+ PowerManager pm = (PowerManager)context.getSystemService(
+ Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ mWakeLock.setReferenceCounted(true);
+
+ mHal = halOpen();
+ if (mHal == 0) {
+ Slog.w(TAG, "No IR HAL loaded");
+ }
+ }
+
+ @Override
+ public boolean hasIrEmitter() {
+ return mHal != 0;
+ }
+
+ private void throwIfNoIrEmitter() {
+ if (mHal == 0) {
+ throw new UnsupportedOperationException("IR emitter not available");
+ }
+ }
+
+
+ @Override
+ public void transmit(String packageName, int carrierFrequency, int[] pattern) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.TRANSMIT_IR)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires TRANSMIT_IR permission");
+ }
+
+ long totalXmitTime = 0;
+
+ for (int slice : pattern) {
+ if (slice <= 0) {
+ throw new IllegalArgumentException("Non-positive IR slice");
+ }
+ totalXmitTime += slice;
+ }
+
+ if (totalXmitTime > MAX_XMIT_TIME ) {
+ throw new IllegalArgumentException("IR pattern too long");
+ }
+
+ throwIfNoIrEmitter();
+
+ // Right now there is no mechanism to ensure fair queing of IR requests
+ synchronized (mHalLock) {
+ int err = halTransmit(mHal, carrierFrequency, pattern);
+
+ if (err < 0) {
+ Slog.e(TAG, "Error transmitting: " + err);
+ }
+ }
+ }
+
+ @Override
+ public int[] getCarrierFrequencies() {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.TRANSMIT_IR)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires TRANSMIT_IR permission");
+ }
+
+ throwIfNoIrEmitter();
+
+ synchronized(mHalLock) {
+ return halGetCarrierFrequencies(mHal);
+ }
+ }
+}
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 7e83396..8cc80f7 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
+import com.android.internal.R;
import com.android.internal.os.storage.ExternalStorageFormatter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
@@ -33,6 +34,9 @@
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AppGlobals;
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DeviceAdminReceiver;
@@ -51,6 +55,7 @@
import android.content.pm.Signature;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
@@ -100,6 +105,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -123,6 +129,8 @@
protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
= "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
+ private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
+
private static final boolean DBG = false;
final Context mContext;
@@ -130,9 +138,16 @@
IPowerManager mIPowerManager;
IWindowManager mIWindowManager;
+ NotificationManager mNotificationManager;
private DeviceOwner mDeviceOwner;
+ /**
+ * Whether or not device admin feature is supported. If it isn't return defaults for all
+ * public methods.
+ */
+ private boolean mHasFeature;
+
public static class DevicePolicyData {
int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
int mActivePasswordLength = 0;
@@ -177,7 +192,12 @@
handlePasswordExpirationNotification(getUserData(userHandle));
}
});
- } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+ }
+ if (Intent.ACTION_BOOT_COMPLETED.equals(action)
+ || KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
+ manageMonitoringCertificateNotification(intent);
+ }
+ if (Intent.ACTION_USER_REMOVED.equals(action)) {
removeUserData(userHandle);
} else if (Intent.ACTION_USER_STARTED.equals(action)
|| Intent.ACTION_PACKAGE_CHANGED.equals(action)
@@ -519,13 +539,20 @@
*/
public DevicePolicyManagerService(Context context) {
mContext = context;
+ mHasFeature = context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_DEVICE_ADMIN);
mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
+ if (!mHasFeature) {
+ // Skip the rest of the initialization
+ return;
+ }
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_STARTED);
+ filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
@@ -635,6 +662,14 @@
return mIWindowManager;
}
+ private NotificationManager getNotificationManager() {
+ if (mNotificationManager == null) {
+ mNotificationManager =
+ (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+ return mNotificationManager;
+ }
+
ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
if (admin != null
@@ -738,6 +773,9 @@
}
public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
enforceCrossUserPermission(userHandle);
Intent resolveIntent = new Intent();
resolveIntent.setComponent(adminName);
@@ -1027,6 +1065,9 @@
}
public void systemReady() {
+ if (!mHasFeature) {
+ return;
+ }
synchronized (this) {
loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
loadDeviceOwner();
@@ -1053,11 +1094,71 @@
}
}
+ private void manageMonitoringCertificateNotification(Intent intent) {
+ final NotificationManager notificationManager = getNotificationManager();
+
+ final boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
+ if (! hasCert) {
+ if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
+ UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ for (UserInfo user : um.getUsers()) {
+ notificationManager.cancelAsUser(
+ null, MONITORING_CERT_NOTIFICATION_ID, user.getUserHandle());
+ }
+ }
+ return;
+ }
+ final boolean isManaged = getDeviceOwner() != null;
+ int smallIconId;
+ String contentText;
+ if (isManaged) {
+ contentText = mContext.getString(R.string.ssl_ca_cert_noti_managed,
+ getDeviceOwnerName());
+ smallIconId = R.drawable.stat_sys_certificate_info;
+ } else {
+ contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_unknown);
+ smallIconId = android.R.drawable.stat_sys_warning;
+ }
+
+ Intent dialogIntent = new Intent(Settings.ACTION_MONITORING_CERT_INFO);
+ dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ dialogIntent.setPackage("com.android.settings");
+ // Notification will be sent individually to all users. The activity should start as
+ // whichever user is current when it starts.
+ PendingIntent notifyIntent = PendingIntent.getActivityAsUser(mContext, 0, dialogIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT, null, UserHandle.CURRENT);
+
+ Notification noti = new Notification.Builder(mContext)
+ .setSmallIcon(smallIconId)
+ .setContentTitle(mContext.getString(R.string.ssl_ca_cert_warning))
+ .setContentText(contentText)
+ .setContentIntent(notifyIntent)
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setShowWhen(false)
+ .build();
+
+ // If this is a boot intent, this will fire for each user. But if this is a storage changed
+ // intent, it will fire once, so we need to notify all users.
+ if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
+ UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ for (UserInfo user : um.getUsers()) {
+ notificationManager.notifyAsUser(
+ null, MONITORING_CERT_NOTIFICATION_ID, noti, user.getUserHandle());
+ }
+ } else {
+ notificationManager.notifyAsUser(
+ null, MONITORING_CERT_NOTIFICATION_ID, noti, UserHandle.CURRENT);
+ }
+ }
+
/**
* @param adminReceiver The admin to add
* @param refreshing true = update an active admin, no error
*/
public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
enforceCrossUserPermission(userHandle);
@@ -1101,6 +1202,9 @@
}
public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
@@ -1108,6 +1212,9 @@
}
public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
@@ -1118,7 +1225,12 @@
}
}
+ @SuppressWarnings("unchecked")
public List<ComponentName> getActiveAdmins(int userHandle) {
+ if (!mHasFeature) {
+ return Collections.EMPTY_LIST;
+ }
+
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
@@ -1135,6 +1247,9 @@
}
public boolean packageHasActiveAdmins(String packageName, int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
@@ -1149,6 +1264,9 @@
}
public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
@@ -1174,6 +1292,9 @@
}
public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
validateQualityConstant(quality);
enforceCrossUserPermission(userHandle);
@@ -1191,6 +1312,9 @@
}
public int getPasswordQuality(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -1213,6 +1337,9 @@
}
public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1228,6 +1355,9 @@
}
public int getPasswordMinimumLength(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
@@ -1250,6 +1380,9 @@
}
public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1265,6 +1398,9 @@
}
public int getPasswordHistoryLength(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
@@ -1287,6 +1423,9 @@
}
public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1317,6 +1456,9 @@
* Returns 0 if not configured.
*/
public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0L;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who != null) {
@@ -1362,6 +1504,9 @@
}
public long getPasswordExpiration(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0L;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
return getPasswordExpirationLocked(who, userHandle);
@@ -1369,6 +1514,9 @@
}
public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1384,6 +1532,9 @@
}
public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
@@ -1421,6 +1572,9 @@
}
public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
@@ -1443,6 +1597,9 @@
}
public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1458,6 +1615,9 @@
}
public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
@@ -1480,6 +1640,9 @@
}
public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1495,6 +1658,9 @@
}
public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
@@ -1517,6 +1683,9 @@
}
public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1532,6 +1701,9 @@
}
public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
@@ -1554,6 +1726,9 @@
}
public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1569,6 +1744,9 @@
}
public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
@@ -1591,6 +1769,9 @@
}
public boolean isActivePasswordSufficient(int userHandle) {
+ if (!mHasFeature) {
+ return true;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
@@ -1626,6 +1807,9 @@
}
public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
// This API can only be called by an active device admin,
@@ -1642,6 +1826,9 @@
}
public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
@@ -1667,6 +1854,9 @@
}
public boolean resetPassword(String password, int flags, int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
enforceCrossUserPermission(userHandle);
int quality;
synchronized (this) {
@@ -1788,6 +1978,9 @@
}
public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1833,6 +2026,9 @@
}
public long getMaximumTimeToLock(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
long time = 0;
@@ -1858,6 +2054,9 @@
}
public void lockNow() {
+ if (!mHasFeature) {
+ return;
+ }
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
@@ -1978,6 +2177,9 @@
}
public void wipeData(int flags, final int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
// This API can only be called by an active device admin,
@@ -2013,6 +2215,9 @@
}
public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
@@ -2043,6 +2248,9 @@
public void setActivePasswordState(int quality, int length, int letters, int uppercase,
int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
@@ -2109,12 +2317,14 @@
try {
policy.mFailedPasswordAttempts++;
saveSettingsLocked(userHandle);
- int max = getMaximumFailedPasswordsForWipe(null, userHandle);
- if (max > 0 && policy.mFailedPasswordAttempts >= max) {
- wipeDeviceOrUserLocked(0, userHandle);
+ if (mHasFeature) {
+ int max = getMaximumFailedPasswordsForWipe(null, userHandle);
+ if (max > 0 && policy.mFailedPasswordAttempts >= max) {
+ wipeDeviceOrUserLocked(0, userHandle);
+ }
+ sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
+ DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
}
- sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
- DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2134,8 +2344,10 @@
policy.mFailedPasswordAttempts = 0;
policy.mPasswordOwner = -1;
saveSettingsLocked(userHandle);
- sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
- DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
+ if (mHasFeature) {
+ sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
+ DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2145,6 +2357,9 @@
public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
String exclusionList, int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
enforceCrossUserPermission(userHandle);
synchronized(this) {
if (who == null) {
@@ -2195,6 +2410,9 @@
}
public ComponentName getGlobalProxyAdmin(int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
enforceCrossUserPermission(userHandle);
synchronized(this) {
DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
@@ -2256,6 +2474,9 @@
* status (for all admins).
*/
public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
+ if (!mHasFeature) {
+ return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
// Check for permissions
@@ -2307,6 +2528,9 @@
* active admins.
*/
public boolean getStorageEncryption(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
// Check for permissions if a particular caller is specified
@@ -2333,6 +2557,9 @@
* Get the current encryption status of the device.
*/
public int getStorageEncryptionStatus(int userHandle) {
+ if (!mHasFeature) {
+ // Ok to return current status.
+ }
enforceCrossUserPermission(userHandle);
return getEncryptionStatus();
}
@@ -2381,6 +2608,9 @@
* Disables all device cameras according to the specified admin.
*/
public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -2401,6 +2631,9 @@
* active admins.
*/
public boolean getCameraDisabled(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
synchronized (this) {
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
@@ -2424,6 +2657,9 @@
* Selectively disable keyguard features.
*/
public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -2444,6 +2680,9 @@
* or the aggregate of all active admins if who is null.
*/
public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who != null) {
@@ -2465,6 +2704,9 @@
@Override
public boolean setDeviceOwner(String packageName, String ownerName) {
+ if (!mHasFeature) {
+ return false;
+ }
if (packageName == null
|| !DeviceOwner.isInstalled(packageName, mContext.getPackageManager())) {
throw new IllegalArgumentException("Invalid package name " + packageName
@@ -2485,6 +2727,9 @@
@Override
public boolean isDeviceOwner(String packageName) {
+ if (!mHasFeature) {
+ return false;
+ }
synchronized (this) {
return mDeviceOwner != null
&& mDeviceOwner.getPackageName().equals(packageName);
@@ -2493,6 +2738,9 @@
@Override
public String getDeviceOwner() {
+ if (!mHasFeature) {
+ return null;
+ }
synchronized (this) {
if (mDeviceOwner != null) {
return mDeviceOwner.getPackageName();
@@ -2503,6 +2751,9 @@
@Override
public String getDeviceOwnerName() {
+ if (!mHasFeature) {
+ return null;
+ }
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
synchronized (this) {
if (mDeviceOwner != null) {
diff --git a/services/java/com/android/server/IdleMaintenanceService.java b/services/java/com/android/server/IdleMaintenanceService.java
index 584d4bc..b0a1aca 100644
--- a/services/java/com/android/server/IdleMaintenanceService.java
+++ b/services/java/com/android/server/IdleMaintenanceService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.app.Activity;
+import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -24,12 +25,13 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
-import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
+import android.util.Slog;
/**
* This service observes the device state and when applicable sends
@@ -69,6 +71,9 @@
private static final String ACTION_UPDATE_IDLE_MAINTENANCE_STATE =
"com.android.server.IdleMaintenanceService.action.UPDATE_IDLE_MAINTENANCE_STATE";
+ private static final String ACTION_FORCE_IDLE_MAINTENANCE =
+ "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE";
+
private static final Intent sIdleMaintenanceStartIntent;
static {
sIdleMaintenanceStartIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_START);
@@ -115,10 +120,10 @@
mUpdateIdleMaintenanceStatePendingIntent = PendingIntent.getBroadcast(mContext, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
- register(mContext.getMainLooper());
+ register(mHandler);
}
- public void register(Looper looper) {
+ public void register(Handler handler) {
IntentFilter intentFilter = new IntentFilter();
// Alarm actions.
@@ -136,7 +141,12 @@
intentFilter.addAction(Intent.ACTION_DREAMING_STOPPED);
mContext.registerReceiverAsUser(this, UserHandle.ALL,
- intentFilter, null, new Handler(looper));
+ intentFilter, null, mHandler);
+
+ intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_FORCE_IDLE_MAINTENANCE);
+ mContext.registerReceiverAsUser(this, UserHandle.ALL,
+ intentFilter, android.Manifest.permission.SET_ACTIVITY_WATCHER, mHandler);
}
private void scheduleUpdateIdleMaintenanceState(long delayMillis) {
@@ -149,7 +159,7 @@
mAlarmService.cancel(mUpdateIdleMaintenanceStatePendingIntent);
}
- private void updateIdleMaintenanceState() {
+ private void updateIdleMaintenanceState(boolean noisy) {
if (mIdleMaintenanceStarted) {
// Idle maintenance can be interrupted by user activity, or duration
// time out, or low battery.
@@ -170,9 +180,9 @@
getNextIdleMaintenanceIntervalStartFromNow());
}
}
- } else if (deviceStatePermitsIdleMaintenanceStart()
- && lastUserActivityPermitsIdleMaintenanceStart()
- && lastRunPermitsIdleMaintenanceStart()) {
+ } else if (deviceStatePermitsIdleMaintenanceStart(noisy)
+ && lastUserActivityPermitsIdleMaintenanceStart(noisy)
+ && lastRunPermitsIdleMaintenanceStart(noisy)) {
// Now that we started idle maintenance, we should schedule another
// update for the moment when the idle maintenance times out.
scheduleUpdateIdleMaintenanceState(MAX_IDLE_MAINTENANCE_DURATION);
@@ -182,8 +192,8 @@
isBatteryCharging() ? 1 : 0);
mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime();
sendIdleMaintenanceStartIntent();
- } else if (lastUserActivityPermitsIdleMaintenanceStart()) {
- if (lastRunPermitsIdleMaintenanceStart()) {
+ } else if (lastUserActivityPermitsIdleMaintenanceStart(noisy)) {
+ if (lastRunPermitsIdleMaintenanceStart(noisy)) {
// The user does not use the device and we did not run maintenance in more
// than the min interval between runs, so schedule an update - maybe the
// battery will be charged latter.
@@ -204,6 +214,10 @@
private void sendIdleMaintenanceStartIntent() {
mWakeLock.acquire();
+ try {
+ ActivityManagerNative.getDefault().performIdleMaintenance();
+ } catch (RemoteException e) {
+ }
mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceStartIntent, UserHandle.ALL,
null, this, mHandler, Activity.RESULT_OK, null, null);
}
@@ -214,25 +228,37 @@
null, this, mHandler, Activity.RESULT_OK, null, null);
}
- private boolean deviceStatePermitsIdleMaintenanceStart() {
+ private boolean deviceStatePermitsIdleMaintenanceStart(boolean noisy) {
final int minBatteryLevel = isBatteryCharging()
? MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING
: MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING;
- return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
+ boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
&& mBatteryService.getBatteryLevel() > minBatteryLevel);
+ if (!allowed && noisy) {
+ Slog.i("IdleMaintenance", "Idle maintenance not allowed due to power");
+ }
+ return allowed;
}
- private boolean lastUserActivityPermitsIdleMaintenanceStart() {
+ private boolean lastUserActivityPermitsIdleMaintenanceStart(boolean noisy) {
// The last time the user poked the device is above the threshold.
- return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
+ boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
&& SystemClock.elapsedRealtime() - mLastUserActivityElapsedTimeMillis
> MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
+ if (!allowed && noisy) {
+ Slog.i("IdleMaintenance", "Idle maintenance not allowed due to last user activity");
+ }
+ return allowed;
}
- private boolean lastRunPermitsIdleMaintenanceStart() {
+ private boolean lastRunPermitsIdleMaintenanceStart(boolean noisy) {
// Enough time passed since the last maintenance run.
- return SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis
+ boolean allowed = SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis
> MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
+ if (!allowed && noisy) {
+ Slog.i("IdleMaintenance", "Idle maintenance not allowed due time since last");
+ }
+ return allowed;
}
private boolean lastUserActivityPermitsIdleMaintenanceRunning() {
@@ -266,7 +292,7 @@
// next release. The only client for this for now is internal an holds
// a wake lock correctly.
if (mIdleMaintenanceStarted) {
- updateIdleMaintenanceState();
+ updateIdleMaintenanceState(false);
}
} else if (Intent.ACTION_SCREEN_ON.equals(action)
|| Intent.ACTION_DREAMING_STOPPED.equals(action)) {
@@ -276,7 +302,7 @@
unscheduleUpdateIdleMaintenanceState();
// If the screen went on/stopped dreaming, we know the user is using the
// device which means that idle maintenance should be stopped if running.
- updateIdleMaintenanceState();
+ updateIdleMaintenanceState(false);
} else if (Intent.ACTION_SCREEN_OFF.equals(action)
|| Intent.ACTION_DREAMING_STARTED.equals(action)) {
mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime();
@@ -285,7 +311,12 @@
// this timeout elapses since the device may go to sleep by then.
scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
} else if (ACTION_UPDATE_IDLE_MAINTENANCE_STATE.equals(action)) {
- updateIdleMaintenanceState();
+ updateIdleMaintenanceState(false);
+ } else if (ACTION_FORCE_IDLE_MAINTENANCE.equals(action)) {
+ long now = SystemClock.elapsedRealtime() - 1;
+ mLastUserActivityElapsedTimeMillis = now - MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START;
+ mLastIdleMaintenanceStartTimeMillis = now - MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
+ updateIdleMaintenanceState(true);
} else if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)
|| Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) {
// We were holding a wake lock while broadcasting the idle maintenance
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index de29155..f70f4db 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -1773,8 +1773,12 @@
@Override
public boolean isProviderEnabled(String provider) {
+ // TODO: remove this check in next release, see b/10696351
checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
provider);
+
+ // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
+ // so we discourage its use
if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
int uid = Binder.getCallingUid();
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 82cc540..92f99c2 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -24,15 +24,15 @@
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_TETHERING;
import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult;
+import static com.android.server.NetworkManagementService.NetdResponseCode.GetMarkResult;
import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
import static com.android.server.NetworkManagementService.NetdResponseCode.IpFwdStatusResult;
import static com.android.server.NetworkManagementService.NetdResponseCode.TetherDnsFwdTgtListResult;
import static com.android.server.NetworkManagementService.NetdResponseCode.TetherInterfaceListResult;
import static com.android.server.NetworkManagementService.NetdResponseCode.TetherStatusResult;
-import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsResult;
+import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsListResult;
import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
-import static com.android.server.NetworkManagementService.NetdResponseCode.GetMarkResult;
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
import android.content.Context;
@@ -118,6 +118,7 @@
public static final int TetherInterfaceListResult = 111;
public static final int TetherDnsFwdTgtListResult = 112;
public static final int TtyListResult = 113;
+ public static final int TetheringStatsListResult = 114;
public static final int TetherStatusResult = 210;
public static final int IpFwdStatusResult = 211;
@@ -523,7 +524,8 @@
throw new IllegalStateException(msg);
}
- int flags, scope;
+ int flags;
+ int scope;
try {
flags = Integer.parseInt(cooked[5]);
scope = Integer.parseInt(cooked[6]);
@@ -1373,55 +1375,42 @@
}
@Override
- public NetworkStats getNetworkStatsTethering(String[] ifacePairs) {
+ public NetworkStats getNetworkStatsTethering() {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- if (ifacePairs.length % 2 != 0) {
- throw new IllegalArgumentException(
- "unexpected ifacePairs; length=" + ifacePairs.length);
- }
-
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
- for (int i = 0; i < ifacePairs.length; i += 2) {
- final String ifaceIn = ifacePairs[i];
- final String ifaceOut = ifacePairs[i + 1];
- if (ifaceIn != null && ifaceOut != null) {
- stats.combineValues(getNetworkStatsTethering(ifaceIn, ifaceOut));
- }
- }
- return stats;
- }
-
- private NetworkStats.Entry getNetworkStatsTethering(String ifaceIn, String ifaceOut) {
- final NativeDaemonEvent event;
try {
- event = mConnector.execute("bandwidth", "gettetherstats", ifaceIn, ifaceOut);
+ final NativeDaemonEvent[] events = mConnector.executeForList(
+ "bandwidth", "gettetherstats");
+ for (NativeDaemonEvent event : events) {
+ if (event.getCode() != TetheringStatsListResult) continue;
+
+ // 114 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
+ final StringTokenizer tok = new StringTokenizer(event.getMessage());
+ try {
+ final String ifaceIn = tok.nextToken();
+ final String ifaceOut = tok.nextToken();
+
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+ entry.iface = ifaceOut;
+ entry.uid = UID_TETHERING;
+ entry.set = SET_DEFAULT;
+ entry.tag = TAG_NONE;
+ entry.rxBytes = Long.parseLong(tok.nextToken());
+ entry.rxPackets = Long.parseLong(tok.nextToken());
+ entry.txBytes = Long.parseLong(tok.nextToken());
+ entry.txPackets = Long.parseLong(tok.nextToken());
+ stats.combineValues(entry);
+ } catch (NoSuchElementException e) {
+ throw new IllegalStateException("problem parsing tethering stats: " + event);
+ } catch (NumberFormatException e) {
+ throw new IllegalStateException("problem parsing tethering stats: " + event);
+ }
+ }
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
-
- event.checkCode(TetheringStatsResult);
-
- // 221 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
- final StringTokenizer tok = new StringTokenizer(event.getMessage());
- tok.nextToken();
- tok.nextToken();
-
- try {
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- entry.iface = ifaceIn;
- entry.uid = UID_TETHERING;
- entry.set = SET_DEFAULT;
- entry.tag = TAG_NONE;
- entry.rxBytes = Long.parseLong(tok.nextToken());
- entry.rxPackets = Long.parseLong(tok.nextToken());
- entry.txBytes = Long.parseLong(tok.nextToken());
- entry.txPackets = Long.parseLong(tok.nextToken());
- return entry;
- } catch (NumberFormatException e) {
- throw new IllegalStateException(
- "problem parsing tethering stats for " + ifaceIn + " " + ifaceOut + ": " + e);
- }
+ return stats;
}
@Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0bbdcfb..ef50df7 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -154,6 +154,7 @@
CommonTimeManagementService commonTimeMgmtService = null;
InputManagerService inputManager = null;
TelephonyRegistry telephonyRegistry = null;
+ ConsumerIrService consumerIr = null;
// Create a handler thread just for the window manager to enjoy.
HandlerThread wmHandlerThread = new HandlerThread("WindowManager");
@@ -216,8 +217,7 @@
ServiceManager.addService("telephony.registry", telephonyRegistry);
Slog.i(TAG, "Scheduling Policy");
- ServiceManager.addService(Context.SCHEDULING_POLICY_SERVICE,
- new SchedulingPolicyService());
+ ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
AttributeCache.init(context);
@@ -284,6 +284,10 @@
vibrator = new VibratorService(context);
ServiceManager.addService("vibrator", vibrator);
+ Slog.i(TAG, "Consumer IR Service");
+ consumerIr = new ConsumerIrService(context);
+ ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr);
+
// only initialize the power service after we have started the
// lights service, content providers and the battery service.
power.init(context, lights, ActivityManagerService.self(), battery,
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index b96cf92..37fbb13 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -20,12 +20,12 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import android.os.Handler;
+import android.util.ArrayMap;
import com.android.internal.app.ProcessStats;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.TransferPipe;
@@ -54,7 +54,6 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.EventLog;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -62,6 +61,8 @@
public final class ActiveServices {
static final boolean DEBUG_SERVICE = ActivityManagerService.DEBUG_SERVICE;
static final boolean DEBUG_SERVICE_EXECUTING = ActivityManagerService.DEBUG_SERVICE_EXECUTING;
+ static final boolean DEBUG_DELAYED_SERVICE = ActivityManagerService.DEBUG_SERVICE;
+ static final boolean DEBUG_DELAYED_STATS = DEBUG_DELAYED_SERVICE;
static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
static final String TAG = ActivityManagerService.TAG;
static final String TAG_MU = ActivityManagerService.TAG_MU;
@@ -94,16 +95,24 @@
// LRU background list.
static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
+ // How long we wait for a background started service to stop itself before
+ // allowing the next pending start to run.
+ static final int BG_START_TIMEOUT = 15*1000;
+
final ActivityManagerService mAm;
- final ServiceMap mServiceMap = new ServiceMap();
+ // Maximum number of services that we allow to start in the background
+ // at the same time.
+ final int mMaxStartingBackground;
+
+ final SparseArray<ServiceMap> mServiceMap = new SparseArray<ServiceMap>();
/**
* All currently bound service connections. Keys are the IBinder of
* the client's IServiceConnection.
*/
- final HashMap<IBinder, ArrayList<ConnectionRecord>> mServiceConnections
- = new HashMap<IBinder, ArrayList<ConnectionRecord>>();
+ final ArrayMap<IBinder, ArrayList<ConnectionRecord>> mServiceConnections
+ = new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();
/**
* List of services that we have been asked to start,
@@ -126,97 +135,127 @@
final ArrayList<ServiceRecord> mStoppingServices
= new ArrayList<ServiceRecord>();
- static class ServiceMap {
+ static final class DelayingProcess extends ArrayList<ServiceRecord> {
+ long timeoout;
+ }
- private final SparseArray<HashMap<ComponentName, ServiceRecord>> mServicesByNamePerUser
- = new SparseArray<HashMap<ComponentName, ServiceRecord>>();
- private final SparseArray<HashMap<Intent.FilterComparison, ServiceRecord>>
- mServicesByIntentPerUser = new SparseArray<
- HashMap<Intent.FilterComparison, ServiceRecord>>();
+ /**
+ * Information about services for a single user.
+ */
+ class ServiceMap extends Handler {
+ final ArrayMap<ComponentName, ServiceRecord> mServicesByName
+ = new ArrayMap<ComponentName, ServiceRecord>();
+ final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent
+ = new ArrayMap<Intent.FilterComparison, ServiceRecord>();
- ServiceRecord getServiceByName(ComponentName name, int callingUser) {
- // TODO: Deal with global services
- if (DEBUG_MU)
- Slog.v(TAG_MU, "getServiceByName(" + name + "), callingUser = " + callingUser);
- return getServices(callingUser).get(name);
- }
+ final ArrayList<ServiceRecord> mDelayedStartList
+ = new ArrayList<ServiceRecord>();
+ /* XXX eventually I'd like to have this based on processes instead of services.
+ * That is, if we try to start two services in a row both running in the same
+ * process, this should be one entry in mStartingBackground for that one process
+ * that remains until all services in it are done.
+ final ArrayMap<ProcessRecord, DelayingProcess> mStartingBackgroundMap
+ = new ArrayMap<ProcessRecord, DelayingProcess>();
+ final ArrayList<DelayingProcess> mStartingProcessList
+ = new ArrayList<DelayingProcess>();
+ */
- ServiceRecord getServiceByName(ComponentName name) {
- return getServiceByName(name, -1);
- }
+ final ArrayList<ServiceRecord> mStartingBackground
+ = new ArrayList<ServiceRecord>();
- ServiceRecord getServiceByIntent(Intent.FilterComparison filter, int callingUser) {
- // TODO: Deal with global services
- if (DEBUG_MU)
- Slog.v(TAG_MU, "getServiceByIntent(" + filter + "), callingUser = " + callingUser);
- return getServicesByIntent(callingUser).get(filter);
- }
+ static final int MSG_BG_START_TIMEOUT = 1;
- ServiceRecord getServiceByIntent(Intent.FilterComparison filter) {
- return getServiceByIntent(filter, -1);
- }
-
- void putServiceByName(ComponentName name, int callingUser, ServiceRecord value) {
- // TODO: Deal with global services
- getServices(callingUser).put(name, value);
- }
-
- void putServiceByIntent(Intent.FilterComparison filter, int callingUser,
- ServiceRecord value) {
- // TODO: Deal with global services
- getServicesByIntent(callingUser).put(filter, value);
- }
-
- void removeServiceByName(ComponentName name, int callingUser) {
- // TODO: Deal with global services
- ServiceRecord removed = getServices(callingUser).remove(name);
- if (DEBUG_MU)
- Slog.v(TAG, "removeServiceByName user=" + callingUser + " name=" + name
- + " removed=" + removed);
- }
-
- void removeServiceByIntent(Intent.FilterComparison filter, int callingUser) {
- // TODO: Deal with global services
- ServiceRecord removed = getServicesByIntent(callingUser).remove(filter);
- if (DEBUG_MU)
- Slog.v(TAG_MU, "removeServiceByIntent user=" + callingUser + " intent=" + filter
- + " removed=" + removed);
- }
-
- Collection<ServiceRecord> getAllServices(int callingUser) {
- // TODO: Deal with global services
- return getServices(callingUser).values();
- }
-
- private HashMap<ComponentName, ServiceRecord> getServices(int callingUser) {
- HashMap<ComponentName, ServiceRecord> map = mServicesByNamePerUser.get(callingUser);
- if (map == null) {
- map = new HashMap<ComponentName, ServiceRecord>();
- mServicesByNamePerUser.put(callingUser, map);
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_BG_START_TIMEOUT: {
+ synchronized (mAm) {
+ rescheduleDelayedStarts();
+ }
+ } break;
}
- return map;
}
- private HashMap<Intent.FilterComparison, ServiceRecord> getServicesByIntent(
- int callingUser) {
- HashMap<Intent.FilterComparison, ServiceRecord> map
- = mServicesByIntentPerUser.get(callingUser);
- if (map == null) {
- map = new HashMap<Intent.FilterComparison, ServiceRecord>();
- mServicesByIntentPerUser.put(callingUser, map);
+ void ensureNotStartingBackground(ServiceRecord r) {
+ if (mStartingBackground.remove(r)) {
+ if (DEBUG_DELAYED_STATS) Slog.v(TAG, "No longer background starting: " + r);
+ rescheduleDelayedStarts();
}
- return map;
+ if (mDelayedStartList.remove(r)) {
+ if (DEBUG_DELAYED_STATS) Slog.v(TAG, "No longer delaying start: " + r);
+ }
+ }
+
+ void rescheduleDelayedStarts() {
+ removeMessages(MSG_BG_START_TIMEOUT);
+ final long now = SystemClock.uptimeMillis();
+ for (int i=0, N=mStartingBackground.size(); i<N; i++) {
+ ServiceRecord r = mStartingBackground.get(i);
+ if (r.startingBgTimeout <= now) {
+ Slog.i(TAG, "Waited long enough for: " + r);
+ mStartingBackground.remove(i);
+ N--;
+ }
+ }
+ while (mDelayedStartList.size() > 0
+ && mStartingBackground.size() < mMaxStartingBackground) {
+ ServiceRecord r = mDelayedStartList.remove(0);
+ if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (exec next): " + r);
+ if (r.pendingStarts.size() <= 0) {
+ Slog.w(TAG, "**** NO PENDING STARTS! " + r + " startReq=" + r.startRequested
+ + " delayedStop=" + r.delayedStop);
+ }
+ if (DEBUG_DELAYED_SERVICE) {
+ if (mDelayedStartList.size() > 0) {
+ Slog.v(TAG, "Remaining delayed list:");
+ for (int i=0; i<mDelayedStartList.size(); i++) {
+ Slog.v(TAG, " #" + i + ": " + mDelayedStartList.get(i));
+ }
+ }
+ }
+ r.delayed = false;
+ startServiceInnerLocked(this, r.pendingStarts.get(0).intent, r, false, true);
+ }
+ if (mStartingBackground.size() > 0) {
+ ServiceRecord next = mStartingBackground.get(0);
+ long when = next.startingBgTimeout > now ? next.startingBgTimeout : now;
+ if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Top bg start is " + next
+ + ", can delay others up to " + when);
+ Message msg = obtainMessage(MSG_BG_START_TIMEOUT);
+ sendMessageAtTime(msg, when);
+ }
}
}
public ActiveServices(ActivityManagerService service) {
mAm = service;
+ mMaxStartingBackground = ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
+ }
+
+ ServiceRecord getServiceByName(ComponentName name, int callingUser) {
+ // TODO: Deal with global services
+ if (DEBUG_MU)
+ Slog.v(TAG_MU, "getServiceByName(" + name + "), callingUser = " + callingUser);
+ return getServiceMap(callingUser).mServicesByName.get(name);
+ }
+
+ private ServiceMap getServiceMap(int callingUser) {
+ ServiceMap smap = mServiceMap.get(callingUser);
+ if (smap == null) {
+ smap = new ServiceMap();
+ mServiceMap.put(callingUser, smap);
+ }
+ return smap;
+ }
+
+ ArrayMap<ComponentName, ServiceRecord> getServices(int callingUser) {
+ return getServiceMap(callingUser).mServicesByName;
}
ComponentName startServiceLocked(IApplicationThread caller,
Intent service, String resolvedType,
int callingPid, int callingUid, int userId) {
- if (DEBUG_SERVICE) Slog.v(TAG, "startService: " + service
+ if (DEBUG_DELAYED_STATS) Slog.v(TAG, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
final boolean callerFg;
@@ -252,13 +291,82 @@
}
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
+ r.delayedStop = false;
+ r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
+ service, neededGrants));
+
+ final ServiceMap smap = getServiceMap(r.userId);
+ boolean addToStarting = false;
+ if (!callerFg && r.app == null && mAm.mStartedUsers.get(r.userId) != null) {
+ ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid);
+ if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
+ // If this is not coming from a foreground caller, then we may want
+ // to delay the start if there are already other background services
+ // that are starting. This is to avoid process start spam when lots
+ // of applications are all handling things like connectivity broadcasts.
+ // We only do this for cached processes, because otherwise an application
+ // can have assumptions about calling startService() for a service to run
+ // in its own process, and for that process to not be killed before the
+ // service is started. This is especially the case for receivers, which
+ // may start a service in onReceive() to do some additional work and have
+ // initialized some global state as part of that.
+ if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Potential start delay of " + r + " in "
+ + proc);
+ if (r.delayed) {
+ // This service is already scheduled for a delayed start; just leave
+ // it still waiting.
+ if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Continuing to delay: " + r);
+ return r.name;
+ }
+ if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
+ // Something else is starting, delay!
+ Slog.i(TAG, "Delaying start of: " + r);
+ smap.mDelayedStartList.add(r);
+ r.delayed = true;
+ return r.name;
+ }
+ if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Not delaying: " + r);
+ addToStarting = true;
+ } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
+ // We slightly loosen when we will enqueue this new service as a background
+ // starting service we are waiting for, to also include processes that are
+ // currently running other services or receivers.
+ addToStarting = true;
+ if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Not delaying, but counting as bg: " + r);
+ } else if (DEBUG_DELAYED_STATS) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("Not potential delay (state=").append(proc.curProcState)
+ .append(' ').append(proc.adjType);
+ String reason = proc.makeAdjReason();
+ if (reason != null) {
+ sb.append(' ');
+ sb.append(reason);
+ }
+ sb.append("): ");
+ sb.append(r.toString());
+ Slog.v(TAG, sb.toString());
+ }
+ } else if (DEBUG_DELAYED_STATS) {
+ if (callerFg) {
+ Slog.v(TAG, "Not potential delay (callerFg=" + callerFg + " uid="
+ + callingUid + " pid=" + callingPid + "): " + r);
+ } else if (r.app != null) {
+ Slog.v(TAG, "Not potential delay (cur app=" + r.app + "): " + r);
+ } else {
+ Slog.v(TAG, "Not potential delay (user " + r.userId + " not started): " + r);
+ }
+ }
+
+ return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
+ }
+
+ ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,
+ ServiceRecord r, boolean callerFg, boolean addToStarting) {
ProcessStats.ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
}
r.callStart = false;
- r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
- service, neededGrants));
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
}
@@ -266,10 +374,37 @@
if (error != null) {
return new ComponentName("!!", error);
}
+
+ if (r.startRequested && addToStarting) {
+ boolean first = smap.mStartingBackground.size() == 0;
+ smap.mStartingBackground.add(r);
+ r.startingBgTimeout = SystemClock.uptimeMillis() + BG_START_TIMEOUT;
+ if (DEBUG_DELAYED_SERVICE) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.v(TAG, "Starting background (first=" + first + "): " + r, here);
+ } else if (DEBUG_DELAYED_STATS) {
+ Slog.v(TAG, "Starting background (first=" + first + "): " + r);
+ }
+ if (first) {
+ smap.rescheduleDelayedStarts();
+ }
+ } else if (callerFg) {
+ smap.ensureNotStartingBackground(r);
+ }
+
return r.name;
}
private void stopServiceLocked(ServiceRecord service) {
+ if (service.delayed) {
+ // If service isn't actually running, but is is being held in the
+ // delayed list, then we need to keep it started but note that it
+ // should be stopped once no longer delayed.
+ if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Delaying stop of pending: " + service);
+ service.delayedStop = true;
+ return;
+ }
synchronized (service.stats.getBatteryStats()) {
service.stats.stopRunningLocked();
}
@@ -409,6 +544,7 @@
if (r.app != null) {
updateServiceForegroundLocked(r.app, true);
}
+ getServiceMap(r.userId).ensureNotStartingBackground(r);
} else {
if (r.isForeground) {
r.isForeground = false;
@@ -591,6 +727,9 @@
} else if (!b.intent.requested) {
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
+
+ getServiceMap(s.userId).ensureNotStartingBackground(s);
+
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -713,7 +852,7 @@
private final ServiceRecord findServiceLocked(ComponentName name,
IBinder token, int userId) {
- ServiceRecord r = mServiceMap.getServiceByName(name, userId);
+ ServiceRecord r = getServiceByName(name, userId);
return r == token ? r : null;
}
@@ -751,12 +890,14 @@
userId = mAm.handleIncomingUser(callingPid, callingUid, userId,
false, true, "service", null);
- if (service.getComponent() != null) {
- r = mServiceMap.getServiceByName(service.getComponent(), userId);
+ ServiceMap smap = getServiceMap(userId);
+ final ComponentName comp = service.getComponent();
+ if (comp != null) {
+ r = smap.mServicesByName.get(comp);
}
if (r == null) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
- r = mServiceMap.getServiceByIntent(filter, userId);
+ r = smap.mServicesByIntent.get(filter);
}
if (r == null) {
try {
@@ -777,14 +918,15 @@
if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
sInfo.name, sInfo.flags)) {
userId = 0;
+ smap = getServiceMap(0);
}
sInfo = new ServiceInfo(sInfo);
sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
}
- r = mServiceMap.getServiceByName(name, userId);
+ r = smap.mServicesByName.get(name);
if (r == null && createIfNeeded) {
- Intent.FilterComparison filter = new Intent.FilterComparison(
- service.cloneFilter());
+ Intent.FilterComparison filter
+ = new Intent.FilterComparison(service.cloneFilter());
ServiceRestarter res = new ServiceRestarter();
BatteryStatsImpl.Uid.Pkg.Serv ss = null;
BatteryStatsImpl stats = mAm.mBatteryStatsService.getActiveStatistics();
@@ -795,8 +937,8 @@
}
r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
res.setService(r);
- mServiceMap.putServiceByName(name, UserHandle.getUserId(r.appInfo.uid), r);
- mServiceMap.putServiceByIntent(filter, UserHandle.getUserId(r.appInfo.uid), r);
+ smap.mServicesByName.put(name, r);
+ smap.mServicesByIntent.put(filter, r);
// Make sure this component isn't in the pending list.
int N = mPendingServices.size();
@@ -842,9 +984,9 @@
}
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
- if (DEBUG_SERVICE) Log.v(TAG, ">>> EXECUTING "
+ if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING "
+ why + " of " + r + " in app " + r.app);
- else if (DEBUG_SERVICE_EXECUTING) Log.v(TAG, ">>> EXECUTING "
+ else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, ">>> EXECUTING "
+ why + " of " + r.shortName);
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0) {
@@ -1052,6 +1194,13 @@
// restarting state.
mRestartingServices.remove(r);
+ // Make sure this service is no longer considered delayed, we are starting it now.
+ if (r.delayed) {
+ if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (bring up): " + r);
+ getServiceMap(r.userId).mDelayedStartList.remove(r);
+ r.delayed = false;
+ }
+
// Make sure that the user who owns this service is started. If not,
// we don't want to allow it to run.
if (mAm.mStartedUsers.get(r.userId) == null) {
@@ -1126,6 +1275,15 @@
mPendingServices.add(r);
}
+ if (r.delayedStop) {
+ // Oh and hey we've already been asked to stop!
+ r.delayedStop = false;
+ if (r.startRequested) {
+ if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Applying delayed stop (in bring up): " + r);
+ stopServiceLocked(r);
+ }
+ }
+
return null;
}
@@ -1188,6 +1346,21 @@
}
sendServiceArgsLocked(r, execInFg, true);
+
+ if (r.delayed) {
+ if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r);
+ getServiceMap(r.userId).mDelayedStartList.remove(r);
+ r.delayed = false;
+ }
+
+ if (r.delayedStop) {
+ // Oh and hey we've already been asked to stop!
+ r.delayedStop = false;
+ if (r.startRequested) {
+ if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Applying delayed stop (from start): " + r);
+ stopServiceLocked(r);
+ }
+ }
}
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
@@ -1246,11 +1419,12 @@
//Slog.i(TAG, "Bring down service:");
//r.dump(" ");
- // Does it still need to run?
+ // Are we still explicitly being asked to run?
if (r.startRequested) {
return;
}
+ // Is someone still bound to us keepign us running?
if (!knowConn) {
hasConn = r.hasAutoCreateConnections();
}
@@ -1258,6 +1432,11 @@
return;
}
+ // Are we in the process of launching?
+ if (mPendingServices.contains(r)) {
+ return;
+ }
+
bringDownServiceLocked(r);
}
@@ -1310,8 +1489,9 @@
EventLogTags.writeAmDestroyService(
r.userId, System.identityHashCode(r), (r.app != null) ? r.app.pid : -1);
- mServiceMap.removeServiceByName(r.name, r.userId);
- mServiceMap.removeServiceByIntent(r.intent, r.userId);
+ final ServiceMap smap = getServiceMap(r.userId);
+ smap.mServicesByName.remove(r.name);
+ smap.mServicesByIntent.remove(r.intent);
r.totalRestartCount = 0;
unscheduleServiceRestartLocked(r);
@@ -1379,6 +1559,8 @@
r.tracker = null;
}
}
+
+ smap.ensureNotStartingBackground(r);
}
void removeConnectionLocked(
@@ -1617,10 +1799,11 @@
private boolean collectForceStopServicesLocked(String name, int userId,
boolean evenPersistent, boolean doit,
- HashMap<ComponentName, ServiceRecord> services,
+ ArrayMap<ComponentName, ServiceRecord> services,
ArrayList<ServiceRecord> result) {
boolean didSomething = false;
- for (ServiceRecord service : services.values()) {
+ for (int i=0; i<services.size(); i++) {
+ ServiceRecord service = services.valueAt(i);
if ((name == null || service.packageName.equals(name))
&& (service.app == null || evenPersistent || !service.app.persistent)) {
if (!doit) {
@@ -1643,17 +1826,17 @@
boolean didSomething = false;
ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
if (userId == UserHandle.USER_ALL) {
- for (int i=0; i<mServiceMap.mServicesByNamePerUser.size(); i++) {
+ for (int i=0; i<mServiceMap.size(); i++) {
didSomething |= collectForceStopServicesLocked(name, userId, evenPersistent,
- doit, mServiceMap.mServicesByNamePerUser.valueAt(i), services);
+ doit, mServiceMap.valueAt(i).mServicesByName, services);
if (!doit && didSomething) {
return true;
}
}
} else {
- HashMap<ComponentName, ServiceRecord> items
- = mServiceMap.mServicesByNamePerUser.get(userId);
- if (items != null) {
+ ServiceMap smap = mServiceMap.valueAt(userId);
+ if (smap != null) {
+ ArrayMap<ComponentName, ServiceRecord> items = smap.mServicesByName;
didSomething = collectForceStopServicesLocked(name, userId, evenPersistent,
doit, items, services);
}
@@ -1668,7 +1851,9 @@
void cleanUpRemovedTaskLocked(TaskRecord tr, ComponentName component, Intent baseIntent) {
ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
- for (ServiceRecord sr : mServiceMap.getAllServices(tr.userId)) {
+ ArrayMap<ComponentName, ServiceRecord> alls = getServices(tr.userId);
+ for (int i=0; i<alls.size(); i++) {
+ ServiceRecord sr = alls.valueAt(i);
if (sr.packageName.equals(component.getPackageName())) {
services.add(sr);
}
@@ -1862,12 +2047,10 @@
uid) == PackageManager.PERMISSION_GRANTED) {
int[] users = mAm.getUsersLocked();
for (int ui=0; ui<users.length && res.size() < maxNum; ui++) {
- if (mServiceMap.getAllServices(users[ui]).size() > 0) {
- Iterator<ServiceRecord> it = mServiceMap.getAllServices(
- users[ui]).iterator();
- while (it.hasNext() && res.size() < maxNum) {
- res.add(makeRunningServiceInfoLocked(it.next()));
- }
+ ArrayMap<ComponentName, ServiceRecord> alls = getServices(users[ui]);
+ for (int i=0; i<alls.size() && res.size() < maxNum; i++) {
+ ServiceRecord sr = alls.valueAt(i);
+ res.add(makeRunningServiceInfoLocked(sr));
}
}
@@ -1880,12 +2063,10 @@
}
} else {
int userId = UserHandle.getUserId(uid);
- if (mServiceMap.getAllServices(userId).size() > 0) {
- Iterator<ServiceRecord> it
- = mServiceMap.getAllServices(userId).iterator();
- while (it.hasNext() && res.size() < maxNum) {
- res.add(makeRunningServiceInfoLocked(it.next()));
- }
+ ArrayMap<ComponentName, ServiceRecord> alls = getServices(userId);
+ for (int i=0; i<alls.size() && res.size() < maxNum; i++) {
+ ServiceRecord sr = alls.valueAt(i);
+ res.add(makeRunningServiceInfoLocked(sr));
}
for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
@@ -1907,7 +2088,7 @@
public PendingIntent getRunningServiceControlPanelLocked(ComponentName name) {
int userId = UserHandle.getUserId(Binder.getCallingUid());
- ServiceRecord r = mServiceMap.getServiceByName(name, userId);
+ ServiceRecord r = getServiceByName(name, userId);
if (r != null) {
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> conn = r.connections.valueAt(conni);
@@ -1974,28 +2155,27 @@
try {
int[] users = mAm.getUsersLocked();
for (int user : users) {
- if (mServiceMap.getAllServices(user).size() > 0) {
- boolean printed = false;
+ ServiceMap smap = getServiceMap(user);
+ boolean printed = false;
+ if (smap.mServicesByName.size() > 0) {
long nowReal = SystemClock.elapsedRealtime();
- Iterator<ServiceRecord> it = mServiceMap.getAllServices(
- user).iterator();
needSep = false;
- while (it.hasNext()) {
- ServiceRecord r = it.next();
+ for (int si=0; si<smap.mServicesByName.size(); si++) {
+ ServiceRecord r = smap.mServicesByName.valueAt(si);
if (!matcher.match(r, r.name)) {
continue;
}
if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
continue;
}
- printedAnything = true;
if (!printed) {
- if (user != 0) {
+ if (printedAnything) {
pw.println();
}
pw.println(" User " + user + " active services:");
printed = true;
}
+ printedAnything = true;
if (needSep) {
pw.println();
}
@@ -2054,9 +2234,47 @@
}
needSep |= printed;
}
+ printed = false;
+ for (int si=0, SN=smap.mDelayedStartList.size(); si<SN; si++) {
+ ServiceRecord r = smap.mDelayedStartList.get(si);
+ if (!matcher.match(r, r.name)) {
+ continue;
+ }
+ if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
+ continue;
+ }
+ if (!printed) {
+ if (printedAnything) {
+ pw.println();
+ }
+ pw.println(" User " + user + " delayed start services:");
+ printed = true;
+ }
+ printedAnything = true;
+ pw.print(" * Delayed start "); pw.println(r);
+ }
+ printed = false;
+ for (int si=0, SN=smap.mStartingBackground.size(); si<SN; si++) {
+ ServiceRecord r = smap.mStartingBackground.get(si);
+ if (!matcher.match(r, r.name)) {
+ continue;
+ }
+ if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
+ continue;
+ }
+ if (!printed) {
+ if (printedAnything) {
+ pw.println();
+ }
+ pw.println(" User " + user + " starting in background:");
+ printed = true;
+ }
+ printedAnything = true;
+ pw.print(" * Starting bg "); pw.println(r);
+ }
}
} catch (Exception e) {
- Log.w(TAG, "Exception in dumpServicesLocked", e);
+ Slog.w(TAG, "Exception in dumpServicesLocked", e);
}
if (mPendingServices.size() > 0) {
@@ -2129,31 +2347,27 @@
}
if (dumpAll) {
- if (mServiceConnections.size() > 0) {
- boolean printed = false;
- Iterator<ArrayList<ConnectionRecord>> it
- = mServiceConnections.values().iterator();
- while (it.hasNext()) {
- ArrayList<ConnectionRecord> r = it.next();
- for (int i=0; i<r.size(); i++) {
- ConnectionRecord cr = r.get(i);
- if (!matcher.match(cr.binding.service, cr.binding.service.name)) {
- continue;
- }
- if (dumpPackage != null && (cr.binding.client == null
- || !dumpPackage.equals(cr.binding.client.info.packageName))) {
- continue;
- }
- printedAnything = true;
- if (!printed) {
- if (needSep) pw.println();
- needSep = true;
- pw.println(" Connection bindings to services:");
- printed = true;
- }
- pw.print(" * "); pw.println(cr);
- cr.dump(pw, " ");
+ boolean printed = false;
+ for (int ic=0; ic<mServiceConnections.size(); ic++) {
+ ArrayList<ConnectionRecord> r = mServiceConnections.valueAt(ic);
+ for (int i=0; i<r.size(); i++) {
+ ConnectionRecord cr = r.get(i);
+ if (!matcher.match(cr.binding.service, cr.binding.service.name)) {
+ continue;
}
+ if (dumpPackage != null && (cr.binding.client == null
+ || !dumpPackage.equals(cr.binding.client.info.packageName))) {
+ continue;
+ }
+ printedAnything = true;
+ if (!printed) {
+ if (needSep) pw.println();
+ needSep = true;
+ pw.println(" Connection bindings to services:");
+ printed = true;
+ }
+ pw.print(" * "); pw.println(cr);
+ cr.dump(pw, " ");
}
}
}
@@ -2179,7 +2393,9 @@
int[] users = mAm.getUsersLocked();
if ("all".equals(name)) {
for (int user : users) {
- for (ServiceRecord r1 : mServiceMap.getAllServices(user)) {
+ ArrayMap<ComponentName, ServiceRecord> alls = getServices(user);
+ for (int i=0; i<alls.size(); i++) {
+ ServiceRecord r1 = alls.valueAt(i);
services.add(r1);
}
}
@@ -2198,7 +2414,9 @@
}
for (int user : users) {
- for (ServiceRecord r1 : mServiceMap.getAllServices(user)) {
+ ArrayMap<ComponentName, ServiceRecord> alls = getServices(user);
+ for (int i=0; i<alls.size(); i++) {
+ ServiceRecord r1 = alls.valueAt(i);
if (componentName != null) {
if (r1.name.equals(componentName)) {
services.add(r1);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 1e3fb40..80f4b00 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -172,7 +172,6 @@
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
@@ -187,7 +186,6 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -314,10 +312,6 @@
// to respond with the result.
static final int PENDING_ASSIST_EXTRAS_TIMEOUT = 500;
- // Index for assist context bundle pertaining to the top activity. Non-negative indices
- // correspond to assist context bundles from foreground services.
- static final int TOP_ACTIVITY_ASSIST_EXTRAS_INDEX = -1;
-
static final int MY_PID = Process.myPid();
static final String[] EMPTY_STRING_ARRAY = new String[0];
@@ -394,30 +388,16 @@
public class PendingAssistExtras extends Binder implements Runnable {
public final ActivityRecord activity;
- public final List<ServiceRecord> services;
- public int numPending;
- public int numRespondedServices = 0;
- public Bundle activityExtras = null;
- public Bundle[] servicesExtras;
- public PendingAssistExtras(ActivityRecord _activity, List<ServiceRecord> _services) {
+ public boolean haveResult = false;
+ public Bundle result = null;
+ public PendingAssistExtras(ActivityRecord _activity) {
activity = _activity;
- services = _services;
- numPending = services.size() + 1;
}
@Override
public void run() {
- if (activityExtras == null) {
- Slog.w(TAG, "getAssistContextExtras failed: timeout retrieving from activtity "
- + activity);
- }
- for (int i = 0; i < services.size(); i++) {
- if (servicesExtras[i] == null) {
- Slog.w(TAG, "getAssistContextExtras failed: timeout retrieving from service "
- + i + " " + services.get(i));
- }
- }
+ Slog.w(TAG, "getAssistContextExtras failed: timeout retrieving from " + activity);
synchronized (this) {
- numPending = 0;
+ haveResult = true;
notifyAll();
}
}
@@ -869,10 +849,39 @@
int mNewNumServiceProcs = 0;
/**
- * System monitoring: number of processes that died since the last
- * N procs were started.
+ * Allow the current computed overall memory level of the system to go down?
+ * This is set to false when we are killing processes for reasons other than
+ * memory management, so that the now smaller process list will not be taken as
+ * an indication that memory is tighter.
*/
- int[] mProcDeaths = new int[20];
+ boolean mAllowLowerMemLevel = false;
+
+ /**
+ * The last computed memory level, for holding when we are in a state that
+ * processes are going away for other reasons.
+ */
+ int mLastMemoryLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+
+ /**
+ * The last total number of process we have, to determine if changes actually look
+ * like a shrinking number of process due to lower RAM.
+ */
+ int mLastNumProcesses;
+
+ /**
+ * The uptime of the last time we performed idle maintenance.
+ */
+ long mLastIdleTime = SystemClock.uptimeMillis();
+
+ /**
+ * Total time spent with RAM that has been added in the past since the last idle time.
+ */
+ long mLowRamTimeSinceLastIdle = 0;
+
+ /**
+ * If RAM is currently low, when that horrible situatin started.
+ */
+ long mLowRamStartTime = 0;
/**
* This is set if we had to do a delayed dexopt of an app before launching
@@ -997,17 +1006,18 @@
static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25;
static final int SHOW_STRICT_MODE_VIOLATION_MSG = 26;
static final int CHECK_EXCESSIVE_WAKE_LOCKS_MSG = 27;
- static final int CLEAR_DNS_CACHE = 28;
- static final int UPDATE_HTTP_PROXY = 29;
+ static final int CLEAR_DNS_CACHE_MSG = 28;
+ static final int UPDATE_HTTP_PROXY_MSG = 29;
static final int SHOW_COMPAT_MODE_DIALOG_MSG = 30;
static final int DISPATCH_PROCESSES_CHANGED = 31;
static final int DISPATCH_PROCESS_DIED = 32;
- static final int REPORT_MEM_USAGE = 33;
+ static final int REPORT_MEM_USAGE_MSG = 33;
static final int REPORT_USER_SWITCH_MSG = 34;
static final int CONTINUE_USER_SWITCH_MSG = 35;
static final int USER_SWITCH_TIMEOUT_MSG = 36;
static final int IMMERSIVE_MODE_LOCK_MSG = 37;
- static final int PERSIST_URI_GRANTS = 38;
+ static final int PERSIST_URI_GRANTS_MSG = 38;
+ static final int REQUEST_ALL_PSS_MSG = 39;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1188,7 +1198,7 @@
}
}
} break;
- case CLEAR_DNS_CACHE: {
+ case CLEAR_DNS_CACHE_MSG: {
synchronized (ActivityManagerService.this) {
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = mLruProcesses.get(i);
@@ -1202,7 +1212,7 @@
}
}
} break;
- case UPDATE_HTTP_PROXY: {
+ case UPDATE_HTTP_PROXY_MSG: {
ProxyProperties proxy = (ProxyProperties)msg.obj;
String host = "";
String port = "";
@@ -1388,65 +1398,168 @@
dispatchProcessDied(pid, uid);
break;
}
- case REPORT_MEM_USAGE: {
- boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
- if (!isDebuggable) {
- return;
- }
- synchronized (ActivityManagerService.this) {
- long now = SystemClock.uptimeMillis();
- if (now < (mLastMemUsageReportTime+5*60*1000)) {
- // Don't report more than every 5 minutes to somewhat
- // avoid spamming.
- return;
- }
- mLastMemUsageReportTime = now;
- }
+ case REPORT_MEM_USAGE_MSG: {
+ final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj;
Thread thread = new Thread() {
@Override public void run() {
- StringBuilder dropBuilder = new StringBuilder(1024);
+ final SparseArray<ProcessMemInfo> infoMap
+ = new SparseArray<ProcessMemInfo>(memInfos.size());
+ for (int i=0, N=memInfos.size(); i<N; i++) {
+ ProcessMemInfo mi = memInfos.get(i);
+ infoMap.put(mi.pid, mi);
+ }
+ updateCpuStatsNow();
+ synchronized (mProcessCpuThread) {
+ final int N = mProcessCpuTracker.countStats();
+ for (int i=0; i<N; i++) {
+ ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+ if (st.vsize > 0) {
+ long pss = Debug.getPss(st.pid, null);
+ if (pss > 0) {
+ if (infoMap.indexOfKey(st.pid) < 0) {
+ ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
+ ProcessList.NATIVE_ADJ, -1, "native", null);
+ mi.pss = pss;
+ memInfos.add(mi);
+ }
+ }
+ }
+ }
+ }
+
+ long totalPss = 0;
+ for (int i=0, N=memInfos.size(); i<N; i++) {
+ ProcessMemInfo mi = memInfos.get(i);
+ if (mi.pss == 0) {
+ mi.pss = Debug.getPss(mi.pid, null);
+ }
+ totalPss += mi.pss;
+ }
+ Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
+ @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
+ if (lhs.oomAdj != rhs.oomAdj) {
+ return lhs.oomAdj < rhs.oomAdj ? -1 : 1;
+ }
+ if (lhs.pss != rhs.pss) {
+ return lhs.pss < rhs.pss ? 1 : -1;
+ }
+ return 0;
+ }
+ });
+
+ StringBuilder tag = new StringBuilder(128);
+ StringBuilder stack = new StringBuilder(128);
+ tag.append("Low on memory -- ");
+ appendMemBucket(tag, totalPss, "total", false);
+ appendMemBucket(stack, totalPss, "total", true);
+
StringBuilder logBuilder = new StringBuilder(1024);
+ logBuilder.append("Low on memory:\n");
+
+ boolean firstLine = true;
+ int lastOomAdj = Integer.MIN_VALUE;
+ for (int i=0, N=memInfos.size(); i<N; i++) {
+ ProcessMemInfo mi = memInfos.get(i);
+
+ if (mi.oomAdj != ProcessList.NATIVE_ADJ
+ && (mi.oomAdj < ProcessList.SERVICE_ADJ
+ || mi.oomAdj == ProcessList.HOME_APP_ADJ
+ || mi.oomAdj == ProcessList.PREVIOUS_APP_ADJ)) {
+ if (lastOomAdj != mi.oomAdj) {
+ lastOomAdj = mi.oomAdj;
+ if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+ tag.append(" / ");
+ }
+ if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+ if (firstLine) {
+ stack.append(":");
+ firstLine = false;
+ }
+ stack.append("\n\t at ");
+ } else {
+ stack.append("$");
+ }
+ } else {
+ tag.append(" ");
+ stack.append("$");
+ }
+ if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+ appendMemBucket(tag, mi.pss, mi.name, false);
+ }
+ appendMemBucket(stack, mi.pss, mi.name, true);
+ if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ
+ && ((i+1) >= N || memInfos.get(i+1).oomAdj != lastOomAdj)) {
+ stack.append("(");
+ for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
+ if (DUMP_MEM_OOM_ADJ[k] == mi.oomAdj) {
+ stack.append(DUMP_MEM_OOM_LABEL[k]);
+ stack.append(":");
+ stack.append(DUMP_MEM_OOM_ADJ[k]);
+ }
+ }
+ stack.append(")");
+ }
+ }
+
+ logBuilder.append(" ");
+ logBuilder.append(ProcessList.makeOomAdjString(mi.oomAdj));
+ logBuilder.append(' ');
+ logBuilder.append(ProcessList.makeProcStateString(mi.procState));
+ logBuilder.append(' ');
+ ProcessList.appendRamKb(logBuilder, mi.pss);
+ logBuilder.append(" kB: ");
+ logBuilder.append(mi.name);
+ logBuilder.append(" (");
+ logBuilder.append(mi.pid);
+ logBuilder.append(") ");
+ logBuilder.append(mi.adjType);
+ logBuilder.append('\n');
+ if (mi.adjReason != null) {
+ logBuilder.append(" ");
+ logBuilder.append(mi.adjReason);
+ logBuilder.append('\n');
+ }
+ }
+
+ logBuilder.append(" ");
+ ProcessList.appendRamKb(logBuilder, totalPss);
+ logBuilder.append(" kB: TOTAL\n");
+
+ long[] infos = new long[Debug.MEMINFO_COUNT];
+ Debug.getMemInfo(infos);
+ logBuilder.append(" MemInfo: ");
+ logBuilder.append(infos[Debug.MEMINFO_SLAB]).append(" kB slab, ");
+ logBuilder.append(infos[Debug.MEMINFO_SHMEM]).append(" kB shmem, ");
+ logBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
+ logBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
+ logBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
+
+ Slog.i(TAG, logBuilder.toString());
+
+ StringBuilder dropBuilder = new StringBuilder(1024);
+ /*
StringWriter oomSw = new StringWriter();
PrintWriter oomPw = new FastPrintWriter(oomSw, false, 256);
StringWriter catSw = new StringWriter();
PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
String[] emptyArgs = new String[] { };
- StringBuilder tag = new StringBuilder(128);
- StringBuilder stack = new StringBuilder(128);
- tag.append("Low on memory -- ");
- dumpApplicationMemoryUsage(null, oomPw, " ", emptyArgs, true, catPw,
- tag, stack);
+ dumpApplicationMemoryUsage(null, oomPw, " ", emptyArgs, true, catPw);
+ oomPw.flush();
+ String oomString = oomSw.toString();
+ */
dropBuilder.append(stack);
dropBuilder.append('\n');
dropBuilder.append('\n');
- oomPw.flush();
- String oomString = oomSw.toString();
+ dropBuilder.append(logBuilder);
+ dropBuilder.append('\n');
+ /*
dropBuilder.append(oomString);
dropBuilder.append('\n');
- logBuilder.append(oomString);
- try {
- java.lang.Process proc = Runtime.getRuntime().exec(new String[] {
- "procrank", });
- final InputStreamReader converter = new InputStreamReader(
- proc.getInputStream());
- BufferedReader in = new BufferedReader(converter);
- String line;
- while (true) {
- line = in.readLine();
- if (line == null) {
- break;
- }
- if (line.length() > 0) {
- logBuilder.append(line);
- logBuilder.append('\n');
- }
- dropBuilder.append(line);
- dropBuilder.append('\n');
- }
- converter.close();
- } catch (IOException e) {
- }
+ */
+ StringWriter catSw = new StringWriter();
synchronized (ActivityManagerService.this) {
+ PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
+ String[] emptyArgs = new String[] { };
catPw.println();
dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null);
catPw.println();
@@ -1454,12 +1567,13 @@
false, false, null);
catPw.println();
dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null);
+ catPw.flush();
}
- catPw.flush();
dropBuilder.append(catSw.toString());
addErrorToDropBox("lowmem", null, "system_server", null,
null, tag.toString(), dropBuilder.toString(), null, null);
- Slog.i(TAG, logBuilder.toString());
+ //Slog.i(TAG, "Sent to dropbox:");
+ //Slog.i(TAG, dropBuilder.toString());
synchronized (ActivityManagerService.this) {
long now = SystemClock.uptimeMillis();
if (mLastMemUsageReportTime < now) {
@@ -1498,10 +1612,14 @@
}
break;
}
- case PERSIST_URI_GRANTS: {
+ case PERSIST_URI_GRANTS_MSG: {
writeGrantedUriPermissions();
break;
}
+ case REQUEST_ALL_PSS_MSG: {
+ requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
+ break;
+ }
}
}
};
@@ -1545,6 +1663,10 @@
num++;
proc.lastPssTime = SystemClock.uptimeMillis();
proc.baseProcessTracker.addPss(pss, tmp[0], true);
+ if (proc.initialIdlePss == 0) {
+ proc.initialIdlePss = pss;
+ }
+ proc.lastPss = pss;
}
}
}
@@ -1710,8 +1832,7 @@
return;
}
- mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args,
- false, null, null, null);
+ mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null);
}
}
@@ -2166,8 +2287,7 @@
}
}
- final void updateLruProcessLocked(ProcessRecord app,
- boolean oomAdj) {
+ final void updateLruProcessLocked(ProcessRecord app, boolean oomAdj) {
mLruSeq++;
updateLruProcessInternalLocked(app, 0);
@@ -2333,9 +2453,6 @@
updateCpuStats();
- System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
- mProcDeaths[0] = 0;
-
try {
int uid = app.uid;
@@ -2485,10 +2602,17 @@
}
}
- String getHomePackageName() {
+ Intent getHomeIntent() {
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
- intent.addCategory(Intent.CATEGORY_HOME);
+ if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+ intent.addCategory(Intent.CATEGORY_HOME);
+ }
+ return intent;
+ }
+
+ String getHomePackageName() {
+ Intent intent = getHomeIntent();
ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, mCurrentUserId);
if (aInfo != null) {
final String homePackageName = aInfo.applicationInfo.packageName;
@@ -2514,13 +2638,7 @@
// error message and don't try to start anything.
return false;
}
- Intent intent = new Intent(
- mTopAction,
- mTopData != null ? Uri.parse(mTopData) : null);
- intent.setComponent(mTopComponent);
- if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
- intent.addCategory(Intent.CATEGORY_HOME);
- }
+ Intent intent = getHomeIntent();
ActivityInfo aInfo =
resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
if (aInfo != null) {
@@ -3290,11 +3408,69 @@
return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
}
+ final void doLowMemReportIfNeededLocked(ProcessRecord dyingProc) {
+ // If there are no longer any background processes running,
+ // and the app that died was not running instrumentation,
+ // then tell everyone we are now low on memory.
+ boolean haveBg = false;
+ for (int i=mLruProcesses.size()-1; i>=0; i--) {
+ ProcessRecord rec = mLruProcesses.get(i);
+ if (rec.thread != null
+ && rec.setProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+ haveBg = true;
+ break;
+ }
+ }
+
+ if (!haveBg) {
+ boolean doReport = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+ if (doReport) {
+ long now = SystemClock.uptimeMillis();
+ if (now < (mLastMemUsageReportTime+5*60*1000)) {
+ doReport = false;
+ } else {
+ mLastMemUsageReportTime = now;
+ }
+ }
+ final ArrayList<ProcessMemInfo> memInfos
+ = doReport ? new ArrayList<ProcessMemInfo>(mLruProcesses.size()) : null;
+ EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
+ long now = SystemClock.uptimeMillis();
+ for (int i=mLruProcesses.size()-1; i>=0; i--) {
+ ProcessRecord rec = mLruProcesses.get(i);
+ if (rec == dyingProc || rec.thread == null) {
+ continue;
+ }
+ if (doReport) {
+ memInfos.add(new ProcessMemInfo(rec.processName, rec.pid, rec.setAdj,
+ rec.setProcState, rec.adjType, rec.makeAdjReason()));
+ }
+ if ((rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
+ // The low memory report is overriding any current
+ // state for a GC request. Make sure to do
+ // heavy/important/visible/foreground processes first.
+ if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+ rec.lastRequestedGc = 0;
+ } else {
+ rec.lastRequestedGc = rec.lastLowMemory;
+ }
+ rec.reportLowMemory = true;
+ rec.lastLowMemory = now;
+ mProcessesToGc.remove(rec);
+ addProcessToGcListLocked(rec);
+ }
+ }
+ if (doReport) {
+ Message msg = mHandler.obtainMessage(REPORT_MEM_USAGE_MSG, memInfos);
+ mHandler.sendMessage(msg);
+ }
+ scheduleAppGcsLocked();
+ }
+ }
+
final void appDiedLocked(ProcessRecord app, int pid,
IApplicationThread thread) {
- mProcDeaths[0]++;
-
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
stats.noteProcessDiedLocked(app.info.uid, pid);
@@ -3303,54 +3479,29 @@
// Clean up already done if the process has been re-started.
if (app.pid == pid && app.thread != null &&
app.thread.asBinder() == thread.asBinder()) {
- if (!app.killedBackground) {
+ boolean doLowMem = app.instrumentationClass == null;
+ boolean doOomAdj = doLowMem;
+ if (!app.killedByAm) {
Slog.i(TAG, "Process " + app.processName + " (pid " + pid
+ ") has died.");
+ mAllowLowerMemLevel = true;
+ } else {
+ // Note that we always want to do oom adj to update our state with the
+ // new number of procs.
+ mAllowLowerMemLevel = false;
+ doLowMem = false;
}
EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
if (DEBUG_CLEANUP) Slog.v(
TAG, "Dying app: " + app + ", pid: " + pid
+ ", thread: " + thread.asBinder());
- boolean doLowMem = app.instrumentationClass == null;
handleAppDiedLocked(app, false, true);
+ if (doOomAdj) {
+ updateOomAdjLocked();
+ }
if (doLowMem) {
- // If there are no longer any background processes running,
- // and the app that died was not running instrumentation,
- // then tell everyone we are now low on memory.
- boolean haveBg = false;
- for (int i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord rec = mLruProcesses.get(i);
- if (rec.thread != null && rec.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
- haveBg = true;
- break;
- }
- }
-
- if (!haveBg) {
- EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
- long now = SystemClock.uptimeMillis();
- for (int i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord rec = mLruProcesses.get(i);
- if (rec != app && rec.thread != null &&
- (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
- // The low memory report is overriding any current
- // state for a GC request. Make sure to do
- // heavy/important/visible/foreground processes first.
- if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
- rec.lastRequestedGc = 0;
- } else {
- rec.lastRequestedGc = rec.lastLowMemory;
- }
- rec.reportLowMemory = true;
- rec.lastLowMemory = now;
- mProcessesToGc.remove(rec);
- addProcessToGcListLocked(rec);
- }
- }
- mHandler.sendEmptyMessage(REPORT_MEM_USAGE);
- scheduleAppGcsLocked();
- }
+ doLowMemReportIfNeededLocked(app);
}
} else if (app.pid != pid) {
// A new process has already been started.
@@ -3681,10 +3832,7 @@
synchronized (this) {
if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
- Slog.w(TAG, "Killing " + app + ": background ANR");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "background ANR");
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "background ANR");
return;
}
@@ -3869,6 +4017,9 @@
for (int i=0; i<N; i++) {
removeProcessLocked(procs.get(i), false, true, "kill all background");
}
+ mAllowLowerMemLevel = true;
+ updateOomAdjLocked();
+ doLowMemReportIfNeededLocked(null);
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -4178,6 +4329,7 @@
for (int i=0; i<N; i++) {
removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);
}
+ updateOomAdjLocked();
return N > 0;
}
@@ -4365,10 +4517,9 @@
mPidsSelfLocked.remove(pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
- Slog.i(TAG, "Killing proc " + app.toShortString() + ": " + reason);
+ killUnneededProcessLocked(app, reason);
handleAppDiedLocked(app, true, allowRestart);
mLruProcesses.remove(app);
- Process.killProcessQuiet(pid);
if (app.persistent && !app.isolated) {
if (!callerWillRestart) {
@@ -4410,9 +4561,7 @@
checkAppInLaunchingProvidersLocked(app, true);
// Take care of any services that are waiting for the process.
mServices.processStartTimedOutLocked(app);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, pid,
- app.processName, app.setAdj, "start timeout");
- Process.killProcessQuiet(pid);
+ killUnneededProcessLocked(app, "start timeout");
if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
Slog.w(TAG, "Unattached app died before backup, skipping");
try {
@@ -5656,8 +5805,8 @@
pi.packageName, targetPkg, targetUid, uri);
final boolean persistChanged = perm.grantModes(modeFlags, persist, owner);
if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS);
- mHandler.obtainMessage(PERSIST_URI_GRANTS).sendToTarget();
+ mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
+ mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
}
}
@@ -5881,8 +6030,8 @@
}
if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS);
- mHandler.obtainMessage(PERSIST_URI_GRANTS).sendToTarget();
+ mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
+ mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
}
}
@@ -5966,8 +6115,8 @@
}
if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS);
- mHandler.obtainMessage(PERSIST_URI_GRANTS).sendToTarget();
+ mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
+ mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
}
}
@@ -6395,6 +6544,16 @@
}
}
+ private void killUnneededProcessLocked(ProcessRecord pr, String reason) {
+ if (!pr.killedByAm) {
+ Slog.i(TAG, "Killing " + pr.toShortString() + " (adj " + pr.setAdj + "): " + reason);
+ EventLog.writeEvent(EventLogTags.AM_KILL, pr.userId, pr.pid,
+ pr.processName, pr.setAdj, reason);
+ pr.killedByAm = true;
+ Process.killProcessQuiet(pr.pid);
+ }
+ }
+
private void cleanUpRemovedTaskLocked(TaskRecord tr, int flags) {
mRecentTasks.remove(tr);
mStackSupervisor.removeTask(tr);
@@ -6433,11 +6592,7 @@
for (int i=0; i<procs.size(); i++) {
ProcessRecord pr = procs.get(i);
if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
- Slog.i(TAG, "Killing " + pr.toShortString() + ": remove task");
- EventLog.writeEvent(EventLogTags.AM_KILL, pr.userId, pr.pid,
- pr.processName, pr.setAdj, "remove task");
- pr.killedBackground = true;
- Process.killProcessQuiet(pr.pid);
+ killUnneededProcessLocked(pr, "remove task");
} else {
pr.waitingToKill = "remove task";
}
@@ -7970,8 +8125,8 @@
return KEY_DISPATCHING_TIMEOUT;
}
-
- public long inputDispatchingTimedOut(int pid, final boolean aboveSystem) {
+ @Override
+ public long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
@@ -7986,7 +8141,7 @@
timeout = getInputDispatchingTimeoutLocked(proc);
}
- if (!inputDispatchingTimedOut(proc, null, null, aboveSystem)) {
+ if (!inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
return -1;
}
@@ -7999,13 +8154,20 @@
*/
public boolean inputDispatchingTimedOut(final ProcessRecord proc,
final ActivityRecord activity, final ActivityRecord parent,
- final boolean aboveSystem) {
+ final boolean aboveSystem, String reason) {
if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
+ android.Manifest.permission.FILTER_EVENTS);
}
+ final String annotation;
+ if (reason == null) {
+ annotation = "Input dispatching timed out";
+ } else {
+ annotation = "Input dispatching timed out (" + reason + ")";
+ }
+
if (proc != null) {
synchronized (this) {
if (proc.debugging) {
@@ -8021,7 +8183,7 @@
if (proc.instrumentationClass != null) {
Bundle info = new Bundle();
info.putString("shortMsg", "keyDispatchingTimedOut");
- info.putString("longMsg", "Timed out while dispatching key event");
+ info.putString("longMsg", annotation);
finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
return true;
}
@@ -8029,7 +8191,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- appNotResponding(proc, activity, parent, aboveSystem, "keyDispatchingTimedOut");
+ appNotResponding(proc, activity, parent, aboveSystem, annotation);
}
});
}
@@ -8042,81 +8204,41 @@
"getAssistContextExtras()");
PendingAssistExtras pae;
Bundle extras = new Bundle();
- List<ServiceRecord> foregroundServices;
synchronized (this) {
- Collection<ServiceRecord> allServices = mServices.mServiceMap.getAllServices(
- Binder.getCallingUid());
- foregroundServices = new ArrayList<ServiceRecord>();
- for (ServiceRecord record : allServices) {
- if ((record.serviceInfo.flags & ServiceInfo.FLAG_PROVIDE_ASSIST_DATA) > 0 &&
- record.isForeground) {
- if (record.app == null || record.app.thread == null) {
- Slog.w(TAG, "getAssistContextExtras error: no process for " + record);
- continue;
- }
- if (record.app.pid == Binder.getCallingPid()) {
- Slog.w(TAG, "getAssistContextExtras error: request process same as " +
- record);
- continue;
- }
- foregroundServices.add(record);
- }
- }
-
ActivityRecord activity = getFocusedStack().mResumedActivity;
- boolean validActivity = true;
if (activity == null) {
- Slog.w(TAG, "getAssistContextExtras error: no resumed activity");
- validActivity = false;
- } else if (activity.app == null || activity.app.thread == null) {
- Slog.w(TAG, "getAssistContextExtras error: no process for " + activity);
- validActivity = false;
- } else if (activity.app.pid == Binder.getCallingPid()) {
- Slog.w(TAG, "getAssistContextExtras error: request process same as " + activity);
- validActivity = false;
+ Slog.w(TAG, "getAssistContextExtras failed: no resumed activity");
+ return null;
}
-
- pae = new PendingAssistExtras(activity, foregroundServices);
+ extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
+ if (activity.app == null || activity.app.thread == null) {
+ Slog.w(TAG, "getAssistContextExtras failed: no process for " + activity);
+ return extras;
+ }
+ if (activity.app.pid == Binder.getCallingPid()) {
+ Slog.w(TAG, "getAssistContextExtras failed: request process same as " + activity);
+ return extras;
+ }
+ pae = new PendingAssistExtras(activity);
try {
- if (validActivity) {
- activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
- requestType, -1);
- }
- for (int i = 0; i < foregroundServices.size(); i++) {
- ServiceRecord record = foregroundServices.get(i);
- record.app.thread.requestAssistContextExtras(record, pae, requestType, i);
- }
+ activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
+ requestType);
mPendingAssistExtras.add(pae);
mHandler.postDelayed(pae, PENDING_ASSIST_EXTRAS_TIMEOUT);
} catch (RemoteException e) {
- Slog.w(TAG, "getAssistContextExtras failed: crash fetching extras.", e);
+ Slog.w(TAG, "getAssistContextExtras failed: crash calling " + activity);
+ return extras;
}
}
synchronized (pae) {
- while (pae.numPending > 0) {
+ while (!pae.haveResult) {
try {
pae.wait();
} catch (InterruptedException e) {
}
}
- if (pae.activityExtras != null) {
- extras.putBundle(Intent.EXTRA_ASSIST_CONTEXT, pae.activityExtras);
- extras.putString(Intent.EXTRA_ASSIST_PACKAGE, pae.activity.packageName);
- }
- if (pae.numRespondedServices > 0) {
- Bundle[] servicesExtras = new Bundle[pae.numRespondedServices];
- String[] servicesPackages = new String[pae.numRespondedServices];
- int extrasIndex = 0;
- for (int i = 0; i < foregroundServices.size(); i++) {
- if (pae.servicesExtras[i] != null) {
- servicesExtras[extrasIndex] = pae.servicesExtras[i];
- ServiceRecord record = foregroundServices.get(i);
- servicesPackages[extrasIndex] = record.packageName;
- extrasIndex++;
- }
- }
- extras.putParcelableArray(Intent.EXTRA_ASSIST_SERVICES_CONTEXTS, servicesExtras);
- extras.putStringArray(Intent.EXTRA_ASSIST_SERVICES_PACKAGES, servicesPackages);
+ if (pae.result != null) {
+ extras.putBundle(Intent.EXTRA_ASSIST_CONTEXT, pae.result);
}
}
synchronized (this) {
@@ -8126,19 +8248,12 @@
return extras;
}
- public void reportAssistContextExtras(IBinder token, Bundle extras, int index) {
+ public void reportAssistContextExtras(IBinder token, Bundle extras) {
PendingAssistExtras pae = (PendingAssistExtras)token;
synchronized (pae) {
- if (index == TOP_ACTIVITY_ASSIST_EXTRAS_INDEX) {
- pae.activityExtras = extras;
- } else {
- pae.servicesExtras[index] = extras;
- pae.numRespondedServices++;
- }
- pae.numPending--;
- if (pae.numPending == 0) {
- pae.notifyAll();
- }
+ pae.result = extras;
+ pae.haveResult = true;
+ pae.notifyAll();
}
}
@@ -8328,13 +8443,9 @@
continue;
}
int adj = proc.setAdj;
- if (adj >= worstType && !proc.killedBackground) {
- Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
- EventLog.writeEvent(EventLogTags.AM_KILL, proc.userId, proc.pid,
- proc.processName, adj, reason);
+ if (adj >= worstType && !proc.killedByAm) {
+ killUnneededProcessLocked(proc, reason);
killed = true;
- proc.killedBackground = true;
- Process.killProcessQuiet(pids[i]);
}
}
}
@@ -8376,13 +8487,9 @@
if (proc == null) continue;
final int adj = proc.setAdj;
- if (adj > belowAdj && !proc.killedBackground) {
- Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
- EventLog.writeEvent(EventLogTags.AM_KILL, proc.userId,
- proc.pid, proc.processName, adj, reason);
+ if (adj > belowAdj && !proc.killedByAm) {
+ killUnneededProcessLocked(proc, reason);
killed = true;
- proc.killedBackground = true;
- Process.killProcessQuiet(pid);
}
}
}
@@ -8460,6 +8567,61 @@
br.onReceive(mContext, intent);
}
+ private long getLowRamTimeSinceIdle(long now) {
+ return mLowRamTimeSinceLastIdle + (mLowRamStartTime > 0 ? (now-mLowRamStartTime) : 0);
+ }
+
+ @Override
+ public void performIdleMaintenance() {
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+ }
+
+ synchronized (this) {
+ final long now = SystemClock.uptimeMillis();
+ final long timeSinceLastIdle = now - mLastIdleTime;
+ final long lowRamSinceLastIdle = getLowRamTimeSinceIdle(now);
+ mLastIdleTime = now;
+ mLowRamTimeSinceLastIdle = 0;
+ if (mLowRamStartTime != 0) {
+ mLowRamStartTime = now;
+ }
+
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("Idle maintenance over ");
+ TimeUtils.formatDuration(timeSinceLastIdle, sb);
+ sb.append(" low RAM for ");
+ TimeUtils.formatDuration(lowRamSinceLastIdle, sb);
+ Slog.i(TAG, sb.toString());
+
+ // If at least 1/3 of our time since the last idle period has been spent
+ // with RAM low, then we want to kill processes.
+ boolean doKilling = lowRamSinceLastIdle > (timeSinceLastIdle/3);
+
+ for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
+ ProcessRecord proc = mLruProcesses.get(i);
+ if (proc.notCachedSinceIdle) {
+ if (proc.setProcState > ActivityManager.PROCESS_STATE_TOP
+ && proc.setProcState <= ActivityManager.PROCESS_STATE_SERVICE) {
+ if (doKilling && proc.initialIdlePss != 0
+ && proc.lastPss > ((proc.initialIdlePss*3)/2)) {
+ killUnneededProcessLocked(proc, "idle maint (pss " + proc.lastPss
+ + " from " + proc.initialIdlePss + ")");
+ }
+ }
+ } else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME) {
+ proc.notCachedSinceIdle = true;
+ proc.initialIdlePss = 0;
+ }
+ }
+
+ mHandler.removeMessages(REQUEST_ALL_PSS_MSG);
+ mHandler.sendEmptyMessageDelayed(REQUEST_ALL_PSS_MSG, 2*60*1000);
+ }
+ }
+
public final void startRunning(String pkg, String cls, String action,
String data) {
synchronized(this) {
@@ -8894,10 +9056,7 @@
}
if (app.pid > 0 && app.pid != MY_PID) {
handleAppCrashLocked(app);
- Slog.i(ActivityManagerService.TAG, "Killing " + app + ": user's request");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "user's request after error");
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "user request after error");
}
}
}
@@ -10371,6 +10530,15 @@
+ " mNumCachedHiddenProcs=" + mNumCachedHiddenProcs
+ " mNumServiceProcs=" + mNumServiceProcs
+ " mNewNumServiceProcs=" + mNewNumServiceProcs);
+ pw.println(" mAllowLowerMemLevel=" + mAllowLowerMemLevel
+ + " mLastMemoryLevel" + mLastMemoryLevel
+ + " mLastNumProcesses" + mLastNumProcesses);
+ long now = SystemClock.uptimeMillis();
+ pw.print(" mLastIdleTime=");
+ TimeUtils.formatDuration(now, mLastIdleTime, pw);
+ pw.print(" mLowRamSinceLastIdle=");
+ TimeUtils.formatDuration(getLowRamTimeSinceIdle(now), pw);
+ pw.println();
}
}
@@ -10850,14 +11018,6 @@
}
}
- private static String buildOomTag(String prefix, String space, int val, int base) {
- if (val == base) {
- if (space == null) return prefix;
- return prefix + " ";
- }
- return prefix + "+" + Integer.toString(val-base);
- }
-
private static final int dumpProcessList(PrintWriter pw,
ActivityManagerService service, List list,
String prefix, String normalLabel, String persistentLabel,
@@ -10929,34 +11089,7 @@
for (int i=list.size()-1; i>=0; i--) {
ProcessRecord r = list.get(i).first;
- String oomAdj;
- if (r.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
- oomAdj = buildOomTag("cch", " ", r.setAdj, ProcessList.CACHED_APP_MIN_ADJ);
- } else if (r.setAdj >= ProcessList.SERVICE_B_ADJ) {
- oomAdj = buildOomTag("svcb ", null, r.setAdj, ProcessList.SERVICE_B_ADJ);
- } else if (r.setAdj >= ProcessList.PREVIOUS_APP_ADJ) {
- oomAdj = buildOomTag("prev ", null, r.setAdj, ProcessList.PREVIOUS_APP_ADJ);
- } else if (r.setAdj >= ProcessList.HOME_APP_ADJ) {
- oomAdj = buildOomTag("home ", null, r.setAdj, ProcessList.HOME_APP_ADJ);
- } else if (r.setAdj >= ProcessList.SERVICE_ADJ) {
- oomAdj = buildOomTag("svc ", null, r.setAdj, ProcessList.SERVICE_ADJ);
- } else if (r.setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
- oomAdj = buildOomTag("hvy ", null, r.setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
- } else if (r.setAdj >= ProcessList.BACKUP_APP_ADJ) {
- oomAdj = buildOomTag("bkup ", null, r.setAdj, ProcessList.BACKUP_APP_ADJ);
- } else if (r.setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
- oomAdj = buildOomTag("prcp ", null, r.setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
- } else if (r.setAdj >= ProcessList.VISIBLE_APP_ADJ) {
- oomAdj = buildOomTag("vis ", null, r.setAdj, ProcessList.VISIBLE_APP_ADJ);
- } else if (r.setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
- oomAdj = buildOomTag("fore ", null, r.setAdj, ProcessList.FOREGROUND_APP_ADJ);
- } else if (r.setAdj >= ProcessList.PERSISTENT_PROC_ADJ) {
- oomAdj = buildOomTag("pers ", null, r.setAdj, ProcessList.PERSISTENT_PROC_ADJ);
- } else if (r.setAdj >= ProcessList.SYSTEM_ADJ) {
- oomAdj = buildOomTag("sys ", null, r.setAdj, ProcessList.SYSTEM_ADJ);
- } else {
- oomAdj = Integer.toString(r.setAdj);
- }
+ String oomAdj = ProcessList.makeOomAdjString(r.setAdj);
char schedGroup;
switch (r.setSchedGroup) {
case Process.THREAD_GROUP_BG_NONINTERACTIVE:
@@ -10977,54 +11110,7 @@
} else {
foreground = ' ';
}
- String procState;
- switch (r.curProcState) {
- case ActivityManager.PROCESS_STATE_PERSISTENT:
- procState = "P ";
- break;
- case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
- procState = "PU";
- break;
- case ActivityManager.PROCESS_STATE_TOP:
- procState = "T ";
- break;
- case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
- procState = "IF";
- break;
- case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
- procState = "IB";
- break;
- case ActivityManager.PROCESS_STATE_BACKUP:
- procState = "BU";
- break;
- case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
- procState = "HW";
- break;
- case ActivityManager.PROCESS_STATE_SERVICE:
- procState = "S ";
- break;
- case ActivityManager.PROCESS_STATE_RECEIVER:
- procState = "R ";
- break;
- case ActivityManager.PROCESS_STATE_HOME:
- procState = "HO";
- break;
- case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
- procState = "LA";
- break;
- case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
- procState = "CA";
- break;
- case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
- procState = "Ca";
- break;
- case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
- procState = "CE";
- break;
- default:
- procState = "??";
- break;
- }
+ String procState = ProcessList.makeProcStateString(r.curProcState);
pw.print(prefix);
pw.print(r.persistent ? persistentLabel : normalLabel);
pw.print(" #");
@@ -11312,6 +11398,7 @@
}
static final int[] DUMP_MEM_OOM_ADJ = new int[] {
+ ProcessList.NATIVE_ADJ,
ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ, ProcessList.FOREGROUND_APP_ADJ,
ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ,
ProcessList.BACKUP_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
@@ -11319,6 +11406,7 @@
ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.CACHED_APP_MAX_ADJ
};
static final String[] DUMP_MEM_OOM_LABEL = new String[] {
+ "Native",
"System", "Persistent", "Foreground",
"Visible", "Perceptible",
"Heavy Weight", "Backup",
@@ -11326,6 +11414,7 @@
"Previous", "B Services", "Cached"
};
static final String[] DUMP_MEM_OOM_COMPACT_LABEL = new String[] {
+ "native",
"sys", "pers", "fore",
"vis", "percept",
"heavy", "backup",
@@ -11334,8 +11423,7 @@
};
final void dumpApplicationMemoryUsage(FileDescriptor fd,
- PrintWriter pw, String prefix, String[] args, boolean brief,
- PrintWriter categoryPw, StringBuilder outTag, StringBuilder outStack) {
+ PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
boolean dumpDetails = false;
boolean dumpDalvik = false;
boolean oomOnly = false;
@@ -11396,6 +11484,7 @@
System.arraycopy(args, opti, innerArgs, 0, args.length-opti);
ArrayList<MemItem> procMems = new ArrayList<MemItem>();
+ final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>();
long nativePss=0, dalvikPss=0, otherPss=0;
long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
@@ -11463,6 +11552,7 @@
(hasActivities ? " / activities)" : ")"),
r.processName, myTotalPss, pid, hasActivities);
procMems.add(pssItem);
+ procMemsMap.put(pid, pssItem);
nativePss += mi.nativePss;
dalvikPss += mi.dalvikPss;
@@ -11493,6 +11583,48 @@
}
if (!isCheckinRequest && procs.size() > 1) {
+ // If we are showing aggregations, also look for native processes to
+ // include so that our aggregations are more accurate.
+ updateCpuStatsNow();
+ synchronized (mProcessCpuThread) {
+ final int N = mProcessCpuTracker.countStats();
+ for (int i=0; i<N; i++) {
+ ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+ if (st.vsize > 0 && procMemsMap.indexOfKey(st.pid) < 0) {
+ if (mi == null) {
+ mi = new Debug.MemoryInfo();
+ }
+ if (!brief && !oomOnly) {
+ Debug.getMemoryInfo(st.pid, mi);
+ } else {
+ mi.nativePss = (int)Debug.getPss(st.pid, tmpLong);
+ mi.nativePrivateDirty = (int)tmpLong[0];
+ }
+
+ final long myTotalPss = mi.getTotalPss();
+ totalPss += myTotalPss;
+
+ MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
+ st.name, myTotalPss, st.pid, false);
+ procMems.add(pssItem);
+
+ nativePss += mi.nativePss;
+ dalvikPss += mi.dalvikPss;
+ otherPss += mi.otherPss;
+ for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+ long mem = mi.getOtherPss(j);
+ miscPss[j] += mem;
+ otherPss -= mem;
+ }
+ oomPss[0] += myTotalPss;
+ if (oomProcs[0] == null) {
+ oomProcs[0] = new ArrayList<MemItem>();
+ }
+ oomProcs[0].add(pssItem);
+ }
+ }
+ }
+
ArrayList<MemItem> catMems = new ArrayList<MemItem>();
catMems.add(new MemItem("Native", "Native", nativePss, -1));
@@ -11515,68 +11647,6 @@
}
}
- if (outTag != null || outStack != null) {
- if (outTag != null) {
- appendMemBucket(outTag, totalPss, "total", false);
- }
- if (outStack != null) {
- appendMemBucket(outStack, totalPss, "total", true);
- }
- boolean firstLine = true;
- for (int i=0; i<oomMems.size(); i++) {
- MemItem miCat = oomMems.get(i);
- if (miCat.subitems == null || miCat.subitems.size() < 1) {
- continue;
- }
- if (miCat.id < ProcessList.SERVICE_ADJ
- || miCat.id == ProcessList.HOME_APP_ADJ
- || miCat.id == ProcessList.PREVIOUS_APP_ADJ) {
- if (outTag != null && miCat.id <= ProcessList.FOREGROUND_APP_ADJ) {
- outTag.append(" / ");
- }
- if (outStack != null) {
- if (miCat.id >= ProcessList.FOREGROUND_APP_ADJ) {
- if (firstLine) {
- outStack.append(":");
- firstLine = false;
- }
- outStack.append("\n\t at ");
- } else {
- outStack.append("$");
- }
- }
- for (int j=0; j<miCat.subitems.size(); j++) {
- MemItem memi = miCat.subitems.get(j);
- if (j > 0) {
- if (outTag != null) {
- outTag.append(" ");
- }
- if (outStack != null) {
- outStack.append("$");
- }
- }
- if (outTag != null && miCat.id <= ProcessList.FOREGROUND_APP_ADJ) {
- appendMemBucket(outTag, memi.pss, memi.shortLabel, false);
- }
- if (outStack != null) {
- appendMemBucket(outStack, memi.pss, memi.shortLabel, true);
- }
- }
- if (outStack != null && miCat.id >= ProcessList.FOREGROUND_APP_ADJ) {
- outStack.append("(");
- for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
- if (DUMP_MEM_OOM_ADJ[k] == miCat.id) {
- outStack.append(DUMP_MEM_OOM_LABEL[k]);
- outStack.append(":");
- outStack.append(DUMP_MEM_OOM_ADJ[k]);
- }
- }
- outStack.append(")");
- }
- }
- }
- }
-
if (!brief && !oomOnly && !isCompact) {
pw.println();
pw.println("Total PSS by process:");
@@ -11729,13 +11799,9 @@
if (!capp.persistent && capp.thread != null
&& capp.pid != 0
&& capp.pid != MY_PID) {
- Slog.i(TAG, "Kill " + capp.processName
- + " (pid " + capp.pid + "): provider " + cpr.info.name
- + " in dying process " + (proc != null ? proc.processName : "??"));
- EventLog.writeEvent(EventLogTags.AM_KILL, capp.userId, capp.pid,
- capp.processName, capp.setAdj, "dying provider "
- + cpr.name.toShortString());
- Process.killProcessQuiet(capp.pid);
+ killUnneededProcessLocked(capp, "depends on provider "
+ + cpr.name.flattenToShortString()
+ + " in dying proc " + (proc != null ? proc.processName : "??"));
}
} else if (capp.thread != null && conn.provider.provider != null) {
try {
@@ -12816,12 +12882,12 @@
}
if (intent.ACTION_CLEAR_DNS_CACHE.equals(intent.getAction())) {
- mHandler.sendEmptyMessage(CLEAR_DNS_CACHE);
+ mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
}
if (Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) {
ProxyProperties proxy = intent.getParcelableExtra("proxy");
- mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY, proxy));
+ mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
}
// Add to the sticky list if requested.
@@ -14552,26 +14618,18 @@
stats.reportExcessiveWakeLocked(app.info.uid, app.processName,
realtimeSince, wtimeUsed);
}
- Slog.w(TAG, "Excessive wake lock in " + app.processName
- + " (pid " + app.pid + "): held " + wtimeUsed
+ killUnneededProcessLocked(app, "excessive wake held " + wtimeUsed
+ " during " + realtimeSince);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "excessive wake lock");
app.baseProcessTracker.reportExcessiveWake(app.pkgList);
- Process.killProcessQuiet(app.pid);
} else if (doCpuKills && uptimeSince > 0
&& ((cputimeUsed*100)/uptimeSince) >= 50) {
synchronized (stats) {
stats.reportExcessiveCpuLocked(app.info.uid, app.processName,
uptimeSince, cputimeUsed);
}
- Slog.w(TAG, "Excessive CPU in " + app.processName
- + " (pid " + app.pid + "): used " + cputimeUsed
+ killUnneededProcessLocked(app, "excessive cpu " + cputimeUsed
+ " during " + uptimeSince);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "excessive cpu");
app.baseProcessTracker.reportExcessiveCpu(app.pkgList);
- Process.killProcessQuiet(app.pid);
} else {
app.lastWakeTime = wtime;
app.lastCpuTime = app.curCpuTime;
@@ -14618,11 +14676,7 @@
+ " to " + app.curSchedGroup);
if (app.waitingToKill != null &&
app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
- Slog.i(TAG, "Killing " + app.toShortString() + ": " + app.waitingToKill);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, app.waitingToKill);
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, app.waitingToKill);
success = false;
} else {
if (true) {
@@ -14682,6 +14736,9 @@
"Proc state change of " + app.processName
+ " to " + app.curProcState);
app.setProcState = app.curProcState;
+ if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
+ app.notCachedSinceIdle = false;
+ }
if (!doingAll) {
setProcessTrackerState(app, mProcessStats.getMemFactorLocked(), now);
} else {
@@ -14692,7 +14749,7 @@
}
private final void setProcessTrackerState(ProcessRecord proc, int memFactor, long now) {
- if (proc.thread != null) {
+ if (proc.thread != null && proc.baseProcessTracker != null) {
proc.baseProcessTracker.setState(proc.repProcState, memFactor, now, proc.pkgList);
}
}
@@ -14808,7 +14865,7 @@
int nextEmptyAdj = curEmptyAdj+2;
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
- if (!app.killedBackground && app.thread != null) {
+ if (!app.killedByAm && app.thread != null) {
app.procStateChanged = false;
final boolean wasKeeping = app.keeping;
computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
@@ -14883,34 +14940,19 @@
mNumCachedHiddenProcs++;
numCached++;
if (numCached > cachedProcessLimit) {
- Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): cached #" + numCached);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "too many background");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "cached #" + numCached);
}
break;
case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
if (numEmpty > ProcessList.TRIM_EMPTY_APPS
&& app.lastActivityTime < oldTime) {
- Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): empty for "
- + ((oldTime+ProcessList.MAX_EMPTY_TIME-app.lastActivityTime)
- / 1000) + "s");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "old background process");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "empty for "
+ + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
+ / 1000) + "s");
} else {
numEmpty++;
if (numEmpty > emptyProcessLimit) {
- Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): empty #" + numEmpty);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "too many background");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "empty #" + numEmpty);
}
}
break;
@@ -14926,16 +14968,11 @@
// definition not re-use the same process again, and it is
// good to avoid having whatever code was running in them
// left sitting around after no longer needed.
- Slog.i(TAG, "Isolated process " + app.processName
- + " (pid " + app.pid + ") no longer needed");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "isolated not needed");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "isolated not needed");
}
if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
- && !app.killedBackground) {
+ && !app.killedByAm) {
numTrimming++;
}
}
@@ -14949,31 +14986,60 @@
// are managing to keep around is less than half the maximum we desire;
// if we are keeping a good number around, we'll let them use whatever
// memory they want.
- boolean allChanged;
+ final int numCachedAndEmpty = numCached + numEmpty;
+ int memFactor;
if (numCached <= ProcessList.TRIM_CACHED_APPS
&& numEmpty <= ProcessList.TRIM_EMPTY_APPS) {
- final int numCachedAndEmpty = numCached + numEmpty;
+ if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
+ memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
+ } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
+ memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;
+ } else {
+ memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;
+ }
+ } else {
+ memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+ }
+ // We always allow the memory level to go up (better). We only allow it to go
+ // down if we are in a state where that is allowed, *and* the total number of processes
+ // has gone down since last time.
+ if (DEBUG_OOM_ADJ) Slog.d(TAG, "oom: memFactor=" + memFactor + " last=" + mLastMemoryLevel
+ + " allowLow=" + mAllowLowerMemLevel + " numProcs=" + mLruProcesses.size()
+ + " last=" + mLastNumProcesses);
+ if (memFactor > mLastMemoryLevel) {
+ if (!mAllowLowerMemLevel || mLruProcesses.size() >= mLastNumProcesses) {
+ memFactor = mLastMemoryLevel;
+ if (DEBUG_OOM_ADJ) Slog.d(TAG, "Keeping last mem factor!");
+ }
+ }
+ mLastMemoryLevel = memFactor;
+ mLastNumProcesses = mLruProcesses.size();
+ boolean allChanged = mProcessStats.setMemFactorLocked(
+ ProcessStats.ADJ_MEM_FACTOR_NORMAL, !mSleeping, now);
+ final int trackerMemFactor = mProcessStats.getMemFactorLocked();
+ if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
+ if (mLowRamStartTime == 0) {
+ mLowRamStartTime = now;
+ }
+ int step = 0;
+ int fgTrimLevel;
+ switch (memFactor) {
+ case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
+ fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
+ break;
+ case ProcessStats.ADJ_MEM_FACTOR_LOW:
+ fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
+ break;
+ default:
+ fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
+ break;
+ }
int factor = numTrimming/3;
int minFactor = 2;
if (mHomeProcess != null) minFactor++;
if (mPreviousProcess != null) minFactor++;
if (factor < minFactor) factor = minFactor;
- int step = 0;
- int fgTrimLevel;
- int memFactor;
- if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
- fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
- memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
- } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
- fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
- memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;
- } else {
- fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
- memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;
- }
int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
- allChanged = mProcessStats.setMemFactorLocked(memFactor, !mSleeping, now);
- final int trackerMemFactor = mProcessStats.getMemFactorLocked();
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
@@ -14981,7 +15047,7 @@
app.procStateChanged = false;
}
if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
- && !app.killedBackground) {
+ && !app.killedByAm) {
if (app.trimMemoryLevel < curLevel && app.thread != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
@@ -15061,9 +15127,10 @@
}
}
} else {
- allChanged = mProcessStats.setMemFactorLocked(
- ProcessStats.ADJ_MEM_FACTOR_NORMAL, !mSleeping, now);
- final int trackerMemFactor = mProcessStats.getMemFactorLocked();
+ if (mLowRamStartTime != 0) {
+ mLowRamTimeSinceLastIdle += now - mLowRamStartTime;
+ mLowRamStartTime = 0;
+ }
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
@@ -15132,6 +15199,7 @@
if (app.pid > 0 && app.pid != MY_PID) {
EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
app.processName, app.setAdj, "empty");
+ app.killedByAm = true;
Process.killProcessQuiet(app.pid);
} else {
try {
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index bf3713b..6e50808 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -305,9 +305,9 @@
}
}
- @Override public boolean keyDispatchingTimedOut() {
+ @Override public boolean keyDispatchingTimedOut(String reason) {
ActivityRecord activity = weakActivity.get();
- return activity != null && activity.keyDispatchingTimedOut();
+ return activity != null && activity.keyDispatchingTimedOut(reason);
}
@Override public long getKeyDispatchingTimeout() {
@@ -960,14 +960,14 @@
return r;
}
- public boolean keyDispatchingTimedOut() {
+ public boolean keyDispatchingTimedOut(String reason) {
ActivityRecord r;
ProcessRecord anrApp;
synchronized(service) {
r = getWaitingHistoryRecordLocked();
anrApp = r != null ? r.app : null;
}
- return service.inputDispatchingTimedOut(anrApp, r, this, false);
+ return service.inputDispatchingTimedOut(anrApp, r, this, false, reason);
}
/** Returns the key dispatching timeout for this application token. */
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 2b76e71..1f64101 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -620,7 +620,13 @@
}
void clearLaunchTime(ActivityRecord r) {
- r.displayStartTime = r.fullyDrawnStartTime = 0;
+ // Make sure that there is no activity waiting for this to launch.
+ if (mStackSupervisor.mWaitingActivityLaunched.isEmpty()) {
+ r.displayStartTime = r.fullyDrawnStartTime = 0;
+ } else {
+ mStackSupervisor.removeTimeoutsForActivityLocked(r);
+ mStackSupervisor.scheduleIdleTimeoutLocked(r);
+ }
}
void awakeFromSleepingLocked() {
@@ -1837,16 +1843,17 @@
// bottom of the activity stack. This also keeps it
// correctly ordered with any activities we previously
// moved.
- TaskRecord bottomTask = mTaskHistory.get(0);
- ActivityRecord p = bottomTask.mActivities.get(0);
- if (target.taskAffinity != null
- && target.taskAffinity.equals(p.task.affinity)) {
+ final ActivityRecord bottom =
+ !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ?
+ mTaskHistory.get(0).mActivities.get(0) : null;
+ if (bottom != null && target.taskAffinity != null
+ && target.taskAffinity.equals(bottom.task.affinity)) {
// If the activity currently at the bottom has the
// same task affinity as the one we are moving,
// then merge it into the same task.
- target.setTask(p.task, p.thumbHolder, false);
+ target.setTask(bottom.task, bottom.thumbHolder, false);
if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
- + " out to bottom task " + p.task);
+ + " out to bottom task " + bottom.task);
} else {
target.setTask(createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
null, false), null, false);
@@ -1862,7 +1869,7 @@
boolean noOptions = canMoveOptions;
final int start = replyChainEnd < 0 ? i : replyChainEnd;
for (int srcPos = start; srcPos >= i; --srcPos) {
- p = activities.get(srcPos);
+ final ActivityRecord p = activities.get(srcPos);
if (p.finishing) {
continue;
}
@@ -2904,6 +2911,19 @@
mWindowManager.prepareAppTransition(transit, false);
}
+ void moveHomeTaskToTop() {
+ final int top = mTaskHistory.size() - 1;
+ for (int taskNdx = top; taskNdx >= 0; --taskNdx) {
+ final TaskRecord task = mTaskHistory.get(taskNdx);
+ if (task.isHomeTask()) {
+ mTaskHistory.remove(taskNdx);
+ mTaskHistory.add(top, task);
+ mWindowManager.moveTaskToTop(task.taskId);
+ return;
+ }
+ }
+ }
+
final boolean findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) {
final TaskRecord task = taskForIdLocked(taskId);
if (task != null) {
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 3e0b5eb..7756ff9 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -284,6 +284,7 @@
if (prev != null) {
prev.mLaunchHomeTaskNext = false;
}
+ mHomeStack.moveHomeTaskToTop();
ActivityRecord r = mHomeStack.topRunningActivityLocked(null);
if (r != null) {
mService.setFocusedActivityLocked(r);
@@ -1416,7 +1417,8 @@
final ActivityStack lastStack = getLastStack();
ActivityRecord curTop = lastStack == null?
null : lastStack.topRunningNonDelayedActivityLocked(notTop);
- if (curTop != null && curTop.task != intentActivity.task) {
+ if (curTop != null && (curTop.task != intentActivity.task ||
+ curTop.task != lastStack.topTask())) {
r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
if (sourceRecord == null || (sourceStack.topActivity() != null &&
sourceStack.topActivity().task == sourceRecord.task)) {
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
index fb81b3a..54593aa 100644
--- a/services/java/com/android/server/am/ProcessList.java
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -19,6 +19,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
+import android.app.ActivityManager;
import com.android.internal.util.MemInfoReader;
import com.android.server.wm.WindowManagerService;
@@ -98,6 +99,10 @@
// The system process runs at the default adjustment.
static final int SYSTEM_ADJ = -16;
+ // Special code for native processes that are not being managed by the system (so
+ // don't have an oom adj assigned by the system).
+ static final int NATIVE_ADJ = -17;
+
// Memory pages are 4K.
static final int PAGE_SIZE = 4*1024;
@@ -278,6 +283,46 @@
return (totalProcessLimit*2)/3;
}
+ private static String buildOomTag(String prefix, String space, int val, int base) {
+ if (val == base) {
+ if (space == null) return prefix;
+ return prefix + " ";
+ }
+ return prefix + "+" + Integer.toString(val-base);
+ }
+
+ public static String makeOomAdjString(int setAdj) {
+ if (setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
+ return buildOomTag("cch", " ", setAdj, ProcessList.CACHED_APP_MIN_ADJ);
+ } else if (setAdj >= ProcessList.SERVICE_B_ADJ) {
+ return buildOomTag("svcb ", null, setAdj, ProcessList.SERVICE_B_ADJ);
+ } else if (setAdj >= ProcessList.PREVIOUS_APP_ADJ) {
+ return buildOomTag("prev ", null, setAdj, ProcessList.PREVIOUS_APP_ADJ);
+ } else if (setAdj >= ProcessList.HOME_APP_ADJ) {
+ return buildOomTag("home ", null, setAdj, ProcessList.HOME_APP_ADJ);
+ } else if (setAdj >= ProcessList.SERVICE_ADJ) {
+ return buildOomTag("svc ", null, setAdj, ProcessList.SERVICE_ADJ);
+ } else if (setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+ return buildOomTag("hvy ", null, setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
+ } else if (setAdj >= ProcessList.BACKUP_APP_ADJ) {
+ return buildOomTag("bkup ", null, setAdj, ProcessList.BACKUP_APP_ADJ);
+ } else if (setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
+ return buildOomTag("prcp ", null, setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
+ } else if (setAdj >= ProcessList.VISIBLE_APP_ADJ) {
+ return buildOomTag("vis ", null, setAdj, ProcessList.VISIBLE_APP_ADJ);
+ } else if (setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+ return buildOomTag("fore ", null, setAdj, ProcessList.FOREGROUND_APP_ADJ);
+ } else if (setAdj >= ProcessList.PERSISTENT_PROC_ADJ) {
+ return buildOomTag("pers ", null, setAdj, ProcessList.PERSISTENT_PROC_ADJ);
+ } else if (setAdj >= ProcessList.SYSTEM_ADJ) {
+ return buildOomTag("sys ", null, setAdj, ProcessList.SYSTEM_ADJ);
+ } else if (setAdj >= ProcessList.NATIVE_ADJ) {
+ return buildOomTag("ntv ", null, setAdj, ProcessList.NATIVE_ADJ);
+ } else {
+ return Integer.toString(setAdj);
+ }
+ }
+
// The minimum amount of time after a state change it is safe ro collect PSS.
public static final int PSS_MIN_TIME_FROM_STATE_CHANGE = 15*1000;
@@ -366,6 +411,70 @@
return sProcStateToProcMem[procState1] != sProcStateToProcMem[procState2];
}
+ public static String makeProcStateString(int curProcState) {
+ String procState;
+ switch (curProcState) {
+ case -1:
+ procState = "N ";
+ break;
+ case ActivityManager.PROCESS_STATE_PERSISTENT:
+ procState = "P ";
+ break;
+ case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
+ procState = "PU";
+ break;
+ case ActivityManager.PROCESS_STATE_TOP:
+ procState = "T ";
+ break;
+ case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
+ procState = "IF";
+ break;
+ case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
+ procState = "IB";
+ break;
+ case ActivityManager.PROCESS_STATE_BACKUP:
+ procState = "BU";
+ break;
+ case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
+ procState = "HW";
+ break;
+ case ActivityManager.PROCESS_STATE_SERVICE:
+ procState = "S ";
+ break;
+ case ActivityManager.PROCESS_STATE_RECEIVER:
+ procState = "R ";
+ break;
+ case ActivityManager.PROCESS_STATE_HOME:
+ procState = "HO";
+ break;
+ case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
+ procState = "LA";
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+ procState = "CA";
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+ procState = "Ca";
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
+ procState = "CE";
+ break;
+ default:
+ procState = "??";
+ break;
+ }
+ return procState;
+ }
+
+ public static void appendRamKb(StringBuilder sb, long ramKb) {
+ for (int j=0, fact=10; j<6; j++, fact*=10) {
+ if (ramKb < fact) {
+ sb.append(' ');
+ }
+ }
+ sb.append(ramKb);
+ }
+
public static long computeNextPssTime(int procState, boolean first, boolean sleeping,
long now) {
final long[] table = sleeping
diff --git a/services/java/com/android/server/am/ProcessMemInfo.java b/services/java/com/android/server/am/ProcessMemInfo.java
new file mode 100644
index 0000000..c94694e
--- /dev/null
+++ b/services/java/com/android/server/am/ProcessMemInfo.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 com.android.server.am;
+
+public class ProcessMemInfo {
+ final String name;
+ final int pid;
+ final int oomAdj;
+ final int procState;
+ final String adjType;
+ final String adjReason;
+ long pss;
+
+ public ProcessMemInfo(String _name, int _pid, int _oomAdj, int _procState,
+ String _adjType, String _adjReason) {
+ name = _name;
+ pid = _pid;
+ oomAdj = _oomAdj;
+ procState = _procState;
+ adjType = _adjType;
+ adjReason = _adjReason;
+ }
+}
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 283d122..d230779 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -66,6 +66,8 @@
long lastPssTime; // Last time we retrieved PSS data
long nextPssTime; // Next time we want to request PSS data
long lastStateTime; // Last time setProcState changed
+ long initialIdlePss; // Initial memory pss of process for idle maintenance.
+ long lastPss; // Last computed memory pss.
int maxAdj; // Maximum OOM adjustment for this process
int curRawAdj; // Current OOM unlimited adjustment for this process
int setRawAdj; // Last set OOM unlimited adjustment for this process
@@ -82,6 +84,7 @@
boolean serviceb; // Process currently is on the service B list
boolean keeping; // Actively running code so don't kill due to that?
boolean setIsForeground; // Running foreground UI when last set?
+ boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle?
boolean hasActivities; // Are there any activities running in this process?
boolean hasClientActivities; // Are there any client services with activities?
boolean hasStartedServices; // Are there any started services running in this process?
@@ -92,7 +95,7 @@
boolean pendingUiClean; // Want to clean up resources from showing UI?
boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so want to be lower
boolean bad; // True if disabled in the bad process list
- boolean killedBackground; // True when proc has been killed due to too many bg
+ boolean killedByAm; // True when proc has been killed by activity manager, not for RAM
boolean procStateChanged; // Keep track of whether we changed 'setAdj'.
String waitingToKill; // Process is waiting to be killed when in the bg; reason
IBinder forcingToForeground;// Token that is forcing this process to be foreground
@@ -216,6 +219,11 @@
pw.print(" keeping="); pw.print(keeping);
pw.print(" cached="); pw.print(cached);
pw.print(" empty="); pw.println(empty);
+ if (notCachedSinceIdle) {
+ pw.print(prefix); pw.print("notCachedSinceIdle="); pw.print(notCachedSinceIdle);
+ pw.print(" initialIdlePss="); pw.print(initialIdlePss);
+ pw.print(" lastPss="); pw.println(lastPss);
+ }
pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
pw.print(" curRaw="); pw.print(curRawAdj);
pw.print(" setRaw="); pw.print(setRawAdj);
@@ -280,8 +288,8 @@
pw.print(" lastLowMemory=");
TimeUtils.formatDuration(lastLowMemory, now, pw);
pw.print(" reportLowMemory="); pw.println(reportLowMemory);
- if (killedBackground || waitingToKill != null) {
- pw.print(prefix); pw.print("killedBackground="); pw.print(killedBackground);
+ if (killedByAm || waitingToKill != null) {
+ pw.print(prefix); pw.print("killedByAm="); pw.print(killedByAm);
pw.print(" waitingToKill="); pw.println(waitingToKill);
}
if (debugging || crashing || crashDialog != null || notResponding
@@ -527,13 +535,40 @@
sb.append('}');
return stringName = sb.toString();
}
-
+
+ public String makeAdjReason() {
+ if (adjSource != null || adjTarget != null) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append(' ');
+ if (adjTarget instanceof ComponentName) {
+ sb.append(((ComponentName)adjTarget).flattenToShortString());
+ } else if (adjTarget != null) {
+ sb.append(adjTarget.toString());
+ } else {
+ sb.append("{null}");
+ }
+ sb.append("<=");
+ if (adjSource instanceof ProcessRecord) {
+ sb.append("Proc{");
+ sb.append(((ProcessRecord)adjSource).toShortString());
+ sb.append("}");
+ } else if (adjSource != null) {
+ sb.append(adjSource.toString());
+ } else {
+ sb.append("{null}");
+ }
+ return sb.toString();
+ }
+ return null;
+ }
+
/*
* Return true if package has been added false if not
*/
public boolean addPackage(String pkg, ProcessStatsService tracker) {
if (!pkgList.containsKey(pkg)) {
- pkgList.put(pkg, tracker.getProcessStateLocked(pkg, info.uid, processName));
+ pkgList.put(pkg, baseProcessTracker != null
+ ? tracker.getProcessStateLocked(pkg, info.uid, processName) : null);
return true;
}
return false;
@@ -558,25 +593,30 @@
* Delete all packages from list except the package indicated in info
*/
public void resetPackageList(ProcessStatsService tracker) {
- long now = SystemClock.uptimeMillis();
- baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), now, pkgList);
final int N = pkgList.size();
- if (N != 1) {
- for (int i=0; i<N; i++) {
- ProcessStats.ProcessState ps = pkgList.valueAt(i);
- if (ps != null && ps != baseProcessTracker) {
- ps.makeInactive();
- }
+ if (baseProcessTracker != null) {
+ long now = SystemClock.uptimeMillis();
+ baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
+ tracker.getMemFactorLocked(), now, pkgList);
+ if (N != 1) {
+ for (int i=0; i<N; i++) {
+ ProcessStats.ProcessState ps = pkgList.valueAt(i);
+ if (ps != null && ps != baseProcessTracker) {
+ ps.makeInactive();
+ }
+ }
+ pkgList.clear();
+ ProcessStats.ProcessState ps = tracker.getProcessStateLocked(
+ info.packageName, info.uid, processName);
+ pkgList.put(info.packageName, ps);
+ if (thread != null && ps != baseProcessTracker) {
+ ps.makeActive();
+ }
}
+ } else if (N != 1) {
pkgList.clear();
- ProcessStats.ProcessState ps = tracker.getProcessStateLocked(
- info.packageName, info.uid, processName);
- pkgList.put(info.packageName, ps);
- if (thread != null && ps != baseProcessTracker) {
- ps.makeActive();
- }
+ pkgList.put(info.packageName, null);
}
}
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
index c180f6e..582e11e 100644
--- a/services/java/com/android/server/am/ProcessStatsService.java
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -445,7 +445,7 @@
static private void dumpHelp(PrintWriter pw) {
pw.println("Process stats (procstats) dump options:");
pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
- pw.println(" [--details] [--current] [--commit] [--write] [-h] [<package.name>]");
+ pw.println(" [--details] [--current] [--commit] [--reset] [--write] [-h] [<package.name>]");
pw.println(" --checkin: perform a checkin: print and delete old committed states.");
pw.println(" --c: print only state in checkin format.");
pw.println(" --csv: output data suitable for putting in a spreadsheet.");
@@ -456,6 +456,7 @@
pw.println(" --details: dump all execution details, not just summary.");
pw.println(" --current: only dump current state.");
pw.println(" --commit: commit current stats to disk and reset to start new stats.");
+ pw.println(" --reset: reset current stats, without committing.");
pw.println(" --write: write current in-memory stats to disk.");
pw.println(" --read: replace current stats with last-written stats.");
pw.println(" -a: print everything.");
@@ -551,17 +552,29 @@
} else if ("--current".equals(arg)) {
currentOnly = true;
} else if ("--commit".equals(arg)) {
- mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
- writeStateLocked(true, true);
- pw.println("Process stats committed.");
+ synchronized (mAm) {
+ mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
+ writeStateLocked(true, true);
+ pw.println("Process stats committed.");
+ }
+ return;
+ } else if ("--reset".equals(arg)) {
+ synchronized (mAm) {
+ mProcessStats.resetSafely();
+ pw.println("Process stats reset.");
+ }
return;
} else if ("--write".equals(arg)) {
- writeStateSyncLocked();
- pw.println("Process stats written.");
+ synchronized (mAm) {
+ writeStateSyncLocked();
+ pw.println("Process stats written.");
+ }
return;
} else if ("--read".equals(arg)) {
- readLocked(mProcessStats, mFile);
- pw.println("Process stats read.");
+ synchronized (mAm) {
+ readLocked(mProcessStats, mFile);
+ pw.println("Process stats read.");
+ }
return;
} else if ("-h".equals(arg)) {
dumpHelp(pw);
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 8293bb8..448117e 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -85,11 +85,14 @@
ProcessRecord app; // where this service is running or null.
ProcessRecord isolatedProc; // keep track of isolated process, if requested
ProcessStats.ServiceState tracker; // tracking service execution, may be null
+ boolean delayed; // are we waiting to start this service in the background?
boolean isForeground; // is service currently in foreground mode?
int foregroundId; // Notification ID of last foreground req.
Notification foregroundNoti; // Notification record of foreground state.
long lastActivity; // last time there was some activity on the service.
+ long startingBgTimeout; // time at which we scheduled this for a delayed start.
boolean startRequested; // someone explicitly called start?
+ boolean delayedStop; // service has been stopped but is in a delayed start?
boolean stopIfKilled; // last onStart() said to stop if service killed?
boolean callStart; // last onStart() has asked to alway be called on restart.
int executeNesting; // number of outstanding operations keeping foreground.
@@ -220,6 +223,9 @@
if (isolatedProc != null) {
pw.print(prefix); pw.print("isolatedProc="); pw.println(isolatedProc);
}
+ if (delayed) {
+ pw.print(prefix); pw.print("delayed="); pw.println(delayed);
+ }
if (isForeground || foregroundId != 0) {
pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
pw.print(" foregroundId="); pw.print(foregroundId);
@@ -227,14 +233,17 @@
}
pw.print(prefix); pw.print("createTime=");
TimeUtils.formatDuration(createTime, nowReal, pw);
- pw.print(" lastActivity=");
- TimeUtils.formatDuration(lastActivity, now, pw);
+ pw.print(" startingBgTimeout=");
+ TimeUtils.formatDuration(startingBgTimeout, now, pw);
pw.println();
- pw.print(prefix); pw.print("restartTime=");
+ pw.print(prefix); pw.print("lastActivity=");
+ TimeUtils.formatDuration(lastActivity, now, pw);
+ pw.print(" restartTime=");
TimeUtils.formatDuration(restartTime, now, pw);
pw.print(" createdFromFg="); pw.println(createdFromFg);
- if (startRequested || lastStartId != 0) {
+ if (startRequested || delayedStop || lastStartId != 0) {
pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
+ pw.print(" delayedStop="); pw.print(delayedStop);
pw.print(" stopIfKilled="); pw.print(stopIfKilled);
pw.print(" callStart="); pw.print(callStart);
pw.print(" lastStartId="); pw.println(lastStartId);
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 63793fa..479665c 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -322,6 +322,10 @@
return subtask.activity;
}
+ boolean isHomeTask() {
+ return mTaskType == ActivityRecord.HOME_ACTIVITY_TYPE;
+ }
+
boolean isApplicationTask() {
return mTaskType == ActivityRecord.APPLICATION_ACTIVITY_TYPE;
}
diff --git a/services/java/com/android/server/connectivity/PacManager.java b/services/java/com/android/server/connectivity/PacManager.java
index c8cc85e..772921a 100644
--- a/services/java/com/android/server/connectivity/PacManager.java
+++ b/services/java/com/android/server/connectivity/PacManager.java
@@ -24,17 +24,22 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.net.Proxy;
import android.net.ProxyProperties;
+import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.net.IProxyCallback;
+import com.android.net.IProxyPortListener;
import com.android.net.IProxyService;
import com.android.server.IoThread;
@@ -79,6 +84,7 @@
private Context mContext;
private int mCurrentDelay;
+ private int mLastPort;
/**
* Used for locking when setting mProxyService and all references to mPacUrl or mCurrentPac.
@@ -119,6 +125,7 @@
public PacManager(Context context) {
mContext = context;
+ mLastPort = -1;
mPacRefreshIntent = PendingIntent.getBroadcast(
context, 0, new Intent(ACTION_PAC_REFRESH), 0);
@@ -133,7 +140,16 @@
return mAlarmManager;
}
- public synchronized void setCurrentProxyScriptUrl(ProxyProperties proxy) {
+ /**
+ * Updates the PAC Manager with current Proxy information. This is called by
+ * the ConnectivityService directly before a broadcast takes place to allow
+ * the PacManager to indicate that the broadcast should not be sent and the
+ * PacManager will trigger a new broadcast when it is ready.
+ *
+ * @param proxy Proxy information that is about to be broadcast.
+ * @return Returns true when the broadcast should not be sent
+ */
+ public synchronized boolean setCurrentProxyScriptUrl(ProxyProperties proxy) {
if (!TextUtils.isEmpty(proxy.getPacFileUrl())) {
synchronized (mProxyLock) {
mPacUrl = proxy.getPacFileUrl();
@@ -141,6 +157,7 @@
mCurrentDelay = DELAY_1;
getAlarmManager().cancel(mPacRefreshIntent);
bind();
+ return true;
} else {
getAlarmManager().cancel(mPacRefreshIntent);
synchronized (mProxyLock) {
@@ -156,6 +173,7 @@
}
}
}
+ return false;
}
}
@@ -233,6 +251,16 @@
}
Intent intent = new Intent();
intent.setClassName(PAC_PACKAGE, PAC_SERVICE);
+ // Already bound no need to bind again.
+ if (mProxyConnection != null) {
+ if (mLastPort != -1) {
+ sendPacBroadcast(new ProxyProperties(mPacUrl, mLastPort));
+ } else {
+ Log.e(TAG, "Received invalid port from Local Proxy,"
+ + " PAC will not be operational");
+ }
+ return;
+ }
mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName component) {
@@ -277,6 +305,26 @@
@Override
public void onServiceConnected(ComponentName component, IBinder binder) {
+ IProxyCallback callbackService = IProxyCallback.Stub.asInterface(binder);
+ if (callbackService != null) {
+ try {
+ callbackService.getProxyPort(new IProxyPortListener.Stub() {
+ @Override
+ public void setProxyPort(int port) throws RemoteException {
+ mLastPort = port;
+ if (port != -1) {
+ Log.d(TAG, "Local proxy is bound on " + port);
+ sendPacBroadcast(new ProxyProperties(mPacUrl, port));
+ } else {
+ Log.e(TAG, "Received invalid port from Local Proxy,"
+ + " PAC will not be operational");
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
}
};
mContext.bindService(intent, mProxyConnection,
@@ -287,5 +335,19 @@
mContext.unbindService(mConnection);
mContext.unbindService(mProxyConnection);
mConnection = null;
+ mProxyConnection = null;
+ }
+
+ private void sendPacBroadcast(ProxyProperties proxy) {
+ Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index fb4c1cf..231a40a 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -688,19 +688,6 @@
return retVal;
}
- public String[] getTetheredIfacePairs() {
- final ArrayList<String> list = Lists.newArrayList();
- synchronized (mPublicSync) {
- for (TetherInterfaceSM sm : mIfaces.values()) {
- if (sm.isTethered()) {
- list.add(sm.mMyUpstreamIfaceName);
- list.add(sm.mIfaceName);
- }
- }
- }
- return list.toArray(new String[list.size()]);
- }
-
public String[] getTetherableIfaces() {
ArrayList<String> list = new ArrayList<String>();
synchronized (mPublicSync) {
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index 7b4c077..d749e6c 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -1292,8 +1292,9 @@
// Native callback.
private long notifyANR(InputApplicationHandle inputApplicationHandle,
- InputWindowHandle inputWindowHandle) {
- return mWindowManagerCallbacks.notifyANR(inputApplicationHandle, inputWindowHandle);
+ InputWindowHandle inputWindowHandle, String reason) {
+ return mWindowManagerCallbacks.notifyANR(
+ inputApplicationHandle, inputWindowHandle, reason);
}
// Native callback.
@@ -1477,7 +1478,7 @@
public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
public long notifyANR(InputApplicationHandle inputApplicationHandle,
- InputWindowHandle inputWindowHandle);
+ InputWindowHandle inputWindowHandle, String reason);
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
diff --git a/services/java/com/android/server/location/FlpHardwareProvider.java b/services/java/com/android/server/location/FlpHardwareProvider.java
index ebeccfb..fab84a8 100644
--- a/services/java/com/android/server/location/FlpHardwareProvider.java
+++ b/services/java/com/android/server/location/FlpHardwareProvider.java
@@ -26,6 +26,7 @@
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
+import android.location.LocationRequest;
import android.content.Context;
import android.os.Bundle;
@@ -73,10 +74,19 @@
// register for listening for passive provider data
LocationManager manager = (LocationManager) mContext.getSystemService(
Context.LOCATION_SERVICE);
- manager.requestLocationUpdates(
+ final long minTime = 0;
+ final float minDistance = 0;
+ final boolean oneShot = false;
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(
LocationManager.PASSIVE_PROVIDER,
- 0 /* minTime */,
- 0 /* minDistance */,
+ minTime,
+ minDistance,
+ oneShot);
+ // Don't keep track of this request since it's done on behalf of other clients
+ // (which are kept track of separately).
+ request.setHideFromAppOps(true);
+ manager.requestLocationUpdates(
+ request,
new NetworkLocationListener(),
Looper.myLooper());
}
@@ -141,10 +151,16 @@
}
private void onGeofenceMonitorStatus(int status, int source, Location location) {
+ // allow the location to be optional in this event
+ Location updatedLocation = null;
+ if(location != null) {
+ updatedLocation = updateLocationInformation(location);
+ }
+
getGeofenceHardwareSink().reportGeofenceMonitorStatus(
GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE,
status,
- updateLocationInformation(location),
+ updatedLocation,
source);
}
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 6053c61..9c76c19 100644
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -512,8 +512,21 @@
public void run() {
LocationManager locManager =
(LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
- locManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
- 0, 0, new NetworkLocationListener(), mHandler.getLooper());
+ final long minTime = 0;
+ final float minDistance = 0;
+ final boolean oneShot = false;
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(
+ LocationManager.PASSIVE_PROVIDER,
+ minTime,
+ minDistance,
+ oneShot);
+ // Don't keep track of this request since it's done on behalf of other clients
+ // (which are kept track of separately).
+ request.setHideFromAppOps(true);
+ locManager.requestLocationUpdates(
+ request,
+ new NetworkLocationListener(),
+ mHandler.getLooper());
}
});
}
diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java
index 2b32b41..cea084b 100644
--- a/services/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/java/com/android/server/net/NetworkStatsRecorder.java
@@ -135,6 +135,9 @@
} catch (IOException e) {
Log.wtf(TAG, "problem completely reading network stats", e);
recoverFromWtf();
+ } catch (OutOfMemoryError e) {
+ Log.wtf(TAG, "problem completely reading network stats", e);
+ recoverFromWtf();
}
}
return complete;
@@ -226,6 +229,9 @@
} catch (IOException e) {
Log.wtf(TAG, "problem persisting pending stats", e);
recoverFromWtf();
+ } catch (OutOfMemoryError e) {
+ Log.wtf(TAG, "problem persisting pending stats", e);
+ recoverFromWtf();
}
}
}
@@ -241,6 +247,9 @@
} catch (IOException e) {
Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
recoverFromWtf();
+ } catch (OutOfMemoryError e) {
+ Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
+ recoverFromWtf();
}
// Remove any pending stats
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 05eeb36..1e8a7b0 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -412,6 +412,8 @@
}
} catch (IOException e) {
Log.wtf(TAG, "problem during legacy upgrade", e);
+ } catch (OutOfMemoryError e) {
+ Log.wtf(TAG, "problem during legacy upgrade", e);
}
}
@@ -1186,8 +1188,7 @@
*/
private NetworkStats getNetworkStatsTethering() throws RemoteException {
try {
- final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs();
- return mNetworkManager.getNetworkStatsTethering(tetheredIfacePairs);
+ return mNetworkManager.getNetworkStatsTethering();
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem reading network stats", e);
return new NetworkStats(0L, 10);
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 686b64e..decda96 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1349,6 +1349,9 @@
//delete tmp files
deleteTempPackageFiles();
+ // Remove any shared userIDs that have no associated packages
+ mSettings.pruneSharedUsersLPw();
+
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
@@ -5506,10 +5509,9 @@
// version of the one on the data partition, but which
// granted a new system permission that it didn't have
// before. In this case we do want to allow the app to
- // now get the new permission, because it is allowed by
- // the system image.
- allowed = false;
- if (sysPs.pkg != null) {
+ // now get the new permission if the new system-partition
+ // apk is privileged to get it.
+ if (sysPs.pkg != null && isPrivilegedApp(pkg)) {
for (int j=0;
j<sysPs.pkg.requestedPermissions.size(); j++) {
if (perm.equals(
@@ -9716,10 +9718,6 @@
throw new IllegalArgumentException(
"replacePreferredActivity expects filter to have only 1 action.");
}
- if (filter.countCategories() != 1) {
- throw new IllegalArgumentException(
- "replacePreferredActivity expects filter to have only 1 category.");
- }
if (filter.countDataAuthorities() != 0
|| filter.countDataPaths() != 0
|| filter.countDataSchemes() != 0
@@ -9756,8 +9754,11 @@
removed = new ArrayList<PreferredActivity>();
}
removed.add(pa);
- Log.i(TAG, "Removing preferred activity " + pa.mPref.mComponent + ":");
- filter.dump(new LogPrinter(Log.INFO, TAG), " ");
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, "Removing preferred activity "
+ + pa.mPref.mComponent + ":");
+ filter.dump(new LogPrinter(Log.INFO, TAG), " ");
+ }
}
}
if (removed != null) {
@@ -9877,6 +9878,28 @@
}
@Override
+ public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_HOME);
+
+ final int callingUserId = UserHandle.getCallingUserId();
+ List<ResolveInfo> list = queryIntentActivities(intent, null, 0, callingUserId);
+ ResolveInfo preferred = findPreferredActivity(intent, null, 0, list, 0,
+ true, false, callingUserId);
+
+ allHomeCandidates.clear();
+ if (list != null) {
+ for (ResolveInfo ri : list) {
+ allHomeCandidates.add(ri);
+ }
+ }
+ return (preferred == null || preferred.activityInfo == null)
+ ? null
+ : new ComponentName(preferred.activityInfo.packageName,
+ preferred.activityInfo.name);
+ }
+
+ @Override
public void setApplicationEnabledSetting(String appPackageName,
int newState, int flags, int userId, String callingPackage) {
if (!sUserManager.exists(userId)) return;
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 415cda1..377c390 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -351,6 +351,19 @@
return null;
}
+ void pruneSharedUsersLPw() {
+ ArrayList<String> removeStage = new ArrayList<String>();
+ for (Map.Entry<String,SharedUserSetting> entry : mSharedUsers.entrySet()) {
+ final SharedUserSetting sus = entry.getValue();
+ if (sus == null || sus.packages.size() == 0) {
+ removeStage.add(entry.getKey());
+ }
+ }
+ for (int i = 0; i < removeStage.size(); i++) {
+ mSharedUsers.remove(removeStage.get(i));
+ }
+ }
+
// Transfer ownership of permissions from one package to another.
void transferPermissionsLPw(String origPkg, String newPkg) {
// Transfer ownership of permissions to the new package.
@@ -1395,9 +1408,8 @@
final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
final int[] gids = pkg.getGids();
- // Avoid any application that has a space in its path
- // or that is handled by the system.
- if (dataPath.indexOf(" ") >= 0 || ai.uid < Process.FIRST_APPLICATION_UID)
+ // Avoid any application that has a space in its path.
+ if (dataPath.indexOf(" ") >= 0)
continue;
// we store on each line the following information for now:
@@ -2841,6 +2853,7 @@
ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
+ ApplicationInfo.FLAG_PRIVILEGED, "PRIVILEGED",
ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
};
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index b5010f2..976a328 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -29,7 +29,6 @@
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
-import android.hardware.SystemSensorManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -119,7 +118,7 @@
// Proximity sensor debounce delay in milliseconds for positive or negative transitions.
private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
- private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 500;
+ private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250;
// Trigger proximity if distance is less than 5 cm.
private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
@@ -164,6 +163,10 @@
// Notifier for sending asynchronous notifications.
private final Notifier mNotifier;
+ // The display suspend blocker.
+ // Held while there are pending state change notifications.
+ private final SuspendBlocker mDisplaySuspendBlocker;
+
// The display blanker.
private final DisplayBlanker mDisplayBlanker;
@@ -271,7 +274,7 @@
// The raw non-debounced proximity sensor state.
private int mPendingProximity = PROXIMITY_UNKNOWN;
- private long mPendingProximityDebounceTime;
+ private long mPendingProximityDebounceTime = -1; // -1 if fully debounced
// True if the screen was turned off because of the proximity sensor.
// When the screen turns on again, we report user activity to the power manager.
@@ -346,10 +349,11 @@
public DisplayPowerController(Looper looper, Context context, Notifier notifier,
LightsService lights, TwilightService twilight, SensorManager sensorManager,
DisplayManagerService displayManager,
- DisplayBlanker displayBlanker,
+ SuspendBlocker displaySuspendBlocker, DisplayBlanker displayBlanker,
Callbacks callbacks, Handler callbackHandler) {
mHandler = new DisplayControllerHandler(looper);
mNotifier = notifier;
+ mDisplaySuspendBlocker = displaySuspendBlocker;
mDisplayBlanker = displayBlanker;
mCallbacks = callbacks;
mCallbackHandler = callbackHandler;
@@ -601,7 +605,7 @@
if (!mScreenOffBecauseOfProximity
&& mProximity == PROXIMITY_POSITIVE) {
mScreenOffBecauseOfProximity = true;
- sendOnProximityPositive();
+ sendOnProximityPositiveWithWakelock();
setScreenOn(false);
}
} else if (mWaitingForNegativeProximity
@@ -616,7 +620,7 @@
if (mScreenOffBecauseOfProximity
&& mProximity != PROXIMITY_POSITIVE) {
mScreenOffBecauseOfProximity = false;
- sendOnProximityNegative();
+ sendOnProximityNegativeWithWakelock();
}
} else {
mWaitingForNegativeProximity = false;
@@ -737,7 +741,7 @@
}
}
}
- sendOnStateChanged();
+ sendOnStateChangedWithWakelock();
}
}
@@ -810,49 +814,67 @@
private void setProximitySensorEnabled(boolean enable) {
if (enable) {
if (!mProximitySensorEnabled) {
+ // Register the listener.
+ // Proximity sensor state already cleared initially.
mProximitySensorEnabled = true;
- mPendingProximity = PROXIMITY_UNKNOWN;
mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
SensorManager.SENSOR_DELAY_NORMAL, mHandler);
}
} else {
if (mProximitySensorEnabled) {
+ // Unregister the listener.
+ // Clear the proximity sensor state for next time.
mProximitySensorEnabled = false;
mProximity = PROXIMITY_UNKNOWN;
+ mPendingProximity = PROXIMITY_UNKNOWN;
mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
mSensorManager.unregisterListener(mProximitySensorListener);
+ clearPendingProximityDebounceTime(); // release wake lock (must be last)
}
}
}
private void handleProximitySensorEvent(long time, boolean positive) {
- if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
- return; // no change
- }
- if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
- return; // no change
- }
+ if (mProximitySensorEnabled) {
+ if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
+ return; // no change
+ }
+ if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
+ return; // no change
+ }
- // Only accept a proximity sensor reading if it remains
- // stable for the entire debounce delay.
- mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
- if (positive) {
- mPendingProximity = PROXIMITY_POSITIVE;
- mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY;
- } else {
- mPendingProximity = PROXIMITY_NEGATIVE;
- mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY;
+ // Only accept a proximity sensor reading if it remains
+ // stable for the entire debounce delay. We hold a wake lock while
+ // debouncing the sensor.
+ mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
+ if (positive) {
+ mPendingProximity = PROXIMITY_POSITIVE;
+ setPendingProximityDebounceTime(
+ time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock
+ } else {
+ mPendingProximity = PROXIMITY_NEGATIVE;
+ setPendingProximityDebounceTime(
+ time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock
+ }
+
+ // Debounce the new sensor reading.
+ debounceProximitySensor();
}
- debounceProximitySensor();
}
private void debounceProximitySensor() {
- if (mPendingProximity != PROXIMITY_UNKNOWN) {
+ if (mProximitySensorEnabled
+ && mPendingProximity != PROXIMITY_UNKNOWN
+ && mPendingProximityDebounceTime >= 0) {
final long now = SystemClock.uptimeMillis();
if (mPendingProximityDebounceTime <= now) {
+ // Sensor reading accepted. Apply the change then release the wake lock.
mProximity = mPendingProximity;
- sendUpdatePowerState();
+ updatePowerState();
+ clearPendingProximityDebounceTime(); // release wake lock (must be last)
} else {
+ // Need to wait a little longer.
+ // Debounce again later. We continue holding a wake lock while waiting.
Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
@@ -860,6 +882,20 @@
}
}
+ private void clearPendingProximityDebounceTime() {
+ if (mPendingProximityDebounceTime >= 0) {
+ mPendingProximityDebounceTime = -1;
+ mDisplaySuspendBlocker.release(); // release wake lock
+ }
+ }
+
+ private void setPendingProximityDebounceTime(long debounceTime) {
+ if (mPendingProximityDebounceTime < 0) {
+ mDisplaySuspendBlocker.acquire(); // acquire wake lock
+ }
+ mPendingProximityDebounceTime = debounceTime;
+ }
+
private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness) {
if (enable) {
if (!mLightSensorEnabled) {
@@ -1120,7 +1156,8 @@
return x + (y - x) * alpha;
}
- private void sendOnStateChanged() {
+ private void sendOnStateChangedWithWakelock() {
+ mDisplaySuspendBlocker.acquire();
mCallbackHandler.post(mOnStateChangedRunnable);
}
@@ -1128,10 +1165,12 @@
@Override
public void run() {
mCallbacks.onStateChanged();
+ mDisplaySuspendBlocker.release();
}
};
- private void sendOnProximityPositive() {
+ private void sendOnProximityPositiveWithWakelock() {
+ mDisplaySuspendBlocker.acquire();
mCallbackHandler.post(mOnProximityPositiveRunnable);
}
@@ -1139,10 +1178,12 @@
@Override
public void run() {
mCallbacks.onProximityPositive();
+ mDisplaySuspendBlocker.release();
}
};
- private void sendOnProximityNegative() {
+ private void sendOnProximityNegativeWithWakelock() {
+ mDisplaySuspendBlocker.acquire();
mCallbackHandler.post(mOnProximityNegativeRunnable);
}
@@ -1150,6 +1191,7 @@
@Override
public void run() {
mCallbacks.onProximityNegative();
+ mDisplaySuspendBlocker.release();
}
};
diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/java/com/android/server/power/ElectronBeam.java
index 0d92f66..729bd16 100644
--- a/services/java/com/android/server/power/ElectronBeam.java
+++ b/services/java/com/android/server/power/ElectronBeam.java
@@ -35,6 +35,7 @@
import android.util.Slog;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.Surface.OutOfResourcesException;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -94,7 +95,7 @@
// Texture names. We only use one texture, which contains the screenshot.
private final int[] mTexNames = new int[1];
private boolean mTexNamesGenerated;
- private float mTexMatrix[] = new float[16];
+ private final float mTexMatrix[] = new float[16];
// Vertex and corresponding texture coordinates.
// We have 4 2D vertices, so 8 elements. The vertices form a quad.
@@ -515,7 +516,7 @@
mSurfaceControl = new SurfaceControl(mSurfaceSession,
"ElectronBeam", mDisplayWidth, mDisplayHeight,
PixelFormat.OPAQUE, flags);
- } catch (SurfaceControl.OutOfResourcesException ex) {
+ } catch (OutOfResourcesException ex) {
Slog.e(TAG, "Unable to create surface.", ex);
return false;
}
@@ -525,7 +526,7 @@
mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
mSurface = new Surface();
mSurface.copyFrom(mSurfaceControl);
-
+
mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManager, mSurfaceControl);
mSurfaceLayout.onDisplayTransaction();
} finally {
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 777ffe7c..fe09a33 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -63,7 +63,6 @@
import android.view.WindowManagerPolicy;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -287,6 +286,9 @@
// True if the device should wake up when plugged or unplugged.
private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
+ // True if the device should suspend when the screen is off due to proximity.
+ private boolean mSuspendWhenScreenOffDueToProximityConfig;
+
// True if dreams are supported on this device.
private boolean mDreamsSupportedConfig;
@@ -447,7 +449,7 @@
// own handler thread to ensure timely operation.
mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
mContext, mNotifier, mLightsService, twilight, sensorManager,
- mDisplayManagerService, mDisplayBlanker,
+ mDisplayManagerService, mDisplaySuspendBlocker, mDisplayBlanker,
mDisplayPowerControllerCallbacks, mHandler);
mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
@@ -514,6 +516,8 @@
mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
com.android.internal.R.bool.config_unplugTurnsOnScreen);
+ mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity);
mDreamsSupportedConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsSupported);
mDreamsEnabledByDefaultConfig = resources.getBoolean(
@@ -639,6 +643,7 @@
}
}
+ @SuppressWarnings("deprecation")
private static boolean isScreenLock(final WakeLock wakeLock) {
switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.FULL_WAKE_LOCK:
@@ -650,8 +655,8 @@
}
private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock) {
- if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0 &&
- isScreenLock(wakeLock)) {
+ if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0
+ && isScreenLock(wakeLock)) {
wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
}
}
@@ -725,7 +730,8 @@
}
private void applyWakeLockFlagsOnReleaseLocked(WakeLock wakeLock) {
- if ((wakeLock.mFlags & PowerManager.ON_AFTER_RELEASE) != 0) {
+ if ((wakeLock.mFlags & PowerManager.ON_AFTER_RELEASE) != 0
+ && isScreenLock(wakeLock)) {
userActivityNoUpdateLocked(SystemClock.uptimeMillis(),
PowerManager.USER_ACTIVITY_EVENT_OTHER,
PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS,
@@ -816,6 +822,7 @@
}
}
+ @SuppressWarnings("deprecation")
private boolean isWakeLockLevelSupportedInternal(int level) {
synchronized (mLock) {
switch (level) {
@@ -1004,6 +1011,7 @@
}
}
+ @SuppressWarnings("deprecation")
private boolean goToSleepNoUpdateLocked(long eventTime, int reason) {
if (DEBUG_SPEW) {
Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime + ", reason=" + reason);
@@ -1260,6 +1268,7 @@
*
* This function must have no other side-effects.
*/
+ @SuppressWarnings("deprecation")
private void updateWakeLockSummaryLocked(int dirty) {
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
mWakeLockSummary = 0;
@@ -1298,7 +1307,7 @@
break;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
if (mWakefulness != WAKEFULNESS_ASLEEP) {
- mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_PROXIMITY_SCREEN_OFF;
+ mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
}
break;
}
@@ -1457,7 +1466,11 @@
/**
* Returns true if the device is being kept awake by a wake lock, user activity
- * or the stay on while powered setting.
+ * or the stay on while powered setting. We also keep the phone awake when
+ * the proximity sensor returns a positive result so that the device does not
+ * lock while in a phone call. This function only controls whether the device
+ * will go to sleep or dream which is independent of whether it will be allowed
+ * to suspend.
*/
private boolean isBeingKeptAwakeLocked() {
return mStayOn
@@ -1748,10 +1761,8 @@
* This function must have no other side-effects.
*/
private void updateSuspendBlockerLocked() {
- final boolean needWakeLockSuspendBlocker = (mWakeLockSummary != 0);
- final boolean needDisplaySuspendBlocker = (mUserActivitySummary != 0
- || mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF
- || !mDisplayReady || !mBootCompleted);
+ final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
+ final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();
// First acquire suspend blockers if needed.
if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
@@ -1774,6 +1785,27 @@
}
}
+ /**
+ * Return true if we must keep a suspend blocker active on behalf of the display.
+ * We do so if the screen is on or is in transition between states.
+ */
+ private boolean needDisplaySuspendBlocker() {
+ if (!mDisplayReady) {
+ return true;
+ }
+ if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
+ // If we asked for the screen to be on but it is off due to the proximity
+ // sensor then we may suspend but only if the configuration allows it.
+ // On some hardware it may not be safe to suspend because the proximity
+ // sensor may not be correctly configured as a wake-up source.
+ if (!mDisplayPowerRequest.useProximitySensor || !mProximityPositive
+ || !mSuspendWhenScreenOffDueToProximityConfig) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override // Binder call
public boolean isScreenOn() {
final long ident = Binder.clearCallingIdentity();
@@ -2114,7 +2146,7 @@
*
* @param brightness The overridden brightness.
*
- * @see Settings.System#SCREEN_BRIGHTNESS
+ * @see android.provider.Settings.System#SCREEN_BRIGHTNESS
*/
@Override // Binder call
public void setTemporaryScreenBrightnessSettingOverride(int brightness) {
@@ -2254,7 +2286,16 @@
pw.println();
pw.println("Settings and Configuration:");
+ pw.println(" mWakeUpWhenPluggedOrUnpluggedConfig="
+ + mWakeUpWhenPluggedOrUnpluggedConfig);
+ pw.println(" mSuspendWhenScreenOffDueToProximityConfig="
+ + mSuspendWhenScreenOffDueToProximityConfig);
pw.println(" mDreamsSupportedConfig=" + mDreamsSupportedConfig);
+ pw.println(" mDreamsEnabledByDefaultConfig=" + mDreamsEnabledByDefaultConfig);
+ pw.println(" mDreamsActivatedOnSleepByDefaultConfig="
+ + mDreamsActivatedOnSleepByDefaultConfig);
+ pw.println(" mDreamsActivatedOnDockByDefaultConfig="
+ + mDreamsActivatedOnDockByDefaultConfig);
pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting);
pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
diff --git a/services/java/com/android/server/power/WirelessChargerDetector.java b/services/java/com/android/server/power/WirelessChargerDetector.java
index ac6dc3e..35920f7 100644
--- a/services/java/com/android/server/power/WirelessChargerDetector.java
+++ b/services/java/com/android/server/power/WirelessChargerDetector.java
@@ -21,6 +21,7 @@
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.BatteryManager;
+import android.os.SystemClock;
import android.util.Slog;
import java.io.PrintWriter;
@@ -130,6 +131,10 @@
private long mFirstSampleTime;
private float mFirstSampleX, mFirstSampleY, mFirstSampleZ;
+ // The time and value of the last sample that was collected (for debugging only).
+ private long mLastSampleTime;
+ private float mLastSampleX, mLastSampleY, mLastSampleZ;
+
public WirelessChargerDetector(SensorManager sensorManager,
SuspendBlocker suspendBlocker) {
mSensorManager = sensorManager;
@@ -153,6 +158,9 @@
pw.println(" mFirstSampleTime=" + mFirstSampleTime);
pw.println(" mFirstSampleX=" + mFirstSampleX
+ ", mFirstSampleY=" + mFirstSampleY + ", mFirstSampleZ=" + mFirstSampleZ);
+ pw.println(" mLastSampleTime=" + mLastSampleTime);
+ pw.println(" mLastSampleX=" + mLastSampleX
+ + ", mLastSampleY=" + mLastSampleY + ", mLastSampleZ=" + mLastSampleZ);
}
}
@@ -224,6 +232,11 @@
return;
}
+ mLastSampleTime = timeNanos;
+ mLastSampleX = x;
+ mLastSampleY = y;
+ mLastSampleZ = z;
+
mTotalSamples += 1;
if (mTotalSamples == 1) {
// Save information about the first sample collected.
@@ -310,7 +323,10 @@
private final SensorEventListener mListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
- processSample(event.timestamp, event.values[0], event.values[1], event.values[2]);
+ // We use SystemClock.elapsedRealtimeNanos() instead of event.timestamp because
+ // on some devices the sensor HAL may produce timestamps that are not monotonic.
+ processSample(SystemClock.elapsedRealtimeNanos(),
+ event.values[0], event.values[1], event.values[2]);
}
@Override
diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java
index 926f822..ddc5046 100644
--- a/services/java/com/android/server/print/PrintManagerService.java
+++ b/services/java/com/android/server/print/PrintManagerService.java
@@ -33,8 +33,10 @@
import android.print.IPrintManager;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintAttributes;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrinterId;
+import android.printservice.PrintServiceInfo;
import android.provider.Settings;
import android.util.SparseArray;
@@ -69,30 +71,32 @@
BackgroundThread.getHandler().post(new Runnable() {
@Override
public void run() {
+ final UserState userState;
synchronized (mLock) {
- UserState userState = getCurrentUserStateLocked();
+ userState = getCurrentUserStateLocked();
userState.updateIfNeededLocked();
- userState.getSpoolerLocked().start();
}
+ // This is the first time we switch to this user after boot, so
+ // now is the time to remove obsolete print jobs since they
+ // are from the last boot and no application would query them.
+ userState.removeObsoletePrintJobs();
}
});
}
@Override
- public PrintJobInfo print(String printJobName, IPrintClient client,
- IPrintDocumentAdapter documentAdapter, PrintAttributes attributes, int appId,
- int userId) {
+ public PrintJobInfo print(String printJobName, final IPrintClient client,
+ final IPrintDocumentAdapter documentAdapter, PrintAttributes attributes,
+ int appId, int userId) {
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
- final RemotePrintSpooler spooler;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
- spooler = userState.getSpoolerLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
- return spooler.createPrintJob(printJobName, client, documentAdapter,
+ return userState.print(printJobName, client, documentAdapter,
attributes, resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -104,89 +108,75 @@
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
- final RemotePrintSpooler spooler;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
- spooler = userState.getSpoolerLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
- return spooler.getPrintJobInfos(null, PrintJobInfo.STATE_ANY,
- resolvedAppId);
+ return userState.getPrintJobInfos(resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
- public PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId) {
+ public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
- final RemotePrintSpooler spooler;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
- spooler = userState.getSpoolerLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
- return spooler.getPrintJobInfo(printJobId, resolvedAppId);
+ return userState.getPrintJobInfo(printJobId, resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
- public void cancelPrintJob(int printJobId, int appId, int userId) {
+ public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
- final RemotePrintSpooler spooler;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
- spooler = userState.getSpoolerLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
- PrintJobInfo printJobInfo = spooler.getPrintJobInfo(printJobId, resolvedAppId);
- if (printJobInfo == null) {
- return;
- }
- if (printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
- ComponentName printServiceName = printJobInfo.getPrinterId().getServiceName();
- RemotePrintService printService = null;
- synchronized (mLock) {
- printService = userState.getActiveServicesLocked().get(printServiceName);
- }
- if (printService == null) {
- return;
- }
- printService.onRequestCancelPrintJob(printJobInfo);
- } else {
- // If the print job is failed we do not need cooperation
- // from the print service.
- spooler.setPrintJobState(printJobId, PrintJobInfo.STATE_CANCELED, null);
- }
+ userState.cancelPrintJob(printJobId, resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
- public void restartPrintJob(int printJobId, int appId, int userId) {
+ public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
- final RemotePrintSpooler spooler;
+ final UserState userState;
synchronized (mLock) {
- spooler = getOrCreateUserStateLocked(resolvedUserId).getSpoolerLocked();
+ userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
try {
- PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, resolvedAppId, resolvedUserId);
- if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
- return;
- }
- spooler.setPrintJobState(printJobId, PrintJobInfo.STATE_QUEUED, null);
+ userState.restartPrintJob(printJobId, resolvedAppId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public List<PrintServiceInfo> getEnabledPrintServices(int userId) {
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ synchronized (mLock) {
+ userState = getOrCreateUserStateLocked(resolvedUserId);
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return userState.getEnabledPrintServices();
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -426,6 +416,7 @@
// user changes
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ intentFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
@@ -454,15 +445,24 @@
}
private void switchUser(int newUserId) {
+ UserState userState;
synchronized (mLock) {
if (newUserId == mCurrentUserId) {
return;
}
mCurrentUserId = newUserId;
- UserState userState = getCurrentUserStateLocked();
- userState.updateIfNeededLocked();
- userState.getSpoolerLocked().start();
+ userState = mUserStates.get(mCurrentUserId);
+ if (userState == null) {
+ userState = getCurrentUserStateLocked();
+ userState.updateIfNeededLocked();
+ } else {
+ userState.updateIfNeededLocked();
+ }
}
+ // This is the first time we switch to this user after boot, so
+ // now is the time to remove obsolete print jobs since they
+ // are from the last boot and no application would query them.
+ userState.removeObsoletePrintJobs();
}
private void removeUser(int removedUserId) {
diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java
index ddff0ae..a20973e 100644
--- a/services/java/com/android/server/print/RemotePrintService.java
+++ b/services/java/com/android/server/print/RemotePrintService.java
@@ -20,17 +20,17 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.ParceledListSlice;
import android.os.Binder;
-import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
-import android.os.AsyncTask;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrinterId;
@@ -39,8 +39,6 @@
import android.printservice.IPrintServiceClient;
import android.util.Slog;
-import com.android.internal.R;
-
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -55,7 +53,7 @@
private static final String LOG_TAG = "RemotePrintService";
- private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+ private static final boolean DEBUG = false;
private final Context mContext;
@@ -65,7 +63,7 @@
private final RemotePrintSpooler mSpooler;
- private final UserState mUserState;
+ private final PrintServiceCallbacks mCallbacks;
private final int mUserId;
@@ -83,20 +81,37 @@
private boolean mDestroyed;
- private boolean mAllPrintJobsHandled;
+ private boolean mHasActivePrintJobs;
private boolean mHasPrinterDiscoverySession;
+ private boolean mServiceDead;
+
+ private List<PrinterId> mDiscoveryPriorityList;
+
+ private List<PrinterId> mTrackedPrinterList;
+
+ public static interface PrintServiceCallbacks {
+ public void onPrintersAdded(List<PrinterInfo> printers);
+ public void onPrintersRemoved(List<PrinterId> printerIds);
+ public void onServiceDied(RemotePrintService service);
+ }
+
public RemotePrintService(Context context, ComponentName componentName, int userId,
- RemotePrintSpooler spooler, UserState userState) {
+ RemotePrintSpooler spooler, PrintServiceCallbacks callbacks) {
mContext = context;
- mUserState = userState;
+ mCallbacks = callbacks;
mComponentName = componentName;
mIntent = new Intent().setComponent(mComponentName);
mUserId = userId;
mSpooler = spooler;
mHandler = new MyHandler(context.getMainLooper());
mPrintServiceClient = new RemotePrintServiceClient(this);
+ mServiceDead = true;
+ }
+
+ public ComponentName getComponentName() {
+ return mComponentName;
}
public void destroy() {
@@ -105,14 +120,33 @@
private void handleDestroy() {
throwIfDestroyed();
- ensureUnbound();
- mAllPrintJobsHandled = false;
- mHasPrinterDiscoverySession = false;
- mDestroyed = true;
- }
- public void onAllPrintJobsHandled() {
- mHandler.sendEmptyMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_HANDLED);
+ // Stop tracking printers.
+ if (mTrackedPrinterList != null) {
+ final int trackedPrinterCount = mTrackedPrinterList.size();
+ for (int i = 0; i < trackedPrinterCount; i++) {
+ PrinterId printerId = mTrackedPrinterList.get(i);
+ if (printerId.getServiceName().equals(mComponentName)) {
+ handleStopPrinterStateTracking(printerId);
+ }
+ }
+ }
+
+ // Stop printer discovery.
+ if (mDiscoveryPriorityList != null) {
+ handleStopPrinterDiscovery();
+ }
+
+ // Destroy the discovery session.
+ if (mHasPrinterDiscoverySession) {
+ handleDestroyPrinterDiscoverySession();
+ }
+
+ // Unbind.
+ ensureUnbound();
+
+ // Done
+ mDestroyed = true;
}
@Override
@@ -121,65 +155,37 @@
}
private void handleBinderDied() {
- mAllPrintJobsHandled = false;
- mHasPrinterDiscoverySession = false;
- mPendingCommands.clear();
- ensureUnbound();
-
- // Makes sure all active print jobs are failed since the service
- // just died. Do this off the main thread since we do to allow
- // calls into the spooler on the main thread.
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- failAllActivePrintJobs();
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ mPrintService.asBinder().unlinkToDeath(this, 0);
+ mPrintService = null;
+ mServiceDead = true;
+ mCallbacks.onServiceDied(this);
}
- public void dump(PrintWriter pw, String prefix) {
- String tab = " ";
- pw.append(prefix).append("service:").println();
- pw.append(prefix).append(tab).append("componentName=")
- .append(mComponentName.flattenToString()).println();
- pw.append(prefix).append(tab).append("destroyed=")
- .append(String.valueOf(mDestroyed)).println();
- pw.append(prefix).append(tab).append("bound=")
- .append(String.valueOf(isBound())).println();
- pw.append(prefix).append(tab).append("hasDicoverySession=")
- .append(String.valueOf(mHasPrinterDiscoverySession));
- }
-
- private void failAllActivePrintJobs() {
- List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(mComponentName,
- PrintJobInfo.STATE_ANY_ACTIVE, PrintManager.APP_ID_ANY);
- if (printJobs == null) {
- return;
- }
- final long identity = Binder.clearCallingIdentity();
- try {
- final int printJobCount = printJobs.size();
- for (int i = 0; i < printJobCount; i++) {
- PrintJobInfo printJob = printJobs.get(i);
- mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
- mContext.getString(R.string.reason_unknown));
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ public void onAllPrintJobsHandled() {
+ mHandler.sendEmptyMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_HANDLED);
}
private void handleOnAllPrintJobsHandled() {
throwIfDestroyed();
-
- mAllPrintJobsHandled = true;
-
- if (isBound()) {
+ mHasActivePrintJobs = false;
+ if (!isBound()) {
+ // The service is dead and neither has active jobs nor discovery
+ // session, so ensure we are unbound since the service has no work.
+ if (mServiceDead && !mHasPrinterDiscoverySession) {
+ ensureUnbound();
+ return;
+ }
+ ensureBound();
+ mPendingCommands.add(new Runnable() {
+ @Override
+ public void run() {
+ handleOnAllPrintJobsHandled();
+ }
+ });
+ } else {
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserId + "] onAllPrintJobsHandled()");
}
-
// If the service has a printer discovery session
// created we should not disconnect from it just yet.
if (!mHasPrinterDiscoverySession) {
@@ -195,9 +201,15 @@
private void handleRequestCancelPrintJob(final PrintJobInfo printJob) {
throwIfDestroyed();
- // If we are not bound, then we have no print jobs to handle
- // which means that there are no print jobs to be cancelled.
- if (isBound()) {
+ if (!isBound()) {
+ ensureBound();
+ mPendingCommands.add(new Runnable() {
+ @Override
+ public void run() {
+ handleRequestCancelPrintJob(printJob);
+ }
+ });
+ } else {
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserId + "] requestCancelPrintJob()");
}
@@ -216,14 +228,12 @@
private void handleOnPrintJobQueued(final PrintJobInfo printJob) {
throwIfDestroyed();
-
- mAllPrintJobsHandled = false;
-
+ mHasActivePrintJobs = true;
if (!isBound()) {
ensureBound();
mPendingCommands.add(new Runnable() {
@Override
- public void run() {
+ public void run() {
handleOnPrintJobQueued(printJob);
}
});
@@ -245,6 +255,7 @@
private void handleCreatePrinterDiscoverySession() {
throwIfDestroyed();
+ mHasPrinterDiscoverySession = true;
if (!isBound()) {
ensureBound();
mPendingCommands.add(new Runnable() {
@@ -262,8 +273,6 @@
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error creating printer dicovery session.", re);
}
-
- mHasPrinterDiscoverySession = true;
}
}
@@ -273,7 +282,14 @@
private void handleDestroyPrinterDiscoverySession() {
throwIfDestroyed();
+ mHasPrinterDiscoverySession = false;
if (!isBound()) {
+ // The service is dead and neither has active jobs nor discovery
+ // session, so ensure we are unbound since the service has no work.
+ if (mServiceDead && !mHasActivePrintJobs) {
+ ensureUnbound();
+ return;
+ }
ensureBound();
mPendingCommands.add(new Runnable() {
@Override
@@ -285,18 +301,14 @@
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserId + "] destroyPrinterDiscoverySession()");
}
-
- mHasPrinterDiscoverySession = false;
-
try {
mPrintService.destroyPrinterDiscoverySession();
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error destroying printer dicovery session.", re);
}
-
// If the service has no print jobs and no active discovery
// session anymore we should disconnect from it.
- if (mAllPrintJobsHandled) {
+ if (!mHasActivePrintJobs) {
ensureUnbound();
}
}
@@ -309,6 +321,11 @@
private void handleStartPrinterDiscovery(final List<PrinterId> priorityList) {
throwIfDestroyed();
+ // Take a note that we are doing discovery.
+ mDiscoveryPriorityList = new ArrayList<PrinterId>();
+ if (priorityList != null) {
+ mDiscoveryPriorityList.addAll(priorityList);
+ }
if (!isBound()) {
ensureBound();
mPendingCommands.add(new Runnable() {
@@ -335,6 +352,8 @@
private void handleStopPrinterDiscovery() {
throwIfDestroyed();
+ // We are not doing discovery anymore.
+ mDiscoveryPriorityList = null;
if (!isBound()) {
ensureBound();
mPendingCommands.add(new Runnable() {
@@ -389,6 +408,11 @@
private void handleStartPrinterStateTracking(final PrinterId printerId) {
throwIfDestroyed();
+ // Take a note we are tracking the printer.
+ if (mTrackedPrinterList == null) {
+ mTrackedPrinterList = new ArrayList<PrinterId>();
+ }
+ mTrackedPrinterList.add(printerId);
if (!isBound()) {
ensureBound();
mPendingCommands.add(new Runnable() {
@@ -416,6 +440,13 @@
private void handleStopPrinterStateTracking(final PrinterId printerId) {
throwIfDestroyed();
+ // We are no longer tracking the printer.
+ if (mTrackedPrinterList == null || !mTrackedPrinterList.remove(printerId)) {
+ return;
+ }
+ if (mTrackedPrinterList.isEmpty()) {
+ mTrackedPrinterList = null;
+ }
if (!isBound()) {
ensureBound();
mPendingCommands.add(new Runnable() {
@@ -436,6 +467,25 @@
}
}
+ public void dump(PrintWriter pw, String prefix) {
+ String tab = " ";
+ pw.append(prefix).append("service:").println();
+ pw.append(prefix).append(tab).append("componentName=")
+ .append(mComponentName.flattenToString()).println();
+ pw.append(prefix).append(tab).append("destroyed=")
+ .append(String.valueOf(mDestroyed)).println();
+ pw.append(prefix).append(tab).append("bound=")
+ .append(String.valueOf(isBound())).println();
+ pw.append(prefix).append(tab).append("hasDicoverySession=")
+ .append(String.valueOf(mHasPrinterDiscoverySession)).println();
+ pw.append(prefix).append(tab).append("hasActivePrintJobs=")
+ .append(String.valueOf(mHasActivePrintJobs)).println();
+ pw.append(prefix).append(tab).append("isDiscoveringPrinters=")
+ .append(String.valueOf(mDiscoveryPriorityList != null)).println();
+ pw.append(prefix).append(tab).append("trackedPrinters=")
+ .append((mTrackedPrinterList != null) ? mTrackedPrinterList.toString() : "null");
+ }
+
private boolean isBound() {
return mPrintService != null;
}
@@ -461,6 +511,10 @@
}
mBinding = false;
mPendingCommands.clear();
+ mHasActivePrintJobs = false;
+ mHasPrinterDiscoverySession = false;
+ mDiscoveryPriorityList = null;
+ mTrackedPrinterList = null;
if (isBound()) {
try {
mPrintService.setClient(null);
@@ -483,6 +537,7 @@
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (mDestroyed || !mBinding) {
+ mContext.unbindService(mServiceConnection);
return;
}
mBinding = false;
@@ -500,11 +555,33 @@
handleBinderDied();
return;
}
- final int pendingCommandCount = mPendingCommands.size();
- for (int i = 0; i < pendingCommandCount; i++) {
- Runnable pendingCommand = mPendingCommands.get(i);
+ // If the service died and there is a discovery session, recreate it.
+ if (mServiceDead && mHasPrinterDiscoverySession) {
+ handleCreatePrinterDiscoverySession();
+ }
+ // If the service died and there is discovery started, restart it.
+ if (mServiceDead && mDiscoveryPriorityList != null) {
+ handleStartPrinterDiscovery(mDiscoveryPriorityList);
+ }
+ // If the service died and printers were tracked, start tracking.
+ if (mServiceDead && mTrackedPrinterList != null) {
+ final int trackedPrinterCount = mTrackedPrinterList.size();
+ for (int i = 0; i < trackedPrinterCount; i++) {
+ handleStartPrinterStateTracking(mTrackedPrinterList.get(i));
+ }
+ }
+ // Finally, do all the pending work.
+ while (!mPendingCommands.isEmpty()) {
+ Runnable pendingCommand = mPendingCommands.remove(0);
pendingCommand.run();
}
+ // We did a best effort to get to the last state if we crashed.
+ // If we do not have print jobs and no discovery is in progress,
+ // then no need to be bound.
+ if (!mHasPrinterDiscoverySession && !mHasActivePrintJobs) {
+ ensureUnbound();
+ }
+ mServiceDead = false;
}
@Override
@@ -615,7 +692,7 @@
}
@Override
- public PrintJobInfo getPrintJobInfo(int printJobId) {
+ public PrintJobInfo getPrintJobInfo(PrintJobId printJobId) {
RemotePrintService service = mWeakService.get();
if (service != null) {
final long identity = Binder.clearCallingIdentity();
@@ -630,7 +707,7 @@
}
@Override
- public boolean setPrintJobState(int printJobId, int state, String error) {
+ public boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
RemotePrintService service = mWeakService.get();
if (service != null) {
final long identity = Binder.clearCallingIdentity();
@@ -644,7 +721,7 @@
}
@Override
- public boolean setPrintJobTag(int printJobId, String tag) {
+ public boolean setPrintJobTag(PrintJobId printJobId, String tag) {
RemotePrintService service = mWeakService.get();
if (service != null) {
final long identity = Binder.clearCallingIdentity();
@@ -658,7 +735,7 @@
}
@Override
- public void writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
+ public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
RemotePrintService service = mWeakService.get();
if (service != null) {
final long identity = Binder.clearCallingIdentity();
@@ -671,13 +748,15 @@
}
@Override
- public void onPrintersAdded(List<PrinterInfo> printers) {
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void onPrintersAdded(ParceledListSlice printers) {
RemotePrintService service = mWeakService.get();
if (service != null) {
- throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, printers);
+ List<PrinterInfo> addedPrinters = (List<PrinterInfo>) printers.getList();
+ throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, addedPrinters);
final long identity = Binder.clearCallingIdentity();
try {
- service.mUserState.onPrintersAdded(printers);
+ service.mCallbacks.onPrintersAdded(addedPrinters);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -685,13 +764,15 @@
}
@Override
- public void onPrintersRemoved(List<PrinterId> printerIds) {
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void onPrintersRemoved(ParceledListSlice printerIds) {
RemotePrintService service = mWeakService.get();
if (service != null) {
- throwIfPrinterIdsTampered(service.mComponentName, printerIds);
+ List<PrinterId> removedPrinterIds = (List<PrinterId>) printerIds.getList();
+ throwIfPrinterIdsTampered(service.mComponentName, removedPrinterIds);
final long identity = Binder.clearCallingIdentity();
try {
- service.mUserState.onPrintersRemoved(printerIds);
+ service.mCallbacks.onPrintersRemoved(removedPrinterIds);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java
index 28a6186..1bde6d7 100644
--- a/services/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/java/com/android/server/print/RemotePrintSpooler.java
@@ -21,7 +21,6 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
-import android.os.Build;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -32,20 +31,20 @@
import android.print.IPrintSpooler;
import android.print.IPrintSpoolerCallbacks;
import android.print.IPrintSpoolerClient;
-import android.print.PrintAttributes;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.util.Slog;
import android.util.TimedRemoteCaller;
-import libcore.io.IoUtils;
-
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.concurrent.TimeoutException;
+import libcore.io.IoUtils;
+
/**
* This represents the remote print spooler as a local object to the
* PrintManagerSerivce. It is responsible to connecting to the remote
@@ -57,7 +56,7 @@
private static final String LOG_TAG = "RemotePrintSpooler";
- private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+ private static final boolean DEBUG = false;
private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000;
@@ -65,8 +64,6 @@
private final GetPrintJobInfosCaller mGetPrintJobInfosCaller = new GetPrintJobInfosCaller();
- private final CreatePrintJobCaller mCreatePrintJobCaller = new CreatePrintJobCaller();
-
private final GetPrintJobInfoCaller mGetPrintJobInfoCaller = new GetPrintJobInfoCaller();
private final SetPrintJobStateCaller mSetPrintJobStatusCaller = new SetPrintJobStateCaller();
@@ -133,16 +130,15 @@
return null;
}
- public final PrintJobInfo createPrintJob(String printJobName, IPrintClient client,
- IPrintDocumentAdapter documentAdapter, PrintAttributes attributes, int appId) {
+ public final void createPrintJob(PrintJobInfo printJob, IPrintClient client,
+ IPrintDocumentAdapter documentAdapter) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
mCanUnbind = false;
}
try {
- return mCreatePrintJobCaller.createPrintJob(getRemoteInstanceLazy(),
- printJobName, client, documentAdapter, attributes, appId);
+ getRemoteInstanceLazy().createPrintJob(printJob, client, documentAdapter);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error creating print job.", re);
} catch (TimeoutException te) {
@@ -156,10 +152,9 @@
mLock.notifyAll();
}
}
- return null;
}
- public final void writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
+ public final void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -185,7 +180,7 @@
}
}
- public final PrintJobInfo getPrintJobInfo(int printJobId, int appId) {
+ public final PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -210,7 +205,7 @@
return null;
}
- public final boolean setPrintJobState(int printJobId, int state, String error) {
+ public final boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -235,7 +230,7 @@
return false;
}
- public final boolean setPrintJobTag(int printJobId, String tag) {
+ public final boolean setPrintJobTag(PrintJobId printJobId, String tag) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -260,19 +255,46 @@
return false;
}
- public final void start() {
+ public final void removeObsoletePrintJobs() {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
mCanUnbind = false;
}
try {
- getRemoteInstanceLazy();
+ getRemoteInstanceLazy().removeObsoletePrintJobs();
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error removing obsolete print jobs .", re);
} catch (TimeoutException te) {
- Slog.e(LOG_TAG, "Error starting the spooler.", te);
+ Slog.e(LOG_TAG, "Error removing obsolete print jobs .", te);
} finally {
if (DEBUG) {
- Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] start()");
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
+ + "] removeObsoletePrintJobs()");
+ }
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
+ }
+ }
+
+ public final void forgetPrintJobs(List<PrintJobId> printJobIds) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ mCanUnbind = false;
+ }
+ try {
+ getRemoteInstanceLazy().forgetPrintJobs(printJobIds);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error forgeting print jobs", re);
+ } catch (TimeoutException te) {
+ Slog.e(LOG_TAG, "Error forgeting print jobs", te);
+ } finally {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
+ + "] forgetPrintJobs()");
}
synchronized (mLock) {
mCanUnbind = true;
@@ -334,6 +356,9 @@
}
private void bindLocked() throws TimeoutException {
+ if (mRemoteInstance != null) {
+ return;
+ }
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] bindLocked()");
}
@@ -363,6 +388,9 @@
}
private void unbindLocked() {
+ if (mRemoteInstance == null) {
+ return;
+ }
while (true) {
if (mCanUnbind) {
if (DEBUG) {
@@ -453,29 +481,6 @@
}
}
- private static final class CreatePrintJobCaller extends TimedRemoteCaller<PrintJobInfo> {
- private final IPrintSpoolerCallbacks mCallback;
-
- public CreatePrintJobCaller() {
- super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
- mCallback = new BasePrintSpoolerServiceCallbacks() {
- @Override
- public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) {
- onRemoteMethodResult(printJob, sequence);
- }
- };
- }
-
- public PrintJobInfo createPrintJob(IPrintSpooler target, String printJobName,
- IPrintClient client, IPrintDocumentAdapter documentAdapter,
- PrintAttributes attributes, int appId) throws RemoteException, TimeoutException {
- final int sequence = onBeforeRemoteCall();
- target.createPrintJob(printJobName, client, documentAdapter, attributes,
- mCallback, appId, sequence);
- return getResultTimed(sequence);
- }
- }
-
private static final class GetPrintJobInfoCaller extends TimedRemoteCaller<PrintJobInfo> {
private final IPrintSpoolerCallbacks mCallback;
@@ -489,7 +494,7 @@
};
}
- public PrintJobInfo getPrintJobInfo(IPrintSpooler target, int printJobId,
+ public PrintJobInfo getPrintJobInfo(IPrintSpooler target, PrintJobId printJobId,
int appId) throws RemoteException, TimeoutException {
final int sequence = onBeforeRemoteCall();
target.getPrintJobInfo(printJobId, mCallback, appId, sequence);
@@ -510,7 +515,7 @@
};
}
- public boolean setPrintJobState(IPrintSpooler target, int printJobId,
+ public boolean setPrintJobState(IPrintSpooler target, PrintJobId printJobId,
int status, String error) throws RemoteException, TimeoutException {
final int sequence = onBeforeRemoteCall();
target.setPrintJobState(printJobId, status, error, mCallback, sequence);
@@ -531,7 +536,7 @@
};
}
- public boolean setPrintJobTag(IPrintSpooler target, int printJobId,
+ public boolean setPrintJobTag(IPrintSpooler target, PrintJobId printJobId,
String tag) throws RemoteException, TimeoutException {
final int sequence = onBeforeRemoteCall();
target.setPrintJobTag(printJobId, tag, mCallback, sequence);
@@ -552,11 +557,6 @@
}
@Override
- public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) {
- /* do nothing */
- }
-
- @Override
public void onCancelPrintJobResult(boolean canceled, int sequence) {
/* do nothing */
}
diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java
index 5392975..fd4a3a4 100644
--- a/services/java/com/android/server/print/UserState.java
+++ b/services/java/com/android/server/print/UserState.java
@@ -21,17 +21,26 @@
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.os.Build;
+import android.os.AsyncTask;
+import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.UserManager;
+import android.print.IPrintClient;
+import android.print.IPrintDocumentAdapter;
import android.print.IPrinterDiscoveryObserver;
+import android.print.PrintAttributes;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
+import android.print.PrintManager;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.printservice.PrintServiceInfo;
@@ -43,7 +52,10 @@
import android.util.Log;
import android.util.Slog;
+import com.android.internal.R;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.os.SomeArgs;
+import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
import java.io.FileDescriptor;
@@ -52,19 +64,16 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Set;
/**
* Represents the print state for a user.
*/
-final class UserState implements PrintSpoolerCallbacks {
+final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
private static final String LOG_TAG = "UserState";
- private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
-
- private static final int MAX_ITEMS_PER_CALLBACK = 50;
+ private static final boolean DEBUG = false;
private static final char COMPONENT_NAME_SEPARATOR = ':';
@@ -83,6 +92,9 @@
private final Set<ComponentName> mEnabledServices =
new ArraySet<ComponentName>();
+ private final CreatedPrintJobTracker mCreatedPrintJobTracker =
+ new CreatedPrintJobTracker();
+
private final Object mLock;
private final Context mContext;
@@ -130,6 +142,99 @@
}
}
+ public void removeObsoletePrintJobs() {
+ mSpooler.removeObsoletePrintJobs();
+ }
+
+ public PrintJobInfo print(String printJobName, final IPrintClient client,
+ final IPrintDocumentAdapter documentAdapter, PrintAttributes attributes,
+ int appId) {
+ PrintJobId printJobId = new PrintJobId();
+
+ // Track this job so we can forget it when the creator dies.
+ if (!mCreatedPrintJobTracker.onPrintJobCreatedLocked(client.asBinder(), printJobId)) {
+ // Not adding a print job means the client is dead - done.
+ return null;
+ }
+
+ // Create print job place holder.
+ final PrintJobInfo printJob = new PrintJobInfo();
+ printJob.setId(printJobId);
+ printJob.setAppId(appId);
+ printJob.setLabel(printJobName);
+ printJob.setAttributes(attributes);
+ printJob.setState(PrintJobInfo.STATE_CREATED);
+
+ // Spin the spooler to add the job and show the config UI.
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ mSpooler.createPrintJob(printJob, client, documentAdapter);
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+
+ return printJob;
+ }
+
+ public List<PrintJobInfo> getPrintJobInfos(int appId) {
+ return mSpooler.getPrintJobInfos(null, PrintJobInfo.STATE_ANY, appId);
+ }
+
+ public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
+ return mSpooler.getPrintJobInfo(printJobId, appId);
+ }
+
+ public void cancelPrintJob(PrintJobId printJobId, int appId) {
+ PrintJobInfo printJobInfo = mSpooler.getPrintJobInfo(printJobId, appId);
+ if (printJobInfo == null) {
+ return;
+ }
+ if (printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
+ ComponentName printServiceName = printJobInfo.getPrinterId().getServiceName();
+ RemotePrintService printService = null;
+ synchronized (mLock) {
+ printService = mActiveServices.get(printServiceName);
+ }
+ if (printService == null) {
+ return;
+ }
+ printService.onRequestCancelPrintJob(printJobInfo);
+ } else {
+ // If the print job is failed we do not need cooperation
+ // from the print service.
+ mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_CANCELED, null);
+ }
+ }
+
+ public void restartPrintJob(PrintJobId printJobId, int appId) {
+ PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, appId);
+ if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
+ return;
+ }
+ mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_QUEUED, null);
+ }
+
+ public List<PrintServiceInfo> getEnabledPrintServices() {
+ synchronized (mLock) {
+ List<PrintServiceInfo> enabledServices = null;
+ final int installedServiceCount = mInstalledServices.size();
+ for (int i = 0; i < installedServiceCount; i++) {
+ PrintServiceInfo installedService = mInstalledServices.get(i);
+ ComponentName componentName = new ComponentName(
+ installedService.getResolveInfo().serviceInfo.packageName,
+ installedService.getResolveInfo().serviceInfo.name);
+ if (mActiveServices.containsKey(componentName)) {
+ if (enabledServices == null) {
+ enabledServices = new ArrayList<PrintServiceInfo>();
+ }
+ enabledServices.add(installedService);
+ }
+ }
+ return enabledServices;
+ }
+ }
+
public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -246,6 +351,7 @@
}
}
+ @Override
public void onPrintersAdded(List<PrinterInfo> printers) {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -257,11 +363,11 @@
if (mPrinterDiscoverySession == null) {
return;
}
- // Request an updated.
mPrinterDiscoverySession.onPrintersAddedLocked(printers);
}
}
+ @Override
public void onPrintersRemoved(List<PrinterId> printerIds) {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -273,11 +379,29 @@
if (mPrinterDiscoverySession == null) {
return;
}
- // Request an updated.
mPrinterDiscoverySession.onPrintersRemovedLocked(printerIds);
}
}
+ @Override
+ public void onServiceDied(RemotePrintService service) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ // No services - nothing to do.
+ if (mActiveServices.isEmpty()) {
+ return;
+ }
+ // Fail all print jobs.
+ failActivePrintJobsForService(service.getComponentName());
+ service.onAllPrintJobsHandled();
+ // No session - nothing to do.
+ if (mPrinterDiscoverySession == null) {
+ return;
+ }
+ mPrinterDiscoverySession.onServiceDiedLocked(service);
+ }
+ }
+
public void updateIfNeededLocked() {
throwIfDestroyedLocked();
if (readConfigurationLocked()) {
@@ -285,18 +409,6 @@
}
}
- public RemotePrintSpooler getSpoolerLocked() {
- throwIfDestroyedLocked();
- return mSpooler;
- }
-
- public Map<ComponentName, RemotePrintService> getActiveServicesLocked() {
- synchronized(mLock) {
- throwIfDestroyedLocked();
- return mActiveServices;
- }
- }
-
public Set<ComponentName> getEnabledServices() {
synchronized(mLock) {
throwIfDestroyedLocked();
@@ -411,7 +523,6 @@
return false;
}
-
private boolean readEnabledPrintServicesLocked() {
Set<ComponentName> tempEnabledServiceNameSet = new HashSet<ComponentName>();
readPrintServicesFromSettingLocked(Settings.Secure.ENABLED_PRINT_SERVICES,
@@ -516,23 +627,71 @@
if (!mActiveServices.containsKey(serviceName)) {
RemotePrintService service = new RemotePrintService(
mContext, serviceName, mUserId, mSpooler, this);
- mActiveServices.put(serviceName, service);
- if (mPrinterDiscoverySession != null) {
- mPrinterDiscoverySession.onServiceAddedLocked(service);
- }
+ addServiceLocked(service);
}
} else {
RemotePrintService service = mActiveServices.remove(serviceName);
if (service != null) {
- service.destroy();
- if (mPrinterDiscoverySession != null) {
- mPrinterDiscoverySession.onServiceRemovedLocked(serviceName);
- }
+ removeServiceLocked(service);
}
}
}
}
+ private void addServiceLocked(RemotePrintService service) {
+ mActiveServices.put(service.getComponentName(), service);
+ if (mPrinterDiscoverySession != null) {
+ mPrinterDiscoverySession.onServiceAddedLocked(service);
+ }
+ }
+
+ private void removeServiceLocked(RemotePrintService service) {
+ // Fail all print jobs.
+ failActivePrintJobsForService(service.getComponentName());
+ // If discovery is in progress, tear down the service.
+ if (mPrinterDiscoverySession != null) {
+ mPrinterDiscoverySession.onServiceRemovedLocked(service);
+ } else {
+ // Otherwise, just destroy it.
+ service.destroy();
+ }
+ }
+
+ private void failActivePrintJobsForService(final ComponentName serviceName) {
+ // Makes sure all active print jobs are failed since the service
+ // just died. Do this off the main thread since we do to allow
+ // calls into the spooler on the main thread.
+ if (Looper.getMainLooper().isCurrentThread()) {
+ BackgroundThread.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ failActivePrintJobsForServiceInternal(serviceName);
+ }
+ });
+ } else {
+ failActivePrintJobsForServiceInternal(serviceName);
+ }
+ }
+
+ private void failActivePrintJobsForServiceInternal(ComponentName serviceName) {
+ List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(serviceName,
+ PrintJobInfo.STATE_ANY_ACTIVE, PrintManager.APP_ID_ANY);
+ if (printJobs == null) {
+ return;
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final int printJobCount = printJobs.size();
+ for (int i = 0; i < printJobCount; i++) {
+ PrintJobInfo printJob = printJobs.get(i);
+ mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
+ mContext.getString(R.string.reason_unknown));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
private void throwIfDestroyedLocked() {
if (mDestroyed) {
throw new IllegalStateException("Cannot interact with a destroyed instance.");
@@ -603,17 +762,18 @@
return;
}
- // If printer discovery is ongoing and the start request has a list
- // of printer to be checked, then we just request validating them.
- if (!mStartedPrinterDiscoveryTokens.isEmpty()
- && priorityList != null && !priorityList.isEmpty()) {
- validatePrinters(priorityList);
- return;
- }
+ final boolean discoveryStarted = !mStartedPrinterDiscoveryTokens.isEmpty();
// Remember we got a start request to match with an end.
mStartedPrinterDiscoveryTokens.add(observer.asBinder());
+ // If printer discovery is ongoing and the start request has a list
+ // of printer to be checked, then we just request validating them.
+ if (discoveryStarted && priorityList != null && !priorityList.isEmpty()) {
+ validatePrinters(priorityList);
+ return;
+ }
+
// The service are already performing discovery - nothing to do.
if (mStartedPrinterDiscoveryTokens.size() > 1) {
return;
@@ -822,32 +982,20 @@
}
}
- public void onServiceRemovedLocked(ComponentName serviceName) {
+ public void onServiceRemovedLocked(RemotePrintService service) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not updating removed service - session destroyed");
return;
}
- // No printers - nothing to do.
- if (mPrinters.isEmpty()) {
- return;
- }
- // Remove the printers for that service.
- List<PrinterId> removedPrinterIds = null;
- final int printerCount = mPrinters.size();
- for (int i = 0; i < printerCount; i++) {
- PrinterId printerId = mPrinters.keyAt(i);
- if (printerId.getServiceName().equals(serviceName)) {
- if (removedPrinterIds == null) {
- removedPrinterIds = new ArrayList<PrinterId>();
- }
- removedPrinterIds.add(printerId);
- }
- }
- if (!removedPrinterIds.isEmpty()) {
- mHandler.obtainMessage(
- SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
- removedPrinterIds).sendToTarget();
- }
+ // Remove the reported and tracked printers for that service.
+ ComponentName serviceName = service.getComponentName();
+ removePrintersForServiceLocked(serviceName);
+ service.destroy();
+ }
+
+ public void onServiceDiedLocked(RemotePrintService service) {
+ // Remove the reported by that service.
+ removePrintersForServiceLocked(service.getComponentName());
}
public void onServiceAddedLocked(RemotePrintService service) {
@@ -908,6 +1056,34 @@
}
}
+ private void removePrintersForServiceLocked(ComponentName serviceName) {
+ // No printers - nothing to do.
+ if (mPrinters.isEmpty()) {
+ return;
+ }
+ // Remove the printers for that service.
+ List<PrinterId> removedPrinterIds = null;
+ final int printerCount = mPrinters.size();
+ for (int i = 0; i < printerCount; i++) {
+ PrinterId printerId = mPrinters.keyAt(i);
+ if (printerId.getServiceName().equals(serviceName)) {
+ if (removedPrinterIds == null) {
+ removedPrinterIds = new ArrayList<PrinterId>();
+ }
+ removedPrinterIds.add(printerId);
+ }
+ }
+ if (removedPrinterIds != null) {
+ final int removedPrinterCount = removedPrinterIds.size();
+ for (int i = 0; i < removedPrinterCount; i++) {
+ mPrinters.remove(removedPrinterIds.get(i));
+ }
+ mHandler.obtainMessage(
+ SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
+ removedPrinterIds).sendToTarget();
+ }
+ }
+
private void handleDispatchPrintersAdded(List<PrinterInfo> addedPrinters) {
final int observerCount = mDiscoveryObservers.beginBroadcast();
for (int i = 0; i < observerCount; i++) {
@@ -980,19 +1156,7 @@
private void handlePrintersAdded(IPrinterDiscoveryObserver observer,
List<PrinterInfo> printers) {
try {
- final int printerCount = printers.size();
- if (printerCount <= MAX_ITEMS_PER_CALLBACK) {
- observer.onPrintersAdded(printers);
- } else {
- // Send the added printers in chunks avoiding the binder transaction limit.
- final int transactionCount = (printerCount / MAX_ITEMS_PER_CALLBACK) + 1;
- for (int i = 0; i < transactionCount; i++) {
- final int start = i * MAX_ITEMS_PER_CALLBACK;
- final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerCount);
- List<PrinterInfo> subPrinters = printers.subList(start, end);
- observer.onPrintersAdded(subPrinters);
- }
- }
+ observer.onPrintersAdded(new ParceledListSlice<PrinterInfo>(printers));
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error sending added printers", re);
}
@@ -1001,21 +1165,9 @@
private void handlePrintersRemoved(IPrinterDiscoveryObserver observer,
List<PrinterId> printerIds) {
try {
- final int printerCount = printerIds.size();
- if (printerCount <= MAX_ITEMS_PER_CALLBACK) {
- observer.onPrintersRemoved(printerIds);
- } else {
- // Send the added printers in chunks avoiding the binder transaction limit.
- final int transactionCount = (printerCount / MAX_ITEMS_PER_CALLBACK) + 1;
- for (int i = 0; i < transactionCount; i++) {
- final int start = i * MAX_ITEMS_PER_CALLBACK;
- final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerCount);
- List<PrinterId> subPrinterIds = printerIds.subList(start, end);
- observer.onPrintersRemoved(subPrinterIds);
- }
- }
+ observer.onPrintersRemoved(new ParceledListSlice<PrinterId>(printerIds));
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error sending added printers", re);
+ Log.e(LOG_TAG, "Error sending removed printers", re);
}
}
@@ -1026,14 +1178,17 @@
public static final int MSG_DISPATCH_PRINTERS_REMOVED = 4;
public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 5;
- public static final int MSG_START_PRINTER_DISCOVERY = 6;
- public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 7;
- public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 8;
- public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 9;
- public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 10;
- public static final int MSG_VALIDATE_PRINTERS = 11;
- public static final int MSG_START_PRINTER_STATE_TRACKING = 12;
- public static final int MSG_STOP_PRINTER_STATE_TRACKING = 13;
+ public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 6;
+ public static final int MSG_START_PRINTER_DISCOVERY = 7;
+ public static final int MSG_STOP_PRINTER_DISCOVERY = 8;
+ public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 9;
+ public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 10;
+ public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 11;
+ public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 12;
+ public static final int MSG_VALIDATE_PRINTERS = 13;
+ public static final int MSG_START_PRINTER_STATE_TRACKING = 14;
+ public static final int MSG_STOP_PRINTER_STATE_TRACKING = 15;
+ public static final int MSG_DESTROY_SERVICE = 16;
SessionHandler(Looper looper) {
super(looper, null, false);
@@ -1074,11 +1229,21 @@
service.createPrinterDiscoverySession();
} break;
+ case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: {
+ RemotePrintService service = (RemotePrintService) message.obj;
+ service.destroyPrinterDiscoverySession();
+ } break;
+
case MSG_START_PRINTER_DISCOVERY: {
RemotePrintService service = (RemotePrintService) message.obj;
service.startPrinterDiscovery(null);
} break;
+ case MSG_STOP_PRINTER_DISCOVERY: {
+ RemotePrintService service = (RemotePrintService) message.obj;
+ service.stopPrinterDiscovery();
+ } break;
+
case MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION: {
List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
handleDispatchCreatePrinterDiscoverySession(services);
@@ -1124,9 +1289,61 @@
PrinterId printerId = (PrinterId) args.arg2;
args.recycle();
handleStopPrinterStateTracking(service, printerId);
- }
+ } break;
+
+ case MSG_DESTROY_SERVICE: {
+ RemotePrintService service = (RemotePrintService) message.obj;
+ service.destroy();
+ } break;
}
}
}
}
-}
\ No newline at end of file
+
+ private final class CreatedPrintJobTracker {
+ private final ArrayMap<IBinder, List<PrintJobId>> mCreatedPrintJobs =
+ new ArrayMap<IBinder, List<PrintJobId>>();
+
+ public boolean onPrintJobCreatedLocked(final IBinder creator, PrintJobId printJobId) {
+ try {
+ creator.linkToDeath(new DeathRecipient() {
+ @Override
+ public void binderDied() {
+ creator.unlinkToDeath(this, 0);
+ UserManager userManager = (UserManager) mContext.getSystemService(
+ Context.USER_SERVICE);
+ // If the death is a result of the user being removed, then
+ // do nothing since the spooler data for this user will be
+ // wiped and we cannot bind to the spooler at this point.
+ if (userManager.getUserInfo(mUserId) == null) {
+ return;
+ }
+ List<PrintJobId> printJobIds = null;
+ synchronized (mLock) {
+ printJobIds = mCreatedPrintJobs.remove(creator);
+ if (printJobIds == null) {
+ return;
+ }
+ printJobIds = new ArrayList<PrintJobId>(printJobIds);
+ }
+ if (printJobIds != null) {
+ mSpooler.forgetPrintJobs(printJobIds);
+ }
+ }
+ }, 0);
+ } catch (RemoteException re) {
+ /* The process is already dead - we just failed. */
+ return false;
+ }
+ synchronized (mLock) {
+ List<PrintJobId> printJobIds = mCreatedPrintJobs.get(creator);
+ if (printJobIds == null) {
+ printJobIds = new ArrayList<PrintJobId>();
+ mCreatedPrintJobs.put(creator, printJobIds);
+ }
+ printJobIds.add(printJobId);
+ }
+ return true;
+ }
+ }
+}
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index c215f40..bbcd01a 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -170,7 +170,26 @@
}
/* Client commands are forwarded to state machine */
case WifiManager.CONNECT_NETWORK:
- case WifiManager.SAVE_NETWORK:
+ case WifiManager.SAVE_NETWORK: {
+ WifiConfiguration config = (WifiConfiguration) msg.obj;
+ int networkId = msg.arg1;
+ if (config != null && config.isValid()) {
+ if (DBG) Slog.d(TAG, "Connect with config" + config);
+ mWifiStateMachine.sendMessage(Message.obtain(msg));
+ } else if (config == null
+ && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
+ if (DBG) Slog.d(TAG, "Connect with networkId" + networkId);
+ mWifiStateMachine.sendMessage(Message.obtain(msg));
+ } else {
+ Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
+ if (msg.what == WifiManager.CONNECT_NETWORK) {
+ replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED);
+ } else {
+ replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED);
+ }
+ }
+ break;
+ }
case WifiManager.FORGET_NETWORK:
case WifiManager.START_WPS:
case WifiManager.CANCEL_WPS:
@@ -185,6 +204,17 @@
}
}
}
+
+ private void replyFailed(Message msg, int what) {
+ Message reply = msg.obtain();
+ reply.what = what;
+ reply.arg1 = WifiManager.INVALID_ARGS;
+ try {
+ msg.replyTo.send(reply);
+ } catch (RemoteException e) {
+ // There's not much we can do if reply can't be sent!
+ }
+ }
}
private ClientHandler mClientHandler;
@@ -318,6 +348,9 @@
enforceChangePermission();
if (workSource != null) {
enforceWorkSourcePermission();
+ // WifiManager currently doesn't use names, so need to clear names out of the
+ // supplied WorkSource to allow future WorkSource combining.
+ workSource.clearNames();
}
mWifiStateMachine.startScan(Binder.getCallingUid(), workSource);
}
@@ -325,11 +358,13 @@
private class BatchedScanRequest extends DeathRecipient {
BatchedScanSettings settings;
int uid;
+ int pid;
- BatchedScanRequest(BatchedScanSettings settings, IBinder binder, int uid) {
+ BatchedScanRequest(BatchedScanSettings settings, IBinder binder) {
super(0, null, binder, null);
this.settings = settings;
- this.uid = uid;
+ this.uid = getCallingUid();
+ this.pid = getCallingPid();
}
public void binderDied() {
stopBatchedScan(settings, mBinder);
@@ -337,6 +372,10 @@
public String toString() {
return "BatchedScanRequest{settings=" + settings + ", binder=" + mBinder + "}";
}
+
+ public boolean isSameApp() {
+ return (this.uid == getCallingUid() && this.pid == getCallingPid());
+ }
}
private final List<BatchedScanRequest> mBatchedScanners = new ArrayList<BatchedScanRequest>();
@@ -359,7 +398,7 @@
if (mBatchedScanSupported == false) return false;
requested = new BatchedScanSettings(requested);
if (requested.isInvalid()) return false;
- BatchedScanRequest r = new BatchedScanRequest(requested, binder, Binder.getCallingUid());
+ BatchedScanRequest r = new BatchedScanRequest(requested, binder);
synchronized(mBatchedScanners) {
mBatchedScanners.add(r);
resolveBatchedScannersLocked();
@@ -393,16 +432,18 @@
public void stopBatchedScan(BatchedScanSettings settings, IBinder binder) {
enforceChangePermission();
if (mBatchedScanSupported == false) return;
+ ArrayList<BatchedScanRequest> found = new ArrayList<BatchedScanRequest>();
synchronized(mBatchedScanners) {
- BatchedScanRequest found = null;
for (BatchedScanRequest r : mBatchedScanners) {
- if (r.mBinder.equals(binder) && r.settings.equals(settings)) {
- found = r;
- break;
+ if (r.isSameApp() && (settings == null || settings.equals(r.settings))) {
+ found.add(r);
+ if (settings != null) break;
}
}
- if (found != null) {
- mBatchedScanners.remove(found);
+ for (BatchedScanRequest r : found) {
+ mBatchedScanners.remove(r);
+ }
+ if (found.size() != 0) {
resolveBatchedScannersLocked();
}
}
@@ -547,7 +588,12 @@
*/
public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
enforceChangePermission();
- mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
+ // null wifiConfig is a meaningful input for CMD_SET_AP
+ if (wifiConfig == null || wifiConfig.isValid()) {
+ mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
+ } else {
+ Slog.e(TAG, "Invalid WifiConfiguration");
+ }
}
/**
@@ -580,7 +626,11 @@
enforceChangePermission();
if (wifiConfig == null)
return;
- mWifiStateMachine.setWifiApConfiguration(wifiConfig);
+ if (wifiConfig.isValid()) {
+ mWifiStateMachine.setWifiApConfiguration(wifiConfig);
+ } else {
+ Slog.e(TAG, "Invalid WifiConfiguration");
+ }
}
/**
@@ -638,10 +688,15 @@
*/
public int addOrUpdateNetwork(WifiConfiguration config) {
enforceChangePermission();
- if (mWifiStateMachineChannel != null) {
- return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
+ if (config.isValid()) {
+ if (mWifiStateMachineChannel != null) {
+ return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
+ } else {
+ Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
+ return -1;
+ }
} else {
- Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
+ Slog.e(TAG, "bad network configuration");
return -1;
}
}
diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java
index 737d854..5aa266d 100644
--- a/services/java/com/android/server/wm/BlackFrame.java
+++ b/services/java/com/android/server/wm/BlackFrame.java
@@ -22,6 +22,7 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.util.Slog;
+import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -36,7 +37,7 @@
final SurfaceControl surface;
BlackSurface(SurfaceSession session, int layer, int l, int t, int r, int b, int layerStack)
- throws SurfaceControl.OutOfResourcesException {
+ throws OutOfResourcesException {
left = l;
top = t;
this.layer = layer;
@@ -112,7 +113,7 @@
}
public BlackFrame(SurfaceSession session, Rect outer, Rect inner, int layer, int layerStack,
- boolean forceDefaultOrientation) throws SurfaceControl.OutOfResourcesException {
+ boolean forceDefaultOrientation) throws OutOfResourcesException {
boolean success = false;
mForceDefaultOrientation = forceDefaultOrientation;
diff --git a/services/java/com/android/server/wm/DisplayMagnifier.java b/services/java/com/android/server/wm/DisplayMagnifier.java
index 0f51028..382d7b4 100644
--- a/services/java/com/android/server/wm/DisplayMagnifier.java
+++ b/services/java/com/android/server/wm/DisplayMagnifier.java
@@ -496,7 +496,7 @@
mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
surfaceControl = new SurfaceControl(mWindowManagerService.mFxSession, SURFACE_TITLE,
mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
- } catch (SurfaceControl.OutOfResourcesException oore) {
+ } catch (OutOfResourcesException oore) {
/* ignore */
}
mSurfaceControl = surfaceControl;
@@ -629,7 +629,7 @@
}
} catch (IllegalArgumentException iae) {
/* ignore */
- } catch (OutOfResourcesException oore) {
+ } catch (Surface.OutOfResourcesException oore) {
/* ignore */
}
if (canvas == null) {
@@ -644,7 +644,7 @@
canvas.drawPath(path, mPaint);
mSurface.unlockCanvasAndPost(canvas);
-
+
if (mAlpha > 0) {
mSurfaceControl.show();
} else {
diff --git a/services/java/com/android/server/wm/FocusedStackFrame.java b/services/java/com/android/server/wm/FocusedStackFrame.java
index 9c18331..365b277 100644
--- a/services/java/com/android/server/wm/FocusedStackFrame.java
+++ b/services/java/com/android/server/wm/FocusedStackFrame.java
@@ -26,6 +26,7 @@
import android.graphics.Region;
import android.util.Slog;
import android.view.Display;
+import android.view.Surface.OutOfResourcesException;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -39,9 +40,9 @@
private final SurfaceControl mSurfaceControl;
private final Surface mSurface = new Surface();
- private Rect mLastBounds = new Rect();
- private Rect mBounds = new Rect();
- private Rect mTmpDrawRect = new Rect();
+ private final Rect mLastBounds = new Rect();
+ private final Rect mBounds = new Rect();
+ private final Rect mTmpDrawRect = new Rect();
public FocusedStackFrame(Display display, SurfaceSession session) {
SurfaceControl ctrl = null;
@@ -56,7 +57,7 @@
ctrl.setLayerStack(display.getLayerStack());
ctrl.setAlpha(ALPHA);
mSurface.copyFrom(ctrl);
- } catch (SurfaceControl.OutOfResourcesException e) {
+ } catch (OutOfResourcesException e) {
}
mSurfaceControl = ctrl;
}
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 9620612..2e13fe2 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -88,7 +88,7 @@
*/
@Override
public long notifyANR(InputApplicationHandle inputApplicationHandle,
- InputWindowHandle inputWindowHandle) {
+ InputWindowHandle inputWindowHandle, String reason) {
AppWindowToken appWindowToken = null;
WindowState windowState = null;
boolean aboveSystem = false;
@@ -105,7 +105,8 @@
if (windowState != null) {
Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
- + "sending to " + windowState.mAttrs.getTitle());
+ + "sending to " + windowState.mAttrs.getTitle()
+ + ". Reason: " + reason);
// Figure out whether this window is layered above system windows.
// We need to do this here to help the activity manager know how to
// layer its ANR dialog.
@@ -114,19 +115,21 @@
aboveSystem = windowState.mBaseLayer > systemAlertLayer;
} else if (appWindowToken != null) {
Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
- + "sending to application " + appWindowToken.stringName);
+ + "sending to application " + appWindowToken.stringName
+ + ". Reason: " + reason);
} else {
- Slog.i(WindowManagerService.TAG, "Input event dispatching timed out.");
+ Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
+ + ". Reason: " + reason);
}
- mService.saveANRStateLocked(appWindowToken, windowState);
+ mService.saveANRStateLocked(appWindowToken, windowState, reason);
}
if (appWindowToken != null && appWindowToken.appToken != null) {
try {
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
- boolean abort = appWindowToken.appToken.keyDispatchingTimedOut();
+ boolean abort = appWindowToken.appToken.keyDispatchingTimedOut(reason);
if (! abort) {
// The activity manager declined to abort dispatching.
// Wait a bit longer and timeout again later.
@@ -139,7 +142,7 @@
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
long timeout = ActivityManagerNative.getDefault().inputDispatchingTimedOut(
- windowState.mSession.mPid, aboveSystem);
+ windowState.mSession.mPid, aboveSystem, reason);
if (timeout >= 0) {
// The activity manager declined to abort dispatching.
// Wait a bit longer and timeout again later.
@@ -342,7 +345,7 @@
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
mService.mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen);
}
-
+
/* Provides an opportunity for the window manager policy to intercept early key
* processing as soon as the key has been read from the device. */
@Override
@@ -367,7 +370,7 @@
WindowState windowState = focus != null ? (WindowState) focus.windowState : null;
return mService.mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags);
}
-
+
/* Provides an opportunity for the window manager policy to process a key that
* the application did not handle. */
@Override
@@ -389,7 +392,7 @@
* Layer assignment is assumed to be complete by the time this is called.
*/
public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
- if (WindowManagerService.DEBUG_INPUT) {
+ if (WindowManagerService.DEBUG_FOCUS_LIGHT || WindowManagerService.DEBUG_INPUT) {
Slog.d(WindowManagerService.TAG, "Input focus has changed to " + newWindow);
}
@@ -409,7 +412,7 @@
}
}
}
-
+
public void setFocusedAppLw(AppWindowToken newApp) {
// Focused app has changed.
if (newApp == null) {
@@ -422,7 +425,7 @@
mService.mInputManager.setFocusedApplication(handle);
}
}
-
+
public void pauseDispatchingLw(WindowToken window) {
if (! window.paused) {
if (WindowManagerService.DEBUG_INPUT) {
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 7d90858..e630737 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -27,6 +27,7 @@
import android.util.Slog;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.Surface.OutOfResourcesException;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -262,7 +263,7 @@
mSurfaceControl.setAlpha(0);
mSurfaceControl.show();
sur.destroy();
- } catch (SurfaceControl.OutOfResourcesException e) {
+ } catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate freeze surface", e);
}
@@ -547,7 +548,7 @@
mCustomBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 3,
layerStack, false);
mCustomBlackFrame.setMatrix(mFrameInitialMatrix);
- } catch (SurfaceControl.OutOfResourcesException e) {
+ } catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
} finally {
SurfaceControl.closeTransaction();
@@ -587,7 +588,7 @@
mExitingBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 2,
layerStack, mForceDefaultOrientation);
mExitingBlackFrame.setMatrix(mFrameInitialMatrix);
- } catch (SurfaceControl.OutOfResourcesException e) {
+ } catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
} finally {
SurfaceControl.closeTransaction();
@@ -609,7 +610,7 @@
Rect inner = new Rect(0, 0, finalWidth, finalHeight);
mEnteringBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER,
layerStack, false);
- } catch (SurfaceControl.OutOfResourcesException e) {
+ } catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
} finally {
SurfaceControl.closeTransaction();
@@ -894,7 +895,7 @@
&& (mMoreStartEnter || mMoreStartExit || mMoreFinishEnter || mMoreFinishExit))
|| (USE_CUSTOM_BLACK_FRAME
&& (mMoreStartFrame || mMoreRotateFrame || mMoreFinishFrame))
- || mMoreRotateEnter || mMoreRotateExit
+ || mMoreRotateEnter || mMoreRotateExit
|| !mFinishAnimReady;
mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
diff --git a/services/java/com/android/server/wm/StrictModeFlash.java b/services/java/com/android/server/wm/StrictModeFlash.java
index 31628e3..fb5876b 100644
--- a/services/java/com/android/server/wm/StrictModeFlash.java
+++ b/services/java/com/android/server/wm/StrictModeFlash.java
@@ -23,6 +23,7 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.view.Display;
+import android.view.Surface.OutOfResourcesException;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -47,7 +48,7 @@
ctrl.setPosition(0, 0);
ctrl.show();
mSurface.copyFrom(ctrl);
- } catch (SurfaceControl.OutOfResourcesException e) {
+ } catch (OutOfResourcesException e) {
}
mSurfaceControl = ctrl;
mDrawNeeded = true;
diff --git a/services/java/com/android/server/wm/Watermark.java b/services/java/com/android/server/wm/Watermark.java
index fedd314..e226e3d 100644
--- a/services/java/com/android/server/wm/Watermark.java
+++ b/services/java/com/android/server/wm/Watermark.java
@@ -27,10 +27,10 @@
import android.util.Log;
import android.util.TypedValue;
import android.view.Display;
+import android.view.Surface.OutOfResourcesException;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
-import android.view.Surface.OutOfResourcesException;
/**
* Displays a watermark on top of the window manager's windows.
@@ -119,7 +119,7 @@
ctrl.setPosition(0, 0);
ctrl.show();
mSurface.copyFrom(ctrl);
- } catch (SurfaceControl.OutOfResourcesException e) {
+ } catch (OutOfResourcesException e) {
}
mSurfaceControl = ctrl;
}
@@ -144,11 +144,11 @@
try {
c = mSurface.lockCanvas(dirty);
} catch (IllegalArgumentException e) {
- } catch (OutOfResourcesException e) {
+ } catch (Surface.OutOfResourcesException e) {
}
if (c != null) {
c.drawColor(0, PorterDuff.Mode.CLEAR);
-
+
int deltaX = mDeltaX;
int deltaY = mDeltaY;
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 25b042c..ca87b4f 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -293,6 +293,8 @@
// We are showing on to of the current
// focus, so re-evaluate focus to make
// sure it is correct.
+ if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.v(TAG,
+ "updateWindowsLocked: setting mFocusMayChange true");
mService.mFocusMayChange = true;
}
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 34d8973..69ff449 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -116,6 +116,7 @@
import android.view.KeyEvent;
import android.view.MagnificationSpec;
import android.view.MotionEvent;
+import android.view.Surface.OutOfResourcesException;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -159,6 +160,7 @@
static final boolean DEBUG = false;
static final boolean DEBUG_ADD_REMOVE = false;
static final boolean DEBUG_FOCUS = false;
+ static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || true;
static final boolean DEBUG_ANIM = false;
static final boolean DEBUG_LAYOUT = false;
static final boolean DEBUG_RESIZE = false;
@@ -461,7 +463,7 @@
// This is held as long as we have the screen frozen, to give us time to
// perform a rotation animation when turning off shows the lock screen which
// changes the orientation.
- private PowerManager.WakeLock mScreenFrozenLock;
+ private final PowerManager.WakeLock mScreenFrozenLock;
final AppTransition mAppTransition;
boolean mStartingIconInTransition = false;
@@ -664,7 +666,7 @@
boolean mInTouchMode = true;
private ViewServer mViewServer;
- private ArrayList<WindowChangeListener> mWindowChangeListeners =
+ private final ArrayList<WindowChangeListener> mWindowChangeListeners =
new ArrayList<WindowChangeListener>();
private boolean mWindowsChanged = false;
@@ -920,8 +922,9 @@
//apptoken note that the window could be a floating window
//that was created later or a window at the top of the list of
//windows associated with this token.
- if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
- "Adding window " + win + " at " + (newIdx + 1) + " of " + N);
+ if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+ "not Base app: Adding window " + win + " at " + (newIdx + 1) + " of " +
+ N);
windows.add(newIdx + 1, win);
if (newIdx < 0) {
// No window from token found on win's display.
@@ -1041,8 +1044,8 @@
break;
}
}
- if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
- "Adding window " + win + " at " + i + " of " + N);
+ if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+ "Based on layer: Adding window " + win + " at " + i + " of " + N);
windows.add(i, win);
mWindowsChanged = true;
return tokenWindowsPos;
@@ -1060,8 +1063,8 @@
}
}
i++;
- if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
- "Adding window " + win + " at " + i + " of " + windows.size());
+ if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+ "Free window: Adding window " + win + " at " + i + " of " + windows.size());
windows.add(i, win);
mWindowsChanged = true;
}
@@ -1128,6 +1131,8 @@
}
private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) {
+ if (DEBUG_FOCUS_LIGHT) Slog.d(TAG, "addWindowToListInOrderLocked: win=" + win +
+ " Callers=" + Debug.getCallers(4));
if (win.mAttachedWindow == null) {
final WindowToken token = win.mToken;
int tokenWindowsPos = 0;
@@ -1183,16 +1188,15 @@
// same display. Or even when the current IME/target are not on the same screen as the next
// IME/target. For now only look for input windows on the main screen.
WindowList windows = getDefaultWindowListLocked();
- final int N = windows.size();
WindowState w = null;
- int i = N;
- while (i > 0) {
- i--;
- w = windows.get(i);
+ int i;
+ for (i = windows.size() - 1; i >= 0; --i) {
+ WindowState win = windows.get(i);
if (DEBUG_INPUT_METHOD && willMove) Slog.i(TAG, "Checking window @" + i
- + " " + w + " fl=0x" + Integer.toHexString(w.mAttrs.flags));
- if (canBeImeTarget(w)) {
+ + " " + win + " fl=0x" + Integer.toHexString(win.mAttrs.flags));
+ if (canBeImeTarget(win)) {
+ w = win;
//Slog.i(TAG, "Putting input method here!");
// Yet more tricksyness! If this window is a "starting"
@@ -2352,7 +2356,7 @@
public void removeWindowLocked(Session session, WindowState win) {
- if (localLOGV || DEBUG_FOCUS) Slog.v(
+ if (localLOGV || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && win==mCurrentFocus) Slog.v(
TAG, "Remove " + win + " client="
+ Integer.toHexString(System.identityHashCode(win.mClient.asBinder()))
+ ", surface=" + win.mWinAnimator.mSurfaceControl,
@@ -3770,7 +3774,7 @@
synchronized(mWindowMap) {
boolean changed = false;
if (token == null) {
- if (DEBUG_FOCUS) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
+ if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
changed = mFocusedApp != null;
mFocusedApp = null;
if (changed) {
@@ -3783,9 +3787,9 @@
return;
}
changed = mFocusedApp != newFocus;
+ if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Set focused app to: " + newFocus
+ + " old focus=" + mFocusedApp + " moveFocusNow=" + moveFocusNow);
mFocusedApp = newFocus;
- if (DEBUG_FOCUS) Slog.v(TAG, "Set focused app to: " + mFocusedApp
- + " moveFocusNow=" + moveFocusNow);
if (changed) {
mInputMonitor.setFocusedAppLw(newFocus);
}
@@ -4507,7 +4511,7 @@
}
unsetAppFreezingScreenLocked(wtoken, true, true);
if (mFocusedApp == wtoken) {
- if (DEBUG_FOCUS) Slog.v(TAG, "Removing focused app token:" + wtoken);
+ if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Removing focused app token:" + wtoken);
mFocusedApp = null;
updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
mInputMonitor.setFocusedAppLw(null);
@@ -6812,7 +6816,7 @@
} else {
Slog.w(TAG, "Drag already in progress");
}
- } catch (SurfaceControl.OutOfResourcesException e) {
+ } catch (OutOfResourcesException e) {
Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
if (mDragState != null) {
mDragState.reset();
@@ -7069,8 +7073,8 @@
return;
}
mLastFocus = newFocus;
- //Slog.i(TAG, "Focus moving from " + lastFocus
- // + " to " + newFocus);
+ if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Focus moving from " + lastFocus +
+ " to " + newFocus);
if (newFocus != null && lastFocus != null
&& !newFocus.isDisplayedLw()) {
//Slog.i(TAG, "Delaying loss of focus...");
@@ -7079,19 +7083,17 @@
}
}
- if (lastFocus != newFocus) {
- //System.out.println("Changing focus from " + lastFocus
- // + " to " + newFocus);
- if (newFocus != null) {
- //Slog.i(TAG, "Gaining focus: " + newFocus);
- newFocus.reportFocusChangedSerialized(true, mInTouchMode);
- notifyFocusChanged();
- }
+ //System.out.println("Changing focus from " + lastFocus
+ // + " to " + newFocus);
+ if (newFocus != null) {
+ if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Gaining focus: " + newFocus);
+ newFocus.reportFocusChangedSerialized(true, mInTouchMode);
+ notifyFocusChanged();
+ }
- if (lastFocus != null) {
- //Slog.i(TAG, "Losing focus: " + lastFocus);
- lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
- }
+ if (lastFocus != null) {
+ if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Losing focus: " + lastFocus);
+ lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
}
} break;
@@ -7105,7 +7107,8 @@
final int N = losers.size();
for (int i=0; i<N; i++) {
- //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
+ if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Losing delayed focus: " +
+ losers.get(i));
losers.get(i).reportFocusChangedSerialized(false, mInTouchMode);
}
} break;
@@ -8580,12 +8583,8 @@
mAppTransition.getStartingPoint(p);
appAnimator.thumbnailX = p.x;
appAnimator.thumbnailY = p.y;
- } catch (SurfaceControl.OutOfResourcesException e) {
- Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
- + " h=" + dirty.height(), e);
- appAnimator.clearThumbnail();
- } catch (Surface.OutOfResourcesException e) {
- Slog.e(TAG, "Can't allocate Canvas surface w=" + dirty.width()
+ } catch (OutOfResourcesException e) {
+ Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w=" + dirty.width()
+ " h=" + dirty.height(), e);
appAnimator.clearThumbnail();
}
@@ -9712,7 +9711,7 @@
newFocus = computeFocusedWindowLocked();
}
- if (localLOGV) Slog.v(
+ if (DEBUG_FOCUS_LIGHT || localLOGV) Slog.v(
TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
final WindowState oldFocus = mCurrentFocus;
mCurrentFocus = newFocus;
@@ -9819,10 +9818,9 @@
tokens = tasks.get(taskNdx).mAppTokens;
for ( ; tokenNdx >= 0; --tokenNdx) {
if (nextApp == mFocusedApp) {
- // Whoops, we are below the focused app... no focus
- // for you!
+ // Whoops, we are below the focused app... no focus for you!
if (localLOGV || DEBUG_FOCUS) Slog.v(
- TAG, "Reached focused app: " + mFocusedApp);
+ TAG, "findFocusedWindow: Reached focused app=" + mFocusedApp);
return null;
}
nextApp = tokens.get(tokenNdx);
@@ -9847,11 +9845,12 @@
// Dispatch to this window if it is wants key events.
if (win.canReceiveKeys()) {
- if (DEBUG_FOCUS) Slog.v(
- TAG, "Found focus @ " + i + " = " + win);
+ if (DEBUG_FOCUS_LIGHT) Slog.v(
+ TAG, "findFocusedWindow: Found new focus @ " + i + " = " + win);
return win;
}
}
+ if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "findFocusedWindow: No focusable windows.");
return null;
}
@@ -10278,14 +10277,13 @@
void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
ArrayList<WindowState> windows) {
- int j = 0;
final int numDisplays = mDisplayContents.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList();
for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
final WindowState w = windowList.get(winNdx);
if (windows == null || windows.contains(w)) {
- pw.print(" Window #"); pw.print(j++); pw.print(' ');
+ pw.print(" Window #"); pw.print(winNdx); pw.print(' ');
pw.print(w); pw.println(":");
w.dump(pw, " ", dumpAll || windows != null);
}
@@ -10541,8 +10539,10 @@
*
* @param appWindowToken The application that ANR'd, may be null.
* @param windowState The window that ANR'd, may be null.
+ * @param reason The reason for the ANR, may be null.
*/
- public void saveANRStateLocked(AppWindowToken appWindowToken, WindowState windowState) {
+ public void saveANRStateLocked(AppWindowToken appWindowToken, WindowState windowState,
+ String reason) {
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 1024);
pw.println(" ANR time: " + DateFormat.getInstance().format(new Date()));
@@ -10552,6 +10552,9 @@
if (windowState != null) {
pw.println(" Window at fault: " + windowState.mAttrs.getTitle());
}
+ if (reason != null) {
+ pw.println(" Reason: " + reason);
+ }
pw.println();
dumpWindowsNoHeaderLocked(pw, true, null);
pw.close();
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 21445d3..64b5a09 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -1142,6 +1142,8 @@
// we allow the display to be enabled now.
mService.enableScreenIfNeededLocked();
if (mService.mCurrentFocus == this) {
+ if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.i(TAG,
+ "WindowState.hideLw: setting mFocusMayChange true");
mService.mFocusMayChange = true;
}
}
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 73325cb..533f626 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -29,6 +29,7 @@
import android.view.Display;
import android.view.DisplayInfo;
import android.view.MagnificationSpec;
+import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.WindowManager;
@@ -339,6 +340,8 @@
mWin.mDisplayContent.layoutNeeded = true;
if (!mWin.mPolicyVisibility) {
if (mService.mCurrentFocus == mWin) {
+ if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.i(TAG,
+ "setAnimationLocked: setting mFocusMayChange true");
mService.mFocusMayChange = true;
}
// Window is no longer visible -- make sure if we were waiting
@@ -480,7 +483,7 @@
private final Rect mWindowCrop = new Rect();
private boolean mShown = false;
private int mLayerStack;
- private String mName;
+ private final String mName;
public SurfaceTrace(SurfaceSession s,
String name, int w, int h, int format, int flags)
@@ -694,7 +697,7 @@
+ attrs.format + " flags=0x"
+ Integer.toHexString(flags)
+ " / " + this);
- } catch (SurfaceControl.OutOfResourcesException e) {
+ } catch (OutOfResourcesException e) {
mWin.mHasSurface = false;
Slog.w(TAG, "OutOfResourcesException creating surface");
mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 93d8e07..98e9b30 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -4,6 +4,7 @@
LOCAL_SRC_FILES:= \
com_android_server_AlarmManagerService.cpp \
com_android_server_AssetAtlasService.cpp \
+ com_android_server_ConsumerIrService.cpp \
com_android_server_input_InputApplicationHandle.cpp \
com_android_server_input_InputManagerService.cpp \
com_android_server_input_InputWindowHandle.cpp \
diff --git a/services/jni/com_android_server_AssetAtlasService.cpp b/services/jni/com_android_server_AssetAtlasService.cpp
index 62e950f..885d21e 100644
--- a/services/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/jni/com_android_server_AssetAtlasService.cpp
@@ -20,6 +20,7 @@
#include "JNIHelp.h"
#include <android_view_GraphicBuffer.h>
+#include <cutils/log.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
diff --git a/services/jni/com_android_server_ConsumerIrService.cpp b/services/jni/com_android_server_ConsumerIrService.cpp
new file mode 100644
index 0000000..004c0aa
--- /dev/null
+++ b/services/jni/com_android_server_ConsumerIrService.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ConsumerIrService"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <stdlib.h>
+#include <utils/misc.h>
+#include <utils/Log.h>
+#include <hardware/hardware.h>
+#include <hardware/consumerir.h>
+#include <ScopedPrimitiveArray.h>
+
+namespace android {
+
+static jint halOpen(JNIEnv *env, jobject obj) {
+ hw_module_t const* module;
+ consumerir_device_t *dev;
+ int err;
+
+ err = hw_get_module(CONSUMERIR_HARDWARE_MODULE_ID, &module);
+ if (err != 0) {
+ ALOGE("Can't open consumer IR HW Module, error: %d", err);
+ return 0;
+ }
+
+ err = module->methods->open(module, CONSUMERIR_TRANSMITTER,
+ (hw_device_t **) &dev);
+ if (err < 0) {
+ ALOGE("Can't open consumer IR transmitter, error: %d", err);
+ return 0;
+ }
+
+ return reinterpret_cast<jint>(dev);
+}
+
+static jint halTransmit(JNIEnv *env, jobject obj, jint halObject,
+ jint carrierFrequency, jintArray pattern) {
+ int ret;
+
+ consumerir_device_t *dev = reinterpret_cast<consumerir_device_t*>(halObject);
+ ScopedIntArrayRO cPattern(env, pattern);
+ if (cPattern.get() == NULL) {
+ return -EINVAL;
+ }
+ jsize patternLength = cPattern.size();
+
+ ret = dev->transmit(dev, carrierFrequency, cPattern.get(), patternLength);
+
+ return reinterpret_cast<jint>(ret);
+}
+
+static jintArray halGetCarrierFrequencies(JNIEnv *env, jobject obj,
+ jint halObject) {
+ consumerir_device_t *dev = (consumerir_device_t *) halObject;
+ consumerir_freq_range_t *ranges;
+ int len;
+
+ len = dev->get_num_carrier_freqs(dev);
+ if (len <= 0)
+ return NULL;
+
+ ranges = new consumerir_freq_range_t[len];
+
+ len = dev->get_carrier_freqs(dev, len, ranges);
+ if (len <= 0) {
+ delete[] ranges;
+ return NULL;
+ }
+
+ int i;
+ ScopedIntArrayRW freqsOut(env, env->NewIntArray(len*2));
+ jint *arr = freqsOut.get();
+ if (arr == NULL) {
+ delete[] ranges;
+ return NULL;
+ }
+ for (i = 0; i < len; i++) {
+ arr[i*2] = ranges[i].min;
+ arr[i*2+1] = ranges[i].max;
+ }
+
+ delete[] ranges;
+ return freqsOut.getJavaArray();
+}
+
+static JNINativeMethod method_table[] = {
+ { "halOpen", "()I", (void *)halOpen },
+ { "halTransmit", "(II[I)I", (void *)halTransmit },
+ { "halGetCarrierFrequencies", "(I)[I", (void *)halGetCarrierFrequencies},
+};
+
+int register_android_server_ConsumerIrService(JNIEnv *env) {
+ return jniRegisterNativeMethods(env, "com/android/server/ConsumerIrService",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/jni/com_android_server_UsbDeviceManager.cpp b/services/jni/com_android_server_UsbDeviceManager.cpp
index 0014db5..3551733 100644
--- a/services/jni/com_android_server_UsbDeviceManager.cpp
+++ b/services/jni/com_android_server_UsbDeviceManager.cpp
@@ -20,6 +20,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include <stdio.h>
#include <asm/byteorder.h>
diff --git a/services/jni/com_android_server_UsbHostManager.cpp b/services/jni/com_android_server_UsbHostManager.cpp
index d0a6cdf..639790b7 100644
--- a/services/jni/com_android_server_UsbHostManager.cpp
+++ b/services/jni/com_android_server_UsbHostManager.cpp
@@ -20,6 +20,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include "utils/Vector.h"
#include <usbhost/usbhost.h>
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp
index 09e5be4..4ab2086 100644
--- a/services/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/jni/com_android_server_input_InputManagerService.cpp
@@ -29,6 +29,7 @@
#include "jni.h"
#include <limits.h>
#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
#include <utils/Log.h>
#include <utils/Looper.h>
@@ -191,7 +192,8 @@
uint32_t policyFlags);
virtual void notifyConfigurationChanged(nsecs_t when);
virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<InputWindowHandle>& inputWindowHandle);
+ const sp<InputWindowHandle>& inputWindowHandle,
+ const String8& reason);
virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle);
virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
@@ -553,7 +555,7 @@
}
nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<InputWindowHandle>& inputWindowHandle) {
+ const sp<InputWindowHandle>& inputWindowHandle, const String8& reason) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyANR");
#endif
@@ -564,15 +566,18 @@
getInputApplicationHandleObjLocalRef(env, inputApplicationHandle);
jobject inputWindowHandleObj =
getInputWindowHandleObjLocalRef(env, inputWindowHandle);
+ jstring reasonObj = env->NewStringUTF(reason.string());
jlong newTimeout = env->CallLongMethod(mServiceObj,
- gServiceClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj);
+ gServiceClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj,
+ reasonObj);
if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
newTimeout = 0; // abort dispatch
} else {
assert(newTimeout >= 0);
}
+ env->DeleteLocalRef(reasonObj);
env->DeleteLocalRef(inputWindowHandleObj);
env->DeleteLocalRef(inputApplicationHandleObj);
return newTimeout;
@@ -1379,7 +1384,7 @@
GET_METHOD_ID(gServiceClassInfo.notifyANR, clazz,
"notifyANR",
- "(Lcom/android/server/input/InputApplicationHandle;Lcom/android/server/input/InputWindowHandle;)J");
+ "(Lcom/android/server/input/InputApplicationHandle;Lcom/android/server/input/InputWindowHandle;Ljava/lang/String;)J");
GET_METHOD_ID(gServiceClassInfo.filterInputEvent, clazz,
"filterInputEvent", "(Landroid/view/InputEvent;I)Z");
diff --git a/services/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/jni/com_android_server_location_FlpHardwareProvider.cpp
index b403ee6..ac269eb 100644
--- a/services/jni/com_android_server_location_FlpHardwareProvider.cpp
+++ b/services/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -23,6 +23,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include "hardware/fused_location.h"
#include "hardware_legacy/power.h"
@@ -318,7 +319,7 @@
jmethodID getNotificationResponsiveness = env->GetMethodID(
geofenceRequestClass,
"getNotificationResponsiveness",
- "()D");
+ "()I");
options->notification_responsivenes_ms = env->CallIntMethod(
geofenceRequestObject,
getNotificationResponsiveness);
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index 98de12a..aec254b 100644
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -26,6 +26,7 @@
#include "utils/Log.h"
#include "utils/misc.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include <string.h>
#include <pthread.h>
diff --git a/services/jni/com_android_server_power_PowerManagerService.cpp b/services/jni/com_android_server_power_PowerManagerService.cpp
index 88b13b5..151e134 100644
--- a/services/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/jni/com_android_server_power_PowerManagerService.cpp
@@ -26,6 +26,7 @@
#include <limits.h>
#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
#include <utils/Timers.h>
#include <utils/misc.h>
#include <utils/String8.h>
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index 5427277..efc34a2 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -21,6 +21,7 @@
namespace android {
int register_android_server_AlarmManagerService(JNIEnv* env);
+int register_android_server_ConsumerIrService(JNIEnv *env);
int register_android_server_InputApplicationHandle(JNIEnv* env);
int register_android_server_InputWindowHandle(JNIEnv* env);
int register_android_server_InputManager(JNIEnv* env);
@@ -65,6 +66,8 @@
register_android_server_location_FlpHardwareProvider(env);
register_android_server_connectivity_Vpn(env);
register_android_server_AssetAtlasService(env);
+ register_android_server_ConsumerIrService(env);
+
return JNI_VERSION_1_4;
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index a9909b2..a1af8cb 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -40,7 +40,6 @@
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
import static org.easymock.EasyMock.anyLong;
-import static org.easymock.EasyMock.aryEq;
import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.eq;
@@ -74,13 +73,13 @@
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
+import libcore.io.IoUtils;
+
import org.easymock.Capture;
import org.easymock.EasyMock;
import java.io.File;
-import libcore.io.IoUtils;
-
/**
* Tests for {@link NetworkStatsService}.
*/
@@ -919,8 +918,7 @@
expect(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL))).andReturn(detail).atLeastOnce();
// also include tethering details, since they are folded into UID
- expect(mConnManager.getTetheredIfacePairs()).andReturn(tetherIfacePairs).atLeastOnce();
- expect(mNetManager.getNetworkStatsTethering(aryEq(tetherIfacePairs)))
+ expect(mNetManager.getNetworkStatsTethering())
.andReturn(tetherStats).atLeastOnce();
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 40201ad..7d8b64f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -309,7 +309,7 @@
*/
public List<NeighboringCellInfo> getNeighboringCellInfo() {
try {
- return getITelephony().getNeighboringCellInfo(mContext.getBasePackageName());
+ return getITelephony().getNeighboringCellInfo(mContext.getOpPackageName());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 252a14e..0d9cd18 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -112,6 +112,12 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public String getOpPackageName() {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public ApplicationInfo getApplicationInfo() {
throw new UnsupportedOperationException();
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 4683534..5f944f6 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -46,6 +46,7 @@
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Binder;
+import android.os.RemoteException;
import android.os.UserHandle;
import java.util.List;
@@ -543,6 +544,12 @@
throw new UnsupportedOperationException();
}
+ /** @hide - hidden in superclass */
+ @Override
+ public ComponentName getHomeActivities(List<ResolveInfo> outActivities) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public String[] getSystemSharedLibraryNames() {
throw new UnsupportedOperationException();
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java b/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java
index 482dc05..f687da3 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java
@@ -76,10 +76,10 @@
final TransitionSet myTransition = new TransitionSet();
myTransition.addTransition(new Fade(Fade.IN)).
- addTransition(new Rotate().addTargetId(R.id.contact_arrow)).
+ addTransition(new Rotate().addTarget(R.id.contact_arrow)).
addTransition(new ChangeBounds()).
addTransition(new Fade(Fade.OUT)).
- addTransition(new Crossfade().addTargetId(R.id.contact_picture));
+ addTransition(new Crossfade().addTarget(R.id.contact_picture));
final ToggleScene toggleScene = new ToggleScene(container, myTransition);
contactItem.setOnClickListener(new View.OnClickListener() {
@Override
diff --git a/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java b/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java
index eb799ec..5bb0e77 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java
@@ -47,8 +47,8 @@
Crossfade crossfade = new Crossfade();
crossfade.setFadeBehavior(Crossfade.FADE_BEHAVIOR_CROSSFADE);
crossfade.setResizeBehavior(Crossfade.RESIZE_BEHAVIOR_NONE);
- crossfade.addTargetId(R.id.textview).addTargetId(R.id.textview1).
- addTargetId(R.id.textview2);
+ crossfade.addTarget(R.id.textview).addTarget(R.id.textview1).
+ addTarget(R.id.textview2);
mTransitionManager = new TransitionManager();
TransitionSet moveCrossFade = new TransitionSet();
moveCrossFade.addTransition(crossfade).addTransition(new ChangeBounds());
diff --git a/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java
index 09b495f..1f278b9 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java
@@ -48,7 +48,7 @@
mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
Crossfade mCrossfade = new Crossfade();
- mCrossfade.addTargetId(R.id.contact_picture);
+ mCrossfade.addTarget(R.id.contact_picture);
TransitionSet group = new TransitionSet();
group.setDuration(1500);
diff --git a/tests/TransitionTests/src/com/android/transitiontests/CrossfadeMultiple.java b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeMultiple.java
index c1183987..d784f75 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/CrossfadeMultiple.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeMultiple.java
@@ -57,7 +57,7 @@
mTextView = (TextView) findViewById(R.id.textview);
mCrossfade = new Crossfade();
- mCrossfade.addTargetId(R.id.button).addTargetId(R.id.textview).addTargetId(R.id.imageview);
+ mCrossfade.addTarget(R.id.button).addTarget(R.id.textview).addTarget(R.id.imageview);
mCrossfadeGroup = new TransitionSet();
mCrossfadeGroup.setDuration(300);
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo1.java b/tests/TransitionTests/src/com/android/transitiontests/Demo1.java
index 5c0cd45..5b5eb15 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/Demo1.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo1.java
@@ -70,9 +70,9 @@
if (mFirstTime) {
mFirstTime = false;
TransitionSet transition = new TransitionSet();
- transition.addTransition(new Fade().addTargetId(R.id.resultsText).
- addTargetId(R.id.resultsList)).
- addTransition(new ChangeBounds().addTargetId(R.id.searchContainer));
+ transition.addTransition(new Fade().addTarget(R.id.resultsText).
+ addTarget(R.id.resultsList)).
+ addTransition(new ChangeBounds().addTarget(R.id.searchContainer));
mTransitionManager = new TransitionManager();
mTransitionManager.setTransition(mSearchScreen, transition);
mTransitionManager.setTransition(mResultsScreen, transition);
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo2.java b/tests/TransitionTests/src/com/android/transitiontests/Demo2.java
index 334b777..0f3257b 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/Demo2.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo2.java
@@ -57,10 +57,10 @@
}
TransitionSet transition = new TransitionSet();
- transition.addTransition(new Fade().addTargetId(R.id.resultsText).
- addTargetId(R.id.resultsList)).
- addTransition(new ChangeBounds().addTargetId(R.id.searchContainer)).
- addTransition(new Recolor().addTargetId(R.id.container));
+ transition.addTransition(new Fade().addTarget(R.id.resultsText).
+ addTarget(R.id.resultsList)).
+ addTransition(new ChangeBounds().addTarget(R.id.searchContainer)).
+ addTransition(new Recolor().addTarget(R.id.container));
mTransitionManager = new TransitionManager();
mTransitionManager.setTransition(mSearchScreen, transition);
mTransitionManager.setTransition(mResultsScreen, transition);
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo4.java b/tests/TransitionTests/src/com/android/transitiontests/Demo4.java
index d1c3358..3aadbb0 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/Demo4.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo4.java
@@ -46,17 +46,17 @@
TransitionSet transitionToResults = new TransitionSet();
Fade fade = new Fade();
- fade.addTargetId(R.id.resultsText).addTargetId(R.id.resultsList);
+ fade.addTarget(R.id.resultsText).addTarget(R.id.resultsList);
fade.setStartDelay(300);
fade.setDuration(1000);
transitionToResults.addTransition(fade).
- addTransition(new ChangeBounds().addTargetId(R.id.searchContainer)).
- addTransition(new Recolor().addTargetId(R.id.container));
+ addTransition(new ChangeBounds().addTarget(R.id.searchContainer)).
+ addTransition(new Recolor().addTarget(R.id.container));
TransitionSet transitionToSearch = new TransitionSet();
transitionToSearch.addTransition(fade).
- addTransition(new ChangeBounds().addTargetId(R.id.searchContainer)).
- addTransition(new Recolor().addTargetId(R.id.container));
+ addTransition(new ChangeBounds().addTarget(R.id.searchContainer)).
+ addTransition(new Recolor().addTarget(R.id.container));
mTransitionManager = new TransitionManager();
mTransitionManager.setTransition(mSearchScreen, transitionToSearch);
diff --git a/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java b/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java
index 000ea9b..29fb868 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java
@@ -34,8 +34,8 @@
Scene mCurrentScene;
static {
- sFade.addTargetId(R.id.removingButton).addTargetId(R.id.invisibleButton).
- addTargetId(R.id.goneButton);
+ sFade.addTarget(R.id.removingButton).addTarget(R.id.invisibleButton).
+ addTarget(R.id.goneButton);
}
@Override
diff --git a/tests/TransitionTests/src/com/android/transitiontests/InterruptionTest.java b/tests/TransitionTests/src/com/android/transitiontests/InterruptionTest.java
index 70257bb..c26e93f 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/InterruptionTest.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/InterruptionTest.java
@@ -53,9 +53,9 @@
mScene4RB = (RadioButton) findViewById(R.id.scene4RB);
ChangeBounds changeBounds1 = new ChangeBounds();
- changeBounds1.addTargetId(R.id.button);
+ changeBounds1.addTarget(R.id.button);
ChangeBounds changeBounds2 = new ChangeBounds();
- changeBounds2.addTargetId(R.id.button1);
+ changeBounds2.addTarget(R.id.button1);
mSequencedMove.addTransition(changeBounds1).addTransition(changeBounds2);
mSequencedMove.setDuration(1000);
diff --git a/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java b/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java
index 34ec6cc..92bbb85 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java
@@ -54,9 +54,9 @@
// Custom transitions in/out of NewUser screen - slide in the 2nd password UI
TransitionSet slider = new TransitionSet();
- slider.addTransition(new Slide().addTargetId(R.id.retype).addTargetId(R.id.retypeEdit));
- slider.addTransition(new Recolor().addTargetId(R.id.password).
- addTargetId(R.id.passwordEdit));
+ slider.addTransition(new Slide().addTarget(R.id.retype).addTarget(R.id.retypeEdit));
+ slider.addTransition(new Recolor().addTarget(R.id.password).
+ addTarget(R.id.passwordEdit));
slider.addTransition(new Fade());
mTransitionManager.setTransition(mLoginScene, mNewUserScene, slider);
mTransitionManager.setTransition(mPasswordScene, mNewUserScene, slider);
@@ -64,8 +64,8 @@
mTransitionManager.setTransition(mNewUserScene, mPasswordScene, slider);
// Custom transitions with recoloring password field
- Transition colorizer = new Recolor().addTargetId(R.id.password).
- addTargetId(R.id.passwordEdit);
+ Transition colorizer = new Recolor().addTarget(R.id.password).
+ addTarget(R.id.passwordEdit);
mTransitionManager.setTransition(mLoginScene, mPasswordScene, colorizer);
mTransitionManager.setTransition(mPasswordScene, mLoginScene, colorizer);
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java
index c6011f2..ecf5ef3 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java
@@ -47,17 +47,17 @@
TransitionSet transitionToResults = new TransitionSet();
Fade fade = new Fade();
- fade.addTargetId(R.id.resultsText).addTargetId(R.id.resultsList);
+ fade.addTarget(R.id.resultsText).addTarget(R.id.resultsList);
fade.setStartDelay(300);
transitionToResults.addTransition(fade);
- transitionToResults.addTransition(new ChangeBounds().addTargetId(R.id.searchContainer));
- transitionToResults.addTransition(new Recolor().addTargetId(R.id.container));
+ transitionToResults.addTransition(new ChangeBounds().addTarget(R.id.searchContainer));
+ transitionToResults.addTransition(new Recolor().addTarget(R.id.container));
TransitionSet transitionToSearch = new TransitionSet();
- transitionToSearch.addTransition(new Fade().addTargetId(R.id.resultsText).
- addTargetId(R.id.resultsList));
- transitionToSearch.addTransition(new ChangeBounds().addTargetId(R.id.searchContainer));
- transitionToSearch.addTransition(new Recolor().addTargetId(R.id.container));
+ transitionToSearch.addTransition(new Fade().addTarget(R.id.resultsText).
+ addTarget(R.id.resultsList));
+ transitionToSearch.addTransition(new ChangeBounds().addTarget(R.id.searchContainer));
+ transitionToSearch.addTransition(new Recolor().addTarget(R.id.container));
mTransitionManager = new TransitionManager();
mTransitionManager.setTransition(mSearchScreen, transitionToSearch);
mTransitionManager.setTransition(mResultsScreen, transitionToResults);
diff --git a/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java b/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java
index ab1dc26..c550e92 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java
@@ -51,9 +51,9 @@
mScene1 = Scene.getSceneForLayout(mSceneRoot, R.layout.fading_test, this);
mScene2 = Scene.getSceneForLayout(mSceneRoot, R.layout.fading_test_scene_2, this);
- Transition fade1 = new Fade().addTargetId(R.id.removingButton);
- Transition fade2 = new Fade().addTargetId(R.id.invisibleButton);
- Transition fade3 = new Fade().addTargetId(R.id.goneButton);
+ Transition fade1 = new Fade().addTarget(R.id.removingButton);
+ Transition fade2 = new Fade().addTarget(R.id.invisibleButton);
+ Transition fade3 = new Fade().addTarget(R.id.goneButton);
TransitionSet fader = new TransitionSet().
setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
fader.addTransition(fade1).addTransition(fade2).addTransition(fade3).
diff --git a/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java b/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java
index 52c21c9..92b169e 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java
@@ -52,14 +52,14 @@
TransitionSet fader = new TransitionSet().
setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
- fader.addTransition(new Fade().addTargetId(R.id.removingButton));
- fader.addTransition(new ChangeBounds().addTargetId(R.id.sceneSwitchButton));
+ fader.addTransition(new Fade().addTarget(R.id.removingButton));
+ fader.addTransition(new ChangeBounds().addTarget(R.id.sceneSwitchButton));
sequencedFade = fader;
sequencedFadeReverse = new TransitionSet().
setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
- sequencedFadeReverse.addTransition(new ChangeBounds().addTargetId(R.id.sceneSwitchButton));
- sequencedFadeReverse.addTransition(new Fade().addTargetId(R.id.removingButton));
+ sequencedFadeReverse.addTransition(new ChangeBounds().addTarget(R.id.sceneSwitchButton));
+ sequencedFadeReverse.addTransition(new Fade().addTarget(R.id.removingButton));
mCurrentScene = mScene1;
}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java b/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java
index 05af044..9b246ad 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java
@@ -67,8 +67,8 @@
container.addView(mTextureView);
final TransitionSet transition = new TransitionSet();
- transition.addTransition(new ChangeBounds()).addTransition(new Crossfade().addTargetId(0).
- addTargetId(1).addTargetId(2));
+ transition.addTransition(new ChangeBounds()).addTransition(new Crossfade().addTarget(0).
+ addTarget(1).addTarget(2));
toggleButton.setOnClickListener(new View.OnClickListener() {
@Override
diff --git a/tools/layoutlib/bridge/src/android/webkit/WebView.java b/tools/layoutlib/bridge/src/android/webkit/WebView.java
index 3b66188..202f204 100644
--- a/tools/layoutlib/bridge/src/android/webkit/WebView.java
+++ b/tools/layoutlib/bridge/src/android/webkit/WebView.java
@@ -99,14 +99,6 @@
public static void disablePlatformNotifications() {
}
- public WebBackForwardList saveState(Bundle outState) {
- return null;
- }
-
- public WebBackForwardList restoreState(Bundle inState) {
- return null;
- }
-
public void loadUrl(String url) {
}
@@ -213,10 +205,6 @@
public void clearSslPreferences() {
}
- public WebBackForwardList copyBackForwardList() {
- return null;
- }
-
public static String findAddress(String addr) {
return null;
}
@@ -236,10 +224,6 @@
public void addJavascriptInterface(Object obj, String interfaceName) {
}
- public WebSettings getSettings() {
- return null;
- }
-
public View getZoomControls() {
return null;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index a1f2697..b9294ab 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -1090,6 +1090,12 @@
}
@Override
+ public String getOpPackageName() {
+ // pass
+ return null;
+ }
+
+ @Override
public ApplicationInfo getApplicationInfo() {
return mApplicationInfo;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
similarity index 62%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
index e0414fe..6c998af 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 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.
@@ -16,7 +16,6 @@
package com.android.layoutlib.bridge.impl.binding;
-import com.android.ide.common.rendering.api.AdapterBinding;
import com.android.ide.common.rendering.api.DataBindingItem;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.LayoutLog;
@@ -27,7 +26,6 @@
import com.android.layoutlib.bridge.impl.RenderAction;
import com.android.util.Pair;
-import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
@@ -35,124 +33,27 @@
import android.widget.ImageView;
import android.widget.TextView;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
/**
- * Base adapter to do fake data binding in {@link AdapterView} objects.
+ * A Helper class to do fake data binding in {@link AdapterView} objects.
*/
-public class BaseAdapter {
+@SuppressWarnings("deprecation")
+public class AdapterHelper {
- /**
- * This is the items provided by the adapter. They are dynamically generated.
- */
- protected final static class AdapterItem {
- private final DataBindingItem mItem;
- private final int mType;
- private final int mFullPosition;
- private final int mPositionPerType;
- private List<AdapterItem> mChildren;
-
- protected AdapterItem(DataBindingItem item, int type, int fullPosition,
- int positionPerType) {
- mItem = item;
- mType = type;
- mFullPosition = fullPosition;
- mPositionPerType = positionPerType;
- }
-
- void addChild(AdapterItem child) {
- if (mChildren == null) {
- mChildren = new ArrayList<AdapterItem>();
- }
-
- mChildren.add(child);
- }
-
- List<AdapterItem> getChildren() {
- if (mChildren != null) {
- return mChildren;
- }
-
- return Collections.emptyList();
- }
-
- int getType() {
- return mType;
- }
-
- int getFullPosition() {
- return mFullPosition;
- }
-
- int getPositionPerType() {
- return mPositionPerType;
- }
-
- DataBindingItem getDataBindingItem() {
- return mItem;
- }
- }
-
- private final AdapterBinding mBinding;
- private final IProjectCallback mCallback;
- private final ResourceReference mAdapterRef;
- private boolean mSkipCallbackParser = false;
-
- protected final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
-
- protected BaseAdapter(ResourceReference adapterRef, AdapterBinding binding,
- IProjectCallback callback) {
- mAdapterRef = adapterRef;
- mBinding = binding;
- mCallback = callback;
- }
-
- // ------- Some Adapter method used by all children classes.
-
- public boolean areAllItemsEnabled() {
- return true;
- }
-
- public boolean hasStableIds() {
- return true;
- }
-
- public boolean isEmpty() {
- return mItems.size() == 0;
- }
-
- public void registerDataSetObserver(DataSetObserver observer) {
- // pass
- }
-
- public void unregisterDataSetObserver(DataSetObserver observer) {
- // pass
- }
-
- // -------
-
-
- protected AdapterBinding getBinding() {
- return mBinding;
- }
-
- protected View getView(AdapterItem item, AdapterItem parentItem, View convertView,
- ViewGroup parent) {
+ static Pair<View, Boolean> getView(AdapterItem item, AdapterItem parentItem, ViewGroup parent,
+ IProjectCallback callback, ResourceReference adapterRef, boolean skipCallbackParser) {
// we don't care about recycling here because we never scroll.
DataBindingItem dataBindingItem = item.getDataBindingItem();
BridgeContext context = RenderAction.getCurrentContext();
Pair<View, Boolean> pair = context.inflateView(dataBindingItem.getViewReference(),
- parent, false /*attachToRoot*/, mSkipCallbackParser);
+ parent, false /*attachToRoot*/, skipCallbackParser);
View view = pair.getFirst();
- mSkipCallbackParser |= pair.getSecond();
+ skipCallbackParser |= pair.getSecond();
if (view != null) {
- fillView(context, view, item, parentItem);
+ fillView(context, view, item, parentItem, callback, adapterRef);
} else {
// create a text view to display an error.
TextView tv = new TextView(context);
@@ -160,16 +61,16 @@
view = tv;
}
- return view;
+ return Pair.of(view, skipCallbackParser);
}
- private void fillView(BridgeContext context, View view, AdapterItem item,
- AdapterItem parentItem) {
+ private static void fillView(BridgeContext context, View view, AdapterItem item,
+ AdapterItem parentItem, IProjectCallback callback, ResourceReference adapterRef) {
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
final int count = group.getChildCount();
for (int i = 0 ; i < count ; i++) {
- fillView(context, group.getChildAt(i), item, parentItem);
+ fillView(context, group.getChildAt(i), item, parentItem, callback, adapterRef);
}
} else {
int id = view.getId();
@@ -184,8 +85,8 @@
if (view instanceof TextView) {
TextView tv = (TextView) view;
- Object value = mCallback.getAdapterItemValue(
- mAdapterRef, context.getViewKey(view),
+ Object value = callback.getAdapterItemValue(
+ adapterRef, context.getViewKey(view),
item.getDataBindingItem().getViewReference(),
fullPosition, positionPerType,
fullParentPosition, parentPositionPerType,
@@ -204,8 +105,8 @@
if (view instanceof Checkable) {
Checkable cb = (Checkable) view;
- Object value = mCallback.getAdapterItemValue(
- mAdapterRef, context.getViewKey(view),
+ Object value = callback.getAdapterItemValue(
+ adapterRef, context.getViewKey(view),
item.getDataBindingItem().getViewReference(),
fullPosition, positionPerType,
fullParentPosition, parentPositionPerType,
@@ -224,8 +125,8 @@
if (view instanceof ImageView) {
ImageView iv = (ImageView) view;
- Object value = mCallback.getAdapterItemValue(
- mAdapterRef, context.getViewKey(view),
+ Object value = callback.getAdapterItemValue(
+ adapterRef, context.getViewKey(view),
item.getDataBindingItem().getViewReference(),
fullPosition, positionPerType,
fullParentPosition, parentPositionPerType,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java
new file mode 100644
index 0000000..8e28dba
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.impl.binding;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.android.ide.common.rendering.api.DataBindingItem;
+
+/**
+ * This is the items provided by the adapter. They are dynamically generated.
+ */
+final class AdapterItem {
+ private final DataBindingItem mItem;
+ private final int mType;
+ private final int mFullPosition;
+ private final int mPositionPerType;
+ private List<AdapterItem> mChildren;
+
+ protected AdapterItem(DataBindingItem item, int type, int fullPosition,
+ int positionPerType) {
+ mItem = item;
+ mType = type;
+ mFullPosition = fullPosition;
+ mPositionPerType = positionPerType;
+ }
+
+ void addChild(AdapterItem child) {
+ if (mChildren == null) {
+ mChildren = new ArrayList<AdapterItem>();
+ }
+
+ mChildren.add(child);
+ }
+
+ List<AdapterItem> getChildren() {
+ if (mChildren != null) {
+ return mChildren;
+ }
+
+ return Collections.emptyList();
+ }
+
+ int getType() {
+ return mType;
+ }
+
+ int getFullPosition() {
+ return mFullPosition;
+ }
+
+ int getPositionPerType() {
+ return mPositionPerType;
+ }
+
+ DataBindingItem getDataBindingItem() {
+ return mItem;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
index 22570b9..9a13f5a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
@@ -20,10 +20,12 @@
import com.android.ide.common.rendering.api.DataBindingItem;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
+import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import android.widget.SpinnerAdapter;
@@ -35,17 +37,23 @@
* and {@link SpinnerAdapter}.
*
*/
-public class FakeAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
+@SuppressWarnings("deprecation")
+public class FakeAdapter extends BaseAdapter {
// don't use a set because the order is important.
private final List<ResourceReference> mTypes = new ArrayList<ResourceReference>();
+ private final IProjectCallback mCallback;
+ private final ResourceReference mAdapterRef;
+ private final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
+ private boolean mSkipCallbackParser = false;
public FakeAdapter(ResourceReference adapterRef, AdapterBinding binding,
IProjectCallback callback) {
- super(adapterRef, binding, callback);
+ mAdapterRef = adapterRef;
+ mCallback = callback;
- final int repeatCount = getBinding().getRepeatCount();
- final int itemCount = getBinding().getItemCount();
+ final int repeatCount = binding.getRepeatCount();
+ final int itemCount = binding.getItemCount();
// Need an array to count for each type.
// This is likely too big, but is the max it can be.
@@ -54,7 +62,7 @@
// We put several repeating sets.
for (int r = 0 ; r < repeatCount ; r++) {
// loop on the type of list items, and add however many for each type.
- for (DataBindingItem dataBindingItem : getBinding()) {
+ for (DataBindingItem dataBindingItem : binding) {
ResourceReference viewRef = dataBindingItem.getViewReference();
int typeIndex = mTypes.indexOf(viewRef);
if (typeIndex == -1) {
@@ -103,7 +111,11 @@
public View getView(int position, View convertView, ViewGroup parent) {
// we don't care about recycling here because we never scroll.
AdapterItem item = mItems.get(position);
- return getView(item, null /*parentGroup*/, convertView, parent);
+ Pair<View, Boolean> pair = AdapterHelper.getView(item, null /*parentGroup*/, parent,
+ mCallback, mAdapterRef, mSkipCallbackParser);
+ mSkipCallbackParser = pair.getSecond();
+ return pair.getFirst();
+
}
@Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
index 199e040..e539579 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
@@ -20,7 +20,9 @@
import com.android.ide.common.rendering.api.DataBindingItem;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.util.Pair;
+import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListAdapter;
@@ -29,8 +31,14 @@
import java.util.ArrayList;
import java.util.List;
-public class FakeExpandableAdapter extends BaseAdapter implements ExpandableListAdapter,
- HeterogeneousExpandableList {
+@SuppressWarnings("deprecation")
+public class FakeExpandableAdapter implements ExpandableListAdapter, HeterogeneousExpandableList {
+
+ private final IProjectCallback mCallback;
+ private final ResourceReference mAdapterRef;
+ private boolean mSkipCallbackParser = false;
+
+ protected final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
// don't use a set because the order is important.
private final List<ResourceReference> mGroupTypes = new ArrayList<ResourceReference>();
@@ -38,7 +46,8 @@
public FakeExpandableAdapter(ResourceReference adapterRef, AdapterBinding binding,
IProjectCallback callback) {
- super(adapterRef, binding, callback);
+ mAdapterRef = adapterRef;
+ mCallback = callback;
createItems(binding, binding.getItemCount(), binding.getRepeatCount(), mGroupTypes, 1);
}
@@ -125,7 +134,10 @@
ViewGroup parent) {
// we don't care about recycling here because we never scroll.
AdapterItem item = mItems.get(groupPosition);
- return getView(item, null /*parentItem*/, convertView, parent);
+ Pair<View, Boolean> pair = AdapterHelper.getView(item, null /*parentItem*/, parent,
+ mCallback, mAdapterRef, mSkipCallbackParser);
+ mSkipCallbackParser = pair.getSecond();
+ return pair.getFirst();
}
@Override
@@ -134,7 +146,10 @@
// we don't care about recycling here because we never scroll.
AdapterItem parentItem = mItems.get(groupPosition);
AdapterItem item = getChildItem(groupPosition, childPosition);
- return getView(item, parentItem, convertView, parent);
+ Pair<View, Boolean> pair = AdapterHelper.getView(item, parentItem, parent, mCallback,
+ mAdapterRef, mSkipCallbackParser);
+ mSkipCallbackParser = pair.getSecond();
+ return pair.getFirst();
}
@Override
@@ -172,6 +187,31 @@
// pass
}
+ @Override
+ public void registerDataSetObserver(DataSetObserver observer) {
+ // pass
+ }
+
+ @Override
+ public void unregisterDataSetObserver(DataSetObserver observer) {
+ // pass
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return mItems.isEmpty();
+ }
+
// ---- HeterogeneousExpandableList
@Override
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index ea7904c..f79a4a6 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -115,6 +115,7 @@
private Context mContext;
private static final String TAG = "WifiConfigStore";
private static final boolean DBG = true;
+ private static final boolean VDBG = false;
private static final String SUPPLICANT_CONFIG_FILE = "/data/misc/wifi/wpa_supplicant.conf";
@@ -154,7 +155,7 @@
private static final String EOS = "eos";
private final LocalLog mLocalLog;
- WpaConfigFileObserver mFileObserver;
+ private final WpaConfigFileObserver mFileObserver;
private WifiNative mWifiNative;
private final KeyStore mKeyStore = KeyStore.getInstance();
@@ -163,10 +164,13 @@
mContext = c;
mWifiNative = wn;
- if (DBG) {
+ if (VDBG) {
mLocalLog = mWifiNative.getLocalLog();
mFileObserver = new WpaConfigFileObserver();
mFileObserver.startWatching();
+ } else {
+ mLocalLog = null;
+ mFileObserver = null;
}
}
@@ -180,7 +184,7 @@
public void onEvent(int event, String path) {
if (event == CLOSE_WRITE) {
File file = new File(SUPPLICANT_CONFIG_FILE);
- localLog("wpa_supplicant.conf changed; new size = " + file.length());
+ if (VDBG) localLog("wpa_supplicant.conf changed; new size = " + file.length());
}
}
}
@@ -245,7 +249,7 @@
* @return false if the network id is invalid
*/
boolean selectNetwork(int netId) {
- localLog("selectNetwork", netId);
+ if (VDBG) localLog("selectNetwork", netId);
if (netId == INVALID_NETWORK_ID) return false;
// Reset the priority of each network at start or if it goes too high.
@@ -282,7 +286,7 @@
* @return network update result
*/
NetworkUpdateResult saveNetwork(WifiConfiguration config) {
- localLog("saveNetwork", config.networkId);
+ if (VDBG) localLog("saveNetwork", config.networkId);
// A new network cannot have null SSID
if (config == null || (config.networkId == INVALID_NETWORK_ID &&
config.SSID == null)) {
@@ -331,7 +335,7 @@
* @return {@code true} if it succeeds, {@code false} otherwise
*/
boolean forgetNetwork(int netId) {
- localLog("forgetNetwork", netId);
+ if (VDBG) localLog("forgetNetwork", netId);
if (mWifiNative.removeNetwork(netId)) {
mWifiNative.saveConfig();
removeConfigAndSendBroadcastIfNeeded(netId);
@@ -352,7 +356,7 @@
* @return network Id
*/
int addOrUpdateNetwork(WifiConfiguration config) {
- localLog("addOrUpdateNetwork", config.networkId);
+ if (VDBG) localLog("addOrUpdateNetwork", config.networkId);
NetworkUpdateResult result = addOrUpdateNetworkNative(config);
if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
sendConfiguredNetworksChangedBroadcast(mConfiguredNetworks.get(result.getNetworkId()),
@@ -372,7 +376,7 @@
* @return {@code true} if it succeeds, {@code false} otherwise
*/
boolean removeNetwork(int netId) {
- localLog("removeNetwork", netId);
+ if (VDBG) localLog("removeNetwork", netId);
boolean ret = mWifiNative.removeNetwork(netId);
if (ret) {
removeConfigAndSendBroadcastIfNeeded(netId);
@@ -407,10 +411,10 @@
boolean enableNetwork(int netId, boolean disableOthers) {
boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers);
if (disableOthers) {
- localLog("enableNetwork(disableOthers=true) ", netId);
+ if (VDBG) localLog("enableNetwork(disableOthers=true) ", netId);
sendConfiguredNetworksChangedBroadcast();
} else {
- localLog("enableNetwork(disableOthers=false) ", netId);
+ if (VDBG) localLog("enableNetwork(disableOthers=false) ", netId);
WifiConfiguration enabledNetwork = null;
synchronized(mConfiguredNetworks) {
enabledNetwork = mConfiguredNetworks.get(netId);
@@ -437,7 +441,7 @@
}
void disableAllNetworks() {
- localLog("disableAllNetworks");
+ if (VDBG) localLog("disableAllNetworks");
boolean networkDisabled = false;
for(WifiConfiguration config : mConfiguredNetworks.values()) {
if(config != null && config.status != Status.DISABLED) {
@@ -470,7 +474,7 @@
* @return {@code true} if it succeeds, {@code false} otherwise
*/
boolean disableNetwork(int netId, int reason) {
- localLog("disableNetwork", netId);
+ if (VDBG) localLog("disableNetwork", netId);
boolean ret = mWifiNative.disableNetwork(netId);
WifiConfiguration network = null;
WifiConfiguration config = mConfiguredNetworks.get(netId);
@@ -683,33 +687,33 @@
if (mNetworkIds.containsKey(configKey(config))) {
// That SSID is already known, just ignore this duplicate entry
- localLog("discarded duplicate network", config.networkId);
+ if (VDBG) localLog("discarded duplicate network", config.networkId);
} else {
mConfiguredNetworks.put(config.networkId, config);
mNetworkIds.put(configKey(config), config.networkId);
- localLog("loaded configured network", config.networkId);
+ if (VDBG) localLog("loaded configured network", config.networkId);
}
}
readIpAndProxyConfigurations();
sendConfiguredNetworksChangedBroadcast();
- localLog("loadConfiguredNetworks loaded " + mNetworkIds.size() + " networks");
+ if (VDBG) localLog("loadConfiguredNetworks loaded " + mNetworkIds.size() + " networks");
if (mNetworkIds.size() == 0) {
// no networks? Lets log if the wpa_supplicant.conf file contents
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(SUPPLICANT_CONFIG_FILE));
- localLog("--- Begin wpa_supplicant.conf Contents ---");
+ if (VDBG) localLog("--- Begin wpa_supplicant.conf Contents ---");
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
- localLog(line);
+ if (VDBG) localLog(line);
}
- localLog("--- End wpa_supplicant.conf Contents ---");
+ if (VDBG) localLog("--- End wpa_supplicant.conf Contents ---");
} catch (FileNotFoundException e) {
- localLog("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e);
+ if (VDBG) localLog("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e);
} catch (IOException e) {
- localLog("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e);
+ if (VDBG) localLog("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e);
} finally {
try {
if (reader != null) {
@@ -1050,7 +1054,7 @@
* refer to an existing configuration.
*/
- localLog("addOrUpdateNetworkNative " + config.getPrintableSsid());
+ if (VDBG) localLog("addOrUpdateNetworkNative " + config.getPrintableSsid());
int netId = config.networkId;
boolean newNetwork = false;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index de377ee..2b3c9e2 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -348,6 +348,28 @@
linkProperties = new LinkProperties();
}
+ /**
+ * indicates whether the configuration is valid
+ * @return true if valid, false otherwise
+ * @hide
+ */
+ public boolean isValid() {
+ if (allowedKeyManagement.cardinality() > 1) {
+ if (allowedKeyManagement.cardinality() != 2) {
+ return false;
+ }
+ if (allowedKeyManagement.get(KeyMgmt.WPA_EAP) == false) {
+ return false;
+ }
+ if (allowedKeyManagement.get(KeyMgmt.IEEE8021X) == false) {
+ return false;
+ }
+ }
+
+ // TODO: Add more checks
+ return true;
+ }
+
@Override
public String toString() {
StringBuilder sbuf = new StringBuilder();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 5f5d54f..3223cb3 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -818,6 +818,10 @@
/**
* End a requested batch scan for this applicaiton. Note that batched scan may
* still occur if other apps are using them.
+ *
+ * @param requested {@link BatchedScanSettings} the scan settings you previously requested
+ * and now wish to stop. A value of null here will stop all scans requested by the
+ * calling App.
* @hide
*/
public void stopBatchedScan(BatchedScanSettings requested) {
@@ -833,7 +837,7 @@
*/
public List<BatchedScanResult> getBatchedScanResults() {
try {
- return mService.getBatchedScanResults(mContext.getBasePackageName());
+ return mService.getBatchedScanResults(mContext.getOpPackageName());
} catch (RemoteException e) {
return null;
}
@@ -883,7 +887,7 @@
*/
public List<ScanResult> getScanResults() {
try {
- return mService.getScanResults(mContext.getBasePackageName());
+ return mService.getScanResults(mContext.getOpPackageName());
} catch (RemoteException e) {
return null;
}
@@ -1366,6 +1370,13 @@
/** WPS timed out {@hide} */
public static final int WPS_TIMED_OUT = 7;
+ /**
+ * Passed with {@link ActionListener#onFailure}.
+ * Indicates that the operation failed due to invalid inputs
+ * @hide
+ */
+ public static final int INVALID_ARGS = 8;
+
/** Interface for callback invocation on an application action {@hide} */
public interface ActionListener {
/** The operation succeeded */
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 83789e2..520668e 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -25,6 +25,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
/**
* Native calls for bring up/shut down of the supplicant daemon and for
@@ -38,6 +39,7 @@
public class WifiNative {
private static final boolean DBG = false;
+ private static final boolean VDBG = false;
private final String mTAG;
private static final int DEFAULT_GROUP_OWNER_INTENT = 6;
@@ -116,12 +118,12 @@
public boolean connectToSupplicant() {
// No synchronization necessary .. it is implemented in WifiMonitor
- localLog(mInterfacePrefix + "connectToSupplicant");
+ if (VDBG) localLog(mInterfacePrefix + "connectToSupplicant");
return connectToSupplicantNative();
}
public void closeSupplicantConnection() {
- localLog(mInterfacePrefix + "closeSupplicantConnection");
+ if (VDBG) localLog(mInterfacePrefix + "closeSupplicantConnection");
closeSupplicantConnectionNative();
}
@@ -134,9 +136,10 @@
if (DBG) Log.d(mTAG, "doBoolean: " + command);
synchronized (mLock) {
int cmdId = getNewCmdIdLocked();
- localLog(cmdId + "->" + mInterfacePrefix + command);
+ if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
boolean result = doBooleanCommandNative(mInterfacePrefix + command);
- localLog(cmdId + "<-" + result);
+ if (VDBG) localLog(cmdId + "<-" + result);
+ if (DBG) Log.d(mTAG, " returned " + result);
return result;
}
}
@@ -145,9 +148,10 @@
if (DBG) Log.d(mTAG, "doInt: " + command);
synchronized (mLock) {
int cmdId = getNewCmdIdLocked();
- localLog(cmdId + "->" + mInterfacePrefix + command);
+ if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
int result = doIntCommandNative(mInterfacePrefix + command);
- localLog(cmdId + "<-" + result);
+ if (VDBG) localLog(cmdId + "<-" + result);
+ if (DBG) Log.d(mTAG, " returned " + result);
return result;
}
}
@@ -156,9 +160,10 @@
if (DBG) Log.d(mTAG, "doString: " + command);
synchronized (mLock) {
int cmdId = getNewCmdIdLocked();
- localLog(cmdId + "->" + mInterfacePrefix + command);
+ if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
String result = doStringCommandNative(mInterfacePrefix + command);
- localLog(cmdId + "<-" + result);
+ if (VDBG) localLog(cmdId + "<-" + result);
+ if (DBG) Log.d(mTAG, " returned " + result);
return result;
}
}
@@ -280,7 +285,7 @@
/**
* Format of command
- * DRIVER WLS_BATCHING SET SCAN_FRQ=x MSCAN=r BESTN=y CHANNEL=<z, w, t> RTT=s
+ * DRIVER WLS_BATCHING SET SCANFREQ=x MSCAN=r BESTN=y CHANNEL=<z, w, t> RTT=s
* where x is an ascii representation of an integer number of seconds between scans
* r is an ascii representation of an integer number of scans per batch
* y is an ascii representation of an integer number of the max AP to remember per scan
@@ -294,7 +299,7 @@
*/
public String setBatchedScanSettings(BatchedScanSettings settings) {
if (settings == null) return doStringCommand("DRIVER WLS_BATCHING STOP");
- String cmd = "DRIVER WLS_BATCHING SET SCAN_FRQ=" + settings.scanIntervalSec;
+ String cmd = "DRIVER WLS_BATCHING SET SCANFREQ=" + settings.scanIntervalSec;
cmd += " MSCAN=" + settings.maxScansPerBatch;
if (settings.maxApPerScan != BatchedScanSettings.UNSPECIFIED) {
cmd += " BESTN=" + settings.maxApPerScan;
@@ -457,7 +462,7 @@
}
public boolean setCountryCode(String countryCode) {
- return doBooleanCommand("DRIVER COUNTRY " + countryCode);
+ return doBooleanCommand("DRIVER COUNTRY " + countryCode.toUpperCase(Locale.ROOT));
}
public void enableBackgroundScan(boolean enable) {
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 3ccdbea..ad89716 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -65,6 +65,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.WorkSource;
@@ -88,7 +89,6 @@
import java.net.Inet6Address;
import java.util.ArrayList;
import java.util.List;
-import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.Iterator;
@@ -860,6 +860,7 @@
mExpectedBatchedScans = Integer.parseInt(scansExpected);
setNextBatchedAlarm(mExpectedBatchedScans);
} catch (NumberFormatException e) {
+ stopBatchedScan();
loge("Exception parsing WifiNative.setBatchedScanSettings response " + e);
}
}
@@ -877,6 +878,11 @@
}
private void handleBatchedScanPollRequest() {
+ if (DBG) {
+ log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" +
+ mBatchedScanMinPollTime + " , mBatchedScanSettings=" +
+ mBatchedScanSettings);
+ }
// if there is no appropriate PollTime that's because we either aren't
// batching or we've already set a time for a poll request
if (mBatchedScanMinPollTime == 0) return;
@@ -888,7 +894,7 @@
// do the poll and reset our timers
startNextBatchedScan();
} else {
- mAlarmManager.set(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime,
+ mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime,
mBatchedScanIntervalIntent);
mBatchedScanMinPollTime = 0;
}
@@ -933,7 +939,7 @@
// set the alarm to do the next poll. We set it a little short as we'd rather
// wake up wearly than miss a scan due to buffer overflow
- mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000),
mBatchedScanIntervalIntent);
}
@@ -965,11 +971,13 @@
* etc
* "----"
*/
+ private final static boolean DEBUG_PARSE = false;
private void retrieveBatchedScanData() {
String rawData = mWifiNative.getBatchedScanResults();
+ if (DEBUG_PARSE) log("rawData = " + rawData);
mBatchedScanMinPollTime = 0;
- if (rawData == null) {
- loge("Unexpected null BatchedScanResults");
+ if (rawData == null || rawData.equalsIgnoreCase("OK")) {
+ loge("Unexpected BatchedScanResults :" + rawData);
return;
}
@@ -979,17 +987,19 @@
final String TRUNCATED = "trunc";
final String AGE = "age=";
final String DIST = "dist=";
- final String DISTSD = "distsd=";
+ final String DISTSD = "distSd=";
String splitData[] = rawData.split("\n");
int n = 0;
if (splitData[n].startsWith(SCANCOUNT)) {
try {
scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length()));
- } catch (NumberFormatException e) {}
- }
+ } catch (NumberFormatException e) {
+ loge("scancount parseInt Exception from " + splitData[n]);
+ }
+ } else log("scancount not found");
if (scanCount == 0) {
- loge("scanCount not found");
+ loge("scanCount==0 - aborting");
return;
}
@@ -1007,17 +1017,19 @@
int dist, distSd;
long tsf = 0;
dist = distSd = ScanResult.UNSPECIFIED;
- long now = System.currentTimeMillis();
+ long now = SystemClock.elapsedRealtime();
while (true) {
while (n < splitData.length) {
+ if (DEBUG_PARSE) logd("parsing " + splitData[n]);
if (splitData[n].equals(END_OF_BATCHES)) {
- if (++n != splitData.length) {
+ if (n+1 != splitData.length) {
loge("didn't consume " + (splitData.length-n));
}
if (mBatchedScanResults.size() > 0) {
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
}
+ logd("retrieveBatchedScanResults X");
return;
}
if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) {
@@ -1039,51 +1051,57 @@
logd("Found empty batch");
}
}
- n++;
- } else if (splitData[n].equals(BSSID_STR)) {
- bssid = splitData[n++].substring(BSSID_STR.length());
- } else if (splitData[n].equals(FREQ_STR)) {
+ } else if (splitData[n].equals(TRUNCATED)) {
+ batchedScanResult.truncated = true;
+ } else if (splitData[n].startsWith(BSSID_STR)) {
+ bssid = splitData[n].substring(BSSID_STR.length());
+ } else if (splitData[n].startsWith(FREQ_STR)) {
try {
- freq = Integer.parseInt(splitData[n++].substring(FREQ_STR.length()));
+ freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length()));
} catch (NumberFormatException e) {
- loge("Invalid freqency: " + splitData[n-1]);
+ loge("Invalid freqency: " + splitData[n]);
freq = 0;
}
- } else if (splitData[n].equals(AGE)) {
+ } else if (splitData[n].startsWith(AGE)) {
try {
- tsf = now - Long.parseLong(splitData[n++].substring(AGE.length()));
+ tsf = now - Long.parseLong(splitData[n].substring(AGE.length()));
+ tsf *= 1000; // convert mS -> uS
} catch (NumberFormatException e) {
- loge("Invalid timestamp: " + splitData[n-1]);
+ loge("Invalid timestamp: " + splitData[n]);
tsf = 0;
}
- } else if (splitData[n].equals(SSID_STR)) {
+ } else if (splitData[n].startsWith(SSID_STR)) {
wifiSsid = WifiSsid.createFromAsciiEncoded(
- splitData[n++].substring(SSID_STR.length()));
- } else if (splitData[n].equals(LEVEL_STR)) {
+ splitData[n].substring(SSID_STR.length()));
+ } else if (splitData[n].startsWith(LEVEL_STR)) {
try {
- level = Integer.parseInt(splitData[n++].substring(LEVEL_STR.length()));
+ level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length()));
if (level > 0) level -= 256;
} catch (NumberFormatException e) {
- loge("Invalid level: " + splitData[n-1]);
+ loge("Invalid level: " + splitData[n]);
level = 0;
}
- } else if (splitData[n].equals(DIST)) {
+ } else if (splitData[n].startsWith(DIST)) {
try {
- dist = Integer.parseInt(splitData[n++].substring(DIST.length()));
+ dist = Integer.parseInt(splitData[n].substring(DIST.length()));
} catch (NumberFormatException e) {
- loge("Invalid distance: " + splitData[n-1]);
+ loge("Invalid distance: " + splitData[n]);
dist = ScanResult.UNSPECIFIED;
}
- } else if (splitData[n].equals(DISTSD)) {
+ } else if (splitData[n].startsWith(DISTSD)) {
try {
- distSd = Integer.parseInt(splitData[n++].substring(DISTSD.length()));
+ distSd = Integer.parseInt(splitData[n].substring(DISTSD.length()));
} catch (NumberFormatException e) {
- loge("Invalid distanceSd: " + splitData[n-1]);
+ loge("Invalid distanceSd: " + splitData[n]);
distSd = ScanResult.UNSPECIFIED;
}
+ } else {
+ loge("Unable to parse batched scan result line: " + splitData[n]);
}
+ n++;
}
rawData = mWifiNative.getBatchedScanResults();
+ if (DEBUG_PARSE) log("reading more data:\n" + rawData);
if (rawData == null) {
loge("Unexpected null BatchedScanResults");
return;
@@ -1431,6 +1449,7 @@
countryCode);
}
sendMessage(CMD_SET_COUNTRY_CODE, countryCode);
+ mWifiP2pChannel.sendMessage(WifiP2pService.SET_COUNTRY_CODE, countryCode);
}
/**
@@ -2392,6 +2411,7 @@
break;
case CMD_POLL_BATCHED_SCAN:
handleBatchedScanPollRequest();
+ break;
case CMD_START_NEXT_BATCHED_SCAN:
startNextBatchedScan();
break;
@@ -2952,7 +2972,7 @@
case CMD_SET_COUNTRY_CODE:
String country = (String) message.obj;
if (DBG) log("set country code " + country);
- if (!mWifiNative.setCountryCode(country.toUpperCase(Locale.ROOT))) {
+ if (!mWifiNative.setCountryCode(country)) {
loge("Failed to set country code " + country);
}
break;
@@ -4256,7 +4276,7 @@
/**
* arg2 on the source message has a unique id that needs to be retained in replies
* to match the request
- *
+
* see WifiManager for details
*/
private Message obtainMessageWithArg2(Message srcMsg) {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 05196b8..625ffb8 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -174,6 +174,9 @@
// msg.obj = StateMachine to send to when blocked
public static final int BLOCK_DISCOVERY = BASE + 15;
+ // set country code
+ public static final int SET_COUNTRY_CODE = BASE + 16;
+
public static final int ENABLED = 1;
public static final int DISABLED = 0;
@@ -632,6 +635,7 @@
case WifiP2pManager.START_LISTEN:
case WifiP2pManager.STOP_LISTEN:
case WifiP2pManager.SET_CHANNEL:
+ case SET_COUNTRY_CODE:
break;
case WifiStateMachine.CMD_ENABLE_P2P:
// Enable is lazy and has no response
@@ -1064,6 +1068,10 @@
replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
}
break;
+ case SET_COUNTRY_CODE:
+ String countryCode = (String) message.obj;
+ mWifiNative.setCountryCode(countryCode);
+ break;
default:
return NOT_HANDLED;
}
@@ -2537,6 +2545,12 @@
mServiceTransactionId = 0;
mServiceDiscReqId = null;
+ String countryCode = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.WIFI_COUNTRY_CODE);
+ if (countryCode != null && !countryCode.isEmpty()) {
+ mP2pStateMachine.sendMessage(SET_COUNTRY_CODE, countryCode);
+ }
+
updatePersistentNetworks(RELOAD);
}