diff options
336 files changed, 5965 insertions, 1897 deletions
diff --git a/api/current.txt b/api/current.txt index 25b36b6..725c27d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -21319,6 +21319,9 @@ package android.os { method public void clear(); method public boolean containsKey(java.lang.String); method public java.lang.Object get(java.lang.String); + method public boolean getBoolean(java.lang.String); + method public boolean getBoolean(java.lang.String, boolean); + method public boolean[] getBooleanArray(java.lang.String); method public double getDouble(java.lang.String); method public double getDouble(java.lang.String, double); method public double[] getDoubleArray(java.lang.String); @@ -21334,6 +21337,8 @@ package android.os { method public boolean isEmpty(); method public java.util.Set<java.lang.String> keySet(); method public void putAll(android.os.PersistableBundle); + method public void putBoolean(java.lang.String, boolean); + method public void putBooleanArray(java.lang.String, boolean[]); method public void putDouble(java.lang.String, double); method public void putDoubleArray(java.lang.String, double[]); method public void putInt(java.lang.String, int); @@ -21479,9 +21484,6 @@ package android.os { method public java.lang.Object clone(); method public int describeContents(); method public android.os.IBinder getBinder(java.lang.String); - method public boolean getBoolean(java.lang.String); - method public boolean getBoolean(java.lang.String, boolean); - method public boolean[] getBooleanArray(java.lang.String); method public android.os.Bundle getBundle(java.lang.String); method public byte getByte(java.lang.String); method public java.lang.Byte getByte(java.lang.String, byte); @@ -21512,8 +21514,6 @@ package android.os { method public boolean hasFileDescriptors(); method public void putAll(android.os.Bundle); method public void putBinder(java.lang.String, android.os.IBinder); - method public void putBoolean(java.lang.String, boolean); - method public void putBooleanArray(java.lang.String, boolean[]); method public void putBundle(java.lang.String, android.os.Bundle); method public void putByte(java.lang.String, byte); method public void putByteArray(java.lang.String, byte[]); @@ -28651,7 +28651,6 @@ package android.telephony { method public boolean isNetworkRoaming(int); method public void registerOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); method public void unregisterOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); - field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff } public static class SubscriptionManager.OnSubscriptionsChangedListener { @@ -33331,6 +33330,7 @@ package android.view { method public void dispatchDisplayHint(int); method public boolean dispatchDragEvent(android.view.DragEvent); method protected void dispatchDraw(android.graphics.Canvas); + method public void dispatchDrawableHotspotChanged(float, float); method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent); method public boolean dispatchGenericMotionEvent(android.view.MotionEvent); method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent); diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index bdcff38..88b9080 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -71,6 +71,7 @@ interface INotificationManager ComponentName getEffectsSuppressor(); boolean matchesCallFilter(in Bundle extras); + boolean isSystemConditionProviderEnabled(String path); ZenModeConfig getZenModeConfig(); boolean setZenModeConfig(in ZenModeConfig config); diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index 3c30404..ad2b61f 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -1217,8 +1217,10 @@ public class Instrumentation { public void callActivityOnNewIntent(Activity activity, ReferrerIntent intent) { final String oldReferrer = activity.mReferrer; try { - activity.mReferrer = intent.mReferrer; - callActivityOnNewIntent(activity, new Intent(intent)); + if (intent != null) { + activity.mReferrer = intent.mReferrer; + } + callActivityOnNewIntent(activity, intent != null ? new Intent(intent) : null); } finally { activity.mReferrer = oldReferrer; } diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 7dc1ad6..cf54107 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -264,5 +264,17 @@ public class NotificationManager } } + /** + * @hide + */ + public boolean isSystemConditionProviderEnabled(String path) { + INotificationManager service = getService(); + try { + return service.isSystemConditionProviderEnabled(path); + } catch (RemoteException e) { + return false; + } + } + private Context mContext; } diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java index a86677c..7cdcc2c 100644 --- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java +++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java @@ -502,7 +502,7 @@ public class BluetoothGattCharacteristic { * @return Cached value of the characteristic */ public String getStringValue(int offset) { - if (offset > mValue.length) return null; + if (mValue == null || offset > mValue.length) return null; byte[] strBytes = new byte[mValue.length - offset]; for (int i=0; i != (mValue.length-offset); ++i) strBytes[i] = mValue[offset+i]; return new String(strBytes); diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index de7fbab..5ebbf16 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -4391,7 +4391,7 @@ public class Intent implements Parcelable, Cloneable { // scheme else if (uri.startsWith("scheme=", i)) { if (inSelector) { - intent.mData = Uri.parse(value); + intent.mData = Uri.parse(value + ":"); } else { scheme = value; } @@ -4461,14 +4461,19 @@ public class Intent implements Parcelable, Cloneable { String authority = null; intent.mPackage = data.substring(14, end); int newEnd; - if (end < data.length() && (newEnd=data.indexOf('/', end+1)) >= 0) { - // Found a scheme, remember it. - scheme = data.substring(end+1, newEnd); - end = newEnd; - if (end < data.length() && (newEnd=data.indexOf('/', end+1)) >= 0) { - // Found a authority, remember it. - authority = data.substring(end+1, newEnd); + if ((end+1) < data.length()) { + if ((newEnd=data.indexOf('/', end+1)) >= 0) { + // Found a scheme, remember it. + scheme = data.substring(end+1, newEnd); end = newEnd; + if (end < data.length() && (newEnd=data.indexOf('/', end+1)) >= 0) { + // Found a authority, remember it. + authority = data.substring(end+1, newEnd); + end = newEnd; + } + } else { + // All we have is a scheme. + scheme = data.substring(end+1); } } if (scheme == null) { @@ -7355,7 +7360,7 @@ public class Intent implements Parcelable, Cloneable { toUriInner(frag, scheme, defAction, defPackage, flags); if (mSelector != null) { - uri.append("SEL;"); + frag.append("SEL;"); // Note that for now we are not going to try to handle the // data part; not clear how to represent this as a URI, and // not much utility in it. diff --git a/core/java/android/hardware/camera2/legacy/GLThreadManager.java b/core/java/android/hardware/camera2/legacy/GLThreadManager.java index 64c532b..b160d2a 100644 --- a/core/java/android/hardware/camera2/legacy/GLThreadManager.java +++ b/core/java/android/hardware/camera2/legacy/GLThreadManager.java @@ -22,6 +22,8 @@ import android.os.ConditionVariable; import android.os.Handler; import android.os.Message; import android.util.Log; +import android.util.Pair; +import android.util.Size; import android.view.Surface; import java.util.Collection; @@ -57,11 +59,11 @@ public class GLThreadManager { */ private static class ConfigureHolder { public final ConditionVariable condition; - public final Collection<Surface> surfaces; + public final Collection<Pair<Surface, Size>> surfaces; public final CaptureCollector collector; - public ConfigureHolder(ConditionVariable condition, Collection<Surface> surfaces, - CaptureCollector collector) { + public ConfigureHolder(ConditionVariable condition, Collection<Pair<Surface, + Size>> surfaces, CaptureCollector collector) { this.condition = condition; this.surfaces = surfaces; this.collector = collector; @@ -202,10 +204,12 @@ public class GLThreadManager { * Configure the GL renderer for the given set of output surfaces, and block until * this configuration has been applied. * - * @param surfaces a collection of {@link android.view.Surface}s to configure. + * @param surfaces a collection of pairs of {@link android.view.Surface}s and their + * corresponding sizes to configure. * @param collector a {@link CaptureCollector} to retrieve requests from. */ - public void setConfigurationAndWait(Collection<Surface> surfaces, CaptureCollector collector) { + public void setConfigurationAndWait(Collection<Pair<Surface, Size>> surfaces, + CaptureCollector collector) { checkNotNull(collector, "collector must not be null"); Handler handler = mGLHandlerThread.getHandler(); diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java index 3a976ba..3043d13 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java +++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java @@ -24,7 +24,6 @@ import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.impl.CameraDeviceImpl; import android.hardware.camera2.impl.CaptureResultExtras; import android.hardware.camera2.ICameraDeviceCallbacks; -import android.hardware.camera2.params.StreamConfiguration; import android.hardware.camera2.params.StreamConfigurationMap; import android.hardware.camera2.utils.ArrayUtils; import android.hardware.camera2.utils.CameraBinderDecorator; @@ -36,6 +35,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.RemoteException; import android.util.Log; +import android.util.Pair; import android.util.Size; import android.view.Surface; @@ -78,6 +78,15 @@ public class LegacyCameraDevice implements AutoCloseable { private final Handler mResultHandler; private static final int ILLEGAL_VALUE = -1; + // Keep up to date with values in hardware/libhardware/include/hardware/gralloc.h + private static final int GRALLOC_USAGE_RENDERSCRIPT = 0x00100000; + private static final int GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003; + private static final int GRALLOC_USAGE_HW_TEXTURE = 0x00000100; + private static final int GRALLOC_USAGE_HW_COMPOSER = 0x00000800; + private static final int GRALLOC_USAGE_HW_VIDEO_ENCODER = 0x00010000; + + private static final int MAX_DIMEN_FOR_ROUNDING = 1080; // maximum allowed width for rounding + private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) { if (holder == null) { return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, @@ -276,6 +285,7 @@ public class LegacyCameraDevice implements AutoCloseable { * on success. */ public int configureOutputs(List<Surface> outputs) { + List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>(); if (outputs != null) { for (Surface output : outputs) { if (output == null) { @@ -289,16 +299,25 @@ public class LegacyCameraDevice implements AutoCloseable { try { Size s = getSurfaceSize(output); int surfaceType = detectSurfaceType(output); - Size[] sizes = streamConfigurations.getOutputSizes(surfaceType); + int usageFlags = detectSurfaceUsageFlags(output); + // Keep up to date with allowed consumer types in + // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp + int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT; + int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_HW_COMPOSER; + boolean flexibleConsumer = ((usageFlags & disallowedFlags) == 0 && + (usageFlags & allowedFlags) != 0); + + Size[] sizes = streamConfigurations.getOutputSizes(surfaceType); if (sizes == null) { // WAR: Override default format to IMPLEMENTATION_DEFINED for b/9487482 if ((surfaceType >= LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888 && surfaceType <= LegacyMetadataMapper.HAL_PIXEL_FORMAT_BGRA_8888)) { - // YUV_420_888 is always present in LEGACY for all IMPLEMENTATION_DEFINED - // output sizes, and is publicly visible in the API (i.e. - // {@code #getOutputSizes} works here). + // YUV_420_888 is always present in LEGACY for all + // IMPLEMENTATION_DEFINED output sizes, and is publicly visible in the + // API (i.e. {@code #getOutputSizes} works here). sizes = streamConfigurations.getOutputSizes(ImageFormat.YUV_420_888); } else if (surfaceType == LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB) { sizes = streamConfigurations.getOutputSizes(ImageFormat.JPEG); @@ -306,12 +325,18 @@ public class LegacyCameraDevice implements AutoCloseable { } if (!ArrayUtils.contains(sizes, s)) { - String reason = (sizes == null) ? "format is invalid." : - ("size not in valid set: " + Arrays.toString(sizes)); - Log.e(TAG, String.format("Surface with size (w=%d, h=%d) and format 0x%x is" - + " not valid, %s", s.getWidth(), s.getHeight(), surfaceType, - reason)); - return BAD_VALUE; + if (flexibleConsumer && (s = findClosestSize(s, sizes)) != null) { + sizedSurfaces.add(new Pair<>(output, s)); + } else { + String reason = (sizes == null) ? "format is invalid." : + ("size not in valid set: " + Arrays.toString(sizes)); + Log.e(TAG, String.format("Surface with size (w=%d, h=%d) and format " + + "0x%x is not valid, %s", s.getWidth(), s.getHeight(), + surfaceType, reason)); + return BAD_VALUE; + } + } else { + sizedSurfaces.add(new Pair<>(output, s)); } } catch (BufferQueueAbandonedException e) { Log.e(TAG, "Surface bufferqueue is abandoned, cannot configure as output: ", e); @@ -323,7 +348,7 @@ public class LegacyCameraDevice implements AutoCloseable { boolean success = false; if (mDeviceState.setConfiguring()) { - mRequestThreadManager.configure(outputs); + mRequestThreadManager.configure(sizedSurfaces); success = mDeviceState.setIdle(); } @@ -473,6 +498,31 @@ public class LegacyCameraDevice implements AutoCloseable { } } + static long findEuclidDistSquare(Size a, Size b) { + long d0 = a.getWidth() - b.getWidth(); + long d1 = a.getHeight() - b.getHeight(); + return d0 * d0 + d1 * d1; + } + + // Keep up to date with rounding behavior in + // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp + static Size findClosestSize(Size size, Size[] supportedSizes) { + if (size == null || supportedSizes == null) { + return null; + } + Size bestSize = null; + for (Size s : supportedSizes) { + if (s.equals(size)) { + return size; + } else if (s.getWidth() <= MAX_DIMEN_FOR_ROUNDING && (bestSize == null || + LegacyCameraDevice.findEuclidDistSquare(size, s) < + LegacyCameraDevice.findEuclidDistSquare(bestSize, s))) { + bestSize = s; + } + } + return bestSize; + } + /** * Query the surface for its currently configured default buffer size. * @param surface a non-{@code null} {@code Surface} @@ -490,6 +540,11 @@ public class LegacyCameraDevice implements AutoCloseable { return new Size(dimens[0], dimens[1]); } + static int detectSurfaceUsageFlags(Surface surface) { + checkNotNull(surface); + return nativeDetectSurfaceUsageFlags(surface); + } + static int detectSurfaceType(Surface surface) throws BufferQueueAbandonedException { checkNotNull(surface); return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceType(surface)); @@ -608,5 +663,7 @@ public class LegacyCameraDevice implements AutoCloseable { private static native int nativeSetNextTimestamp(Surface surface, long timestamp); + private static native int nativeDetectSurfaceUsageFlags(Surface surface); + static native int nativeGetJpegFooterSize(); } diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java index 35deb71..6535a4e 100644 --- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java +++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java @@ -41,6 +41,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.concurrent.TimeUnit; @@ -116,9 +117,10 @@ public class RequestThreadManager { */ private static class ConfigureHolder { public final ConditionVariable condition; - public final Collection<Surface> surfaces; + public final Collection<Pair<Surface, Size>> surfaces; - public ConfigureHolder(ConditionVariable condition, Collection<Surface> surfaces) { + public ConfigureHolder(ConditionVariable condition, Collection<Pair<Surface, + Size>> surfaces) { this.condition = condition; this.surfaces = surfaces; } @@ -317,7 +319,7 @@ public class RequestThreadManager { startPreview(); } - private void configureOutputs(Collection<Surface> outputs) { + private void configureOutputs(Collection<Pair<Surface, Size>> outputs) { if (DEBUG) { String outputsStr = outputs == null ? "null" : (outputs.size() + " surfaces"); Log.d(TAG, "configureOutputs with " + outputsStr); @@ -346,10 +348,15 @@ public class RequestThreadManager { mJpegSurfaceIds.clear(); mPreviewTexture = null; + List<Size> previewOutputSizes = new ArrayList<>(); + List<Size> callbackOutputSizes = new ArrayList<>(); + int facing = mCharacteristics.get(CameraCharacteristics.LENS_FACING); int orientation = mCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); if (outputs != null) { - for (Surface s : outputs) { + for (Pair<Surface, Size> outPair : outputs) { + Surface s = outPair.first; + Size outSize = outPair.second; try { int format = LegacyCameraDevice.detectSurfaceType(s); LegacyCameraDevice.setSurfaceOrientation(s, facing, orientation); @@ -362,9 +369,11 @@ public class RequestThreadManager { } mJpegSurfaceIds.add(LegacyCameraDevice.getSurfaceId(s)); mCallbackOutputs.add(s); + callbackOutputSizes.add(outSize); break; default: mPreviewOutputs.add(s); + previewOutputSizes.add(outSize); break; } } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) { @@ -391,18 +400,9 @@ public class RequestThreadManager { mParams.setPreviewFpsRange(bestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], bestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); - if (mPreviewOutputs.size() > 0) { - List<Size> outputSizes = new ArrayList<>(outputs.size()); - for (Surface s : mPreviewOutputs) { - try { - Size size = LegacyCameraDevice.getSurfaceSize(s); - outputSizes.add(size); - } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) { - Log.w(TAG, "Surface abandoned, skipping...", e); - } - } + if (previewOutputSizes.size() > 0) { - Size largestOutput = SizeAreaComparator.findLargestByArea(outputSizes); + Size largestOutput = SizeAreaComparator.findLargestByArea(previewOutputSizes); // Find largest jpeg dimension - assume to have the same aspect ratio as sensor. Size largestJpegDimen = ParameterUtils.getLargestSupportedJpegSizeByArea(mParams); @@ -439,7 +439,8 @@ public class RequestThreadManager { } } - Size smallestSupportedJpegSize = calculatePictureSize(mCallbackOutputs, mParams); + Size smallestSupportedJpegSize = calculatePictureSize(mCallbackOutputs, + callbackOutputSizes, mParams); if (smallestSupportedJpegSize != null) { /* * Set takePicture size to the smallest supported JPEG size large enough @@ -457,7 +458,12 @@ public class RequestThreadManager { mGLThreadManager.start(); } mGLThreadManager.waitUntilStarted(); - mGLThreadManager.setConfigurationAndWait(mPreviewOutputs, mCaptureCollector); + List<Pair<Surface, Size>> previews = new ArrayList<>(); + Iterator<Size> previewSizeIter = previewOutputSizes.iterator(); + for (Surface p : mPreviewOutputs) { + previews.add(new Pair<>(p, previewSizeIter.next())); + } + mGLThreadManager.setConfigurationAndWait(previews, mCaptureCollector); mGLThreadManager.allowNewFrames(); mPreviewTexture = mGLThreadManager.getCurrentSurfaceTexture(); if (mPreviewTexture != null) { @@ -499,26 +505,25 @@ public class RequestThreadManager { * {@code null} if the {@code callbackOutputs} did not have any {@code JPEG} * surfaces. */ - private Size calculatePictureSize( - Collection<Surface> callbackOutputs, Camera.Parameters params) { + private Size calculatePictureSize( List<Surface> callbackOutputs, + List<Size> callbackSizes, Camera.Parameters params) { /* * Find the largest JPEG size (if any), from the configured outputs: * - the api1 picture size should be set to the smallest legal size that's at least as large * as the largest configured JPEG size */ - List<Size> configuredJpegSizes = new ArrayList<Size>(); + if (callbackOutputs.size() != callbackSizes.size()) { + throw new IllegalStateException("Input collections must be same length"); + } + List<Size> configuredJpegSizes = new ArrayList<>(); + Iterator<Size> sizeIterator = callbackSizes.iterator(); for (Surface callbackSurface : callbackOutputs) { - try { - + Size jpegSize = sizeIterator.next(); if (!LegacyCameraDevice.containsSurfaceId(callbackSurface, mJpegSurfaceIds)) { continue; // Ignore non-JPEG callback formats } - Size jpegSize = LegacyCameraDevice.getSurfaceSize(callbackSurface); configuredJpegSizes.add(jpegSize); - } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) { - Log.w(TAG, "Surface abandoned, skipping...", e); - } } if (!configuredJpegSizes.isEmpty()) { /* @@ -994,7 +999,7 @@ public class RequestThreadManager { * * @param outputs a {@link java.util.Collection} of outputs to configure. */ - public void configure(Collection<Surface> outputs) { + public void configure(Collection<Pair<Surface, Size>> outputs) { Handler handler = mRequestThread.waitAndGetHandler(); final ConditionVariable condition = new ConditionVariable(/*closed*/false); ConfigureHolder holder = new ConfigureHolder(condition, outputs); diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java index c0d1d5e..4853b81 100644 --- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java +++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java @@ -397,16 +397,9 @@ public class SurfaceTextureRenderer { EGL14.EGL_NONE }; for (EGLSurfaceHolder holder : surfaces) { - try { - Size size = LegacyCameraDevice.getSurfaceSize(holder.surface); - holder.width = size.getWidth(); - holder.height = size.getHeight(); - holder.eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mConfigs, - holder.surface, surfaceAttribs, /*offset*/ 0); - checkEglError("eglCreateWindowSurface"); - } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) { - Log.w(TAG, "Surface abandoned, skipping...", e); - } + holder.eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mConfigs, + holder.surface, surfaceAttribs, /*offset*/ 0); + checkEglError("eglCreateWindowSurface"); } } @@ -417,24 +410,17 @@ public class SurfaceTextureRenderer { int maxLength = 0; for (EGLSurfaceHolder holder : surfaces) { - try { - Size size = LegacyCameraDevice.getSurfaceSize(holder.surface); - int length = size.getWidth() * size.getHeight(); - // Find max surface size, ensure PBuffer can hold this many pixels - maxLength = (length > maxLength) ? length : maxLength; - int[] surfaceAttribs = { - EGL14.EGL_WIDTH, size.getWidth(), - EGL14.EGL_HEIGHT, size.getHeight(), - EGL14.EGL_NONE - }; - holder.width = size.getWidth(); - holder.height = size.getHeight(); - holder.eglSurface = - EGL14.eglCreatePbufferSurface(mEGLDisplay, mConfigs, surfaceAttribs, 0); - checkEglError("eglCreatePbufferSurface"); - } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) { - Log.w(TAG, "Surface abandoned, skipping...", e); - } + int length = holder.width * holder.height; + // Find max surface size, ensure PBuffer can hold this many pixels + maxLength = (length > maxLength) ? length : maxLength; + int[] surfaceAttribs = { + EGL14.EGL_WIDTH, holder.width, + EGL14.EGL_HEIGHT, holder.height, + EGL14.EGL_NONE + }; + holder.eglSurface = + EGL14.eglCreatePbufferSurface(mEGLDisplay, mConfigs, surfaceAttribs, 0); + checkEglError("eglCreatePbufferSurface"); } mPBufferPixels = ByteBuffer.allocateDirect(maxLength * PBUFFER_PIXEL_BYTES) .order(ByteOrder.nativeOrder()); @@ -569,7 +555,7 @@ public class SurfaceTextureRenderer { * * @param surfaces a {@link Collection} of surfaces. */ - public void configureSurfaces(Collection<Surface> surfaces) { + public void configureSurfaces(Collection<Pair<Surface, Size>> surfaces) { releaseEGLContext(); if (surfaces == null || surfaces.size() == 0) { @@ -577,18 +563,20 @@ public class SurfaceTextureRenderer { return; } - for (Surface s : surfaces) { + for (Pair<Surface, Size> p : surfaces) { + Surface s = p.first; + Size surfaceSize = p.second; // If pixel conversions aren't handled by egl, use a pbuffer try { + EGLSurfaceHolder holder = new EGLSurfaceHolder(); + holder.surface = s; + holder.width = surfaceSize.getWidth(); + holder.height = surfaceSize.getHeight(); if (LegacyCameraDevice.needsConversion(s)) { // Always override to YV12 output for YUV surface formats. LegacyCameraDevice.setSurfaceFormat(s, ImageFormat.YV12); - EGLSurfaceHolder holder = new EGLSurfaceHolder(); - holder.surface = s; mConversionSurfaces.add(holder); } else { - EGLSurfaceHolder holder = new EGLSurfaceHolder(); - holder.surface = s; mSurfaces.add(holder); } } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) { @@ -672,10 +660,11 @@ public class SurfaceTextureRenderer { List<Long> targetSurfaceIds = LegacyCameraDevice.getSurfaceIds(targetSurfaces); for (EGLSurfaceHolder holder : mSurfaces) { if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) { - makeCurrent(holder.eglSurface); - try { + try{ LegacyCameraDevice.setSurfaceDimens(holder.surface, holder.width, holder.height); + makeCurrent(holder.eglSurface); + LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second); drawFrame(mSurfaceTexture, holder.width, holder.height); swapBuffers(holder.eglSurface); @@ -695,10 +684,11 @@ public class SurfaceTextureRenderer { try { int format = LegacyCameraDevice.detectSurfaceType(holder.surface); + LegacyCameraDevice.setSurfaceDimens(holder.surface, holder.width, + holder.height); LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second); LegacyCameraDevice.produceFrame(holder.surface, mPBufferPixels.array(), holder.width, holder.height, format); - swapBuffers(holder.eglSurface); } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) { Log.w(TAG, "Surface abandoned, dropping frame. ", e); } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 4215f20..7d5db85 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -37,6 +37,7 @@ import android.os.Messenger; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Settings; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.Log; @@ -100,7 +101,7 @@ public class ConnectivityManager { /** * Identical to {@link #CONNECTIVITY_ACTION} broadcast, but sent without any - * applicable {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}. + * historic {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}. * * @hide */ @@ -428,18 +429,6 @@ public class ConnectivityManager { public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI; /** - * Default value for {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY} in - * milliseconds. This was introduced because IPv6 routes seem to take a - * moment to settle - trying network activity before the routes are adjusted - * can lead to packets using the wrong interface or having the wrong IP address. - * This delay is a bit crude, but in the future hopefully we will have kernel - * notifications letting us know when it's safe to use the new network. - * - * @hide - */ - public static final int CONNECTIVITY_CHANGE_DELAY_DEFAULT = 3000; - - /** * @hide */ public final static int REQUEST_ID_UNSET = 0; @@ -1295,9 +1284,15 @@ public class ConnectivityManager { if (b != null) { try { ITelephony it = ITelephony.Stub.asInterface(b); - return it.getDataEnabled(); + int subId = SubscriptionManager.getDefaultDataSubId(); + Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId); + boolean retVal = it.getDataEnabled(subId); + Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId + + " retVal=" + retVal); + return retVal; } catch (RemoteException e) { } } + Log.d("ConnectivityManager", "getMobileDataEnabled()- remote exception retVal=false"); return false; } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 8021210..d9921a6 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -68,9 +68,6 @@ interface IConnectivityManager boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress); - /** Policy control over specific {@link NetworkStateTracker}. */ - void setPolicyDataEnable(int networkType, boolean enabled); - int tether(String iface); int untether(String iface); diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index b7b8731..2c3881c 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -40,8 +40,12 @@ interface INetworkStatsService { /** Mark given UID as being in foreground for stats purposes. */ void setUidForeground(int uid, boolean uidForeground); + + /** Force update of ifaces. */ + void forceUpdateIfaces(); /** Force update of statistics. */ void forceUpdate(); + /** Advise persistance threshold; may be overridden internally. */ void advisePersistThreshold(long thresholdBytes); diff --git a/core/java/android/net/LocalServerSocket.java b/core/java/android/net/LocalServerSocket.java index a36203b..9464222 100644 --- a/core/java/android/net/LocalServerSocket.java +++ b/core/java/android/net/LocalServerSocket.java @@ -20,12 +20,8 @@ import java.io.IOException; import java.io.FileDescriptor; /** - * non-standard class for creating inbound UNIX-domain socket - * on the Android platform, this is created in the Linux non-filesystem - * namespace. - * - * On simulator platforms, this may be created in a temporary directory on - * the filesystem + * Non-standard class for creating an inbound UNIX-domain socket + * in the Linux abstract namespace. */ public class LocalServerSocket { private final LocalSocketImpl impl; @@ -35,7 +31,7 @@ public class LocalServerSocket { private static final int LISTEN_BACKLOG = 50; /** - * Crewates a new server socket listening at specified name. + * Creates a new server socket listening at specified name. * On the Android platform, the name is created in the Linux * abstract namespace (instead of on the filesystem). * diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index d36707e..a9de23e 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -25,6 +25,7 @@ import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; import android.telephony.TelephonyManager; +import android.util.Slog; import java.util.Objects; @@ -35,10 +36,16 @@ import java.util.Objects; * @hide */ public class NetworkIdentity implements Comparable<NetworkIdentity> { + private static final String TAG = "NetworkIdentity"; + /** * When enabled, combine all {@link #mSubType} together under * {@link #SUBTYPE_COMBINED}. + * + * @deprecated we no longer offer to collect statistics on a per-subtype + * basis; this is always disabled. */ + @Deprecated public static final boolean COMBINE_SUBTYPE_ENABLED = true; public static final int SUBTYPE_COMBINED = -1; @@ -133,6 +140,18 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { } /** + * Scrub given IMSI on production builds. + */ + public static String[] scrubSubscriberId(String[] subscriberId) { + if (subscriberId == null) return null; + final String[] res = new String[subscriberId.length]; + for (int i = 0; i < res.length; i++) { + res[i] = NetworkIdentity.scrubSubscriberId(subscriberId[i]); + } + return res; + } + + /** * Build a {@link NetworkIdentity} from the given {@link NetworkState}, * assuming that any mobile networks are using the current IMSI. */ @@ -140,23 +159,18 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { final int type = state.networkInfo.getType(); final int subType = state.networkInfo.getSubtype(); - // TODO: consider moving subscriberId over to LinkCapabilities, so it - // comes from an authoritative source. - String subscriberId = null; String networkId = null; boolean roaming = false; if (isNetworkTypeMobile(type)) { - final TelephonyManager telephony = (TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE); - roaming = telephony.isNetworkRoaming(); - if (state.subscriberId != null) { - subscriberId = state.subscriberId; - } else { - subscriberId = telephony.getSubscriberId(); + if (state.subscriberId == null) { + Slog.w(TAG, "Active mobile network without subscriber!"); } + subscriberId = state.subscriberId; + roaming = state.networkInfo.isRoaming(); + } else if (type == TYPE_WIFI) { if (state.networkId != null) { networkId = state.networkId; diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java index 5d2a43d..b92c9e3 100644 --- a/core/java/android/net/NetworkMisc.java +++ b/core/java/android/net/NetworkMisc.java @@ -20,15 +20,18 @@ import android.os.Parcel; import android.os.Parcelable; /** - * A grab-bag of information (metadata, policies, properties, etc) about a {@link Network}. + * A grab-bag of information (metadata, policies, properties, etc) about a + * {@link Network}. Since this contains PII, it should not be sent outside the + * system. * * @hide */ public class NetworkMisc implements Parcelable { /** - * If the {@link Network} is a VPN, whether apps are allowed to bypass the VPN. This is set by - * a {@link VpnService} and used by {@link ConnectivityService} when creating a VPN. + * If the {@link Network} is a VPN, whether apps are allowed to bypass the + * VPN. This is set by a {@link VpnService} and used by + * {@link ConnectivityManager} when creating a VPN. */ public boolean allowBypass; @@ -41,6 +44,11 @@ public class NetworkMisc implements Parcelable { */ public boolean explicitlySelected; + /** + * For mobile networks, this is the subscriber ID (such as IMSI). + */ + public String subscriberId; + public NetworkMisc() { } @@ -48,6 +56,7 @@ public class NetworkMisc implements Parcelable { if (nm != null) { allowBypass = nm.allowBypass; explicitlySelected = nm.explicitlySelected; + subscriberId = nm.subscriberId; } } @@ -60,6 +69,7 @@ public class NetworkMisc implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeInt(allowBypass ? 1 : 0); out.writeInt(explicitlySelected ? 1 : 0); + out.writeString(subscriberId); } public static final Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() { @@ -68,6 +78,7 @@ public class NetworkMisc implements Parcelable { NetworkMisc networkMisc = new NetworkMisc(); networkMisc.allowBypass = in.readInt() != 0; networkMisc.explicitlySelected = in.readInt() != 0; + networkMisc.subscriberId = in.readString(); return networkMisc; } diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java index 10c686b..e88bc26 100644 --- a/core/java/android/net/NetworkPolicy.java +++ b/core/java/android/net/NetworkPolicy.java @@ -35,7 +35,7 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> { public static final long LIMIT_DISABLED = -1; public static final long SNOOZE_NEVER = -1; - public final NetworkTemplate template; + public NetworkTemplate template; public int cycleDay; public String cycleTimezone; public long warningBytes; diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java index d26c70d..933287f 100644 --- a/core/java/android/net/NetworkState.java +++ b/core/java/android/net/NetworkState.java @@ -30,16 +30,10 @@ public class NetworkState implements Parcelable { public final LinkProperties linkProperties; public final NetworkCapabilities networkCapabilities; public final Network network; - /** Currently only used by testing. */ public final String subscriberId; public final String networkId; public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties, - NetworkCapabilities networkCapabilities, Network network) { - this(networkInfo, linkProperties, networkCapabilities, network, null, null); - } - - public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, Network network, String subscriberId, String networkId) { this.networkInfo = networkInfo; @@ -85,5 +79,4 @@ public class NetworkState implements Parcelable { return new NetworkState[size]; } }; - } diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index b839e0a..57eef83 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -22,7 +22,6 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; -import static android.net.NetworkIdentity.scrubSubscriberId; import static android.net.wifi.WifiInfo.removeDoubleQuotes; import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; @@ -36,7 +35,9 @@ import android.os.Parcel; import android.os.Parcelable; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; +import java.util.Arrays; import java.util.Objects; /** @@ -48,7 +49,9 @@ import java.util.Objects; public class NetworkTemplate implements Parcelable { public static final int MATCH_MOBILE_ALL = 1; + @Deprecated public static final int MATCH_MOBILE_3G_LOWER = 2; + @Deprecated public static final int MATCH_MOBILE_4G = 3; public static final int MATCH_WIFI = 4; public static final int MATCH_ETHERNET = 5; @@ -146,17 +149,35 @@ public class NetworkTemplate implements Parcelable { private final int mMatchRule; private final String mSubscriberId; + + /** + * Ugh, templates are designed to target a single subscriber, but we might + * need to match several "merged" subscribers. These are the subscribers + * that should be considered to match this template. + * <p> + * Since the merge set is dynamic, it should <em>not</em> be persisted or + * used for determining equality. + */ + private final String[] mMatchSubscriberIds; + private final String mNetworkId; public NetworkTemplate(int matchRule, String subscriberId, String networkId) { + this(matchRule, subscriberId, new String[] { subscriberId }, networkId); + } + + public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, + String networkId) { mMatchRule = matchRule; mSubscriberId = subscriberId; + mMatchSubscriberIds = matchSubscriberIds; mNetworkId = networkId; } private NetworkTemplate(Parcel in) { mMatchRule = in.readInt(); mSubscriberId = in.readString(); + mMatchSubscriberIds = in.createStringArray(); mNetworkId = in.readString(); } @@ -164,6 +185,7 @@ public class NetworkTemplate implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mMatchRule); dest.writeString(mSubscriberId); + dest.writeStringArray(mMatchSubscriberIds); dest.writeString(mNetworkId); } @@ -177,7 +199,12 @@ public class NetworkTemplate implements Parcelable { final StringBuilder builder = new StringBuilder("NetworkTemplate: "); builder.append("matchRule=").append(getMatchRuleName(mMatchRule)); if (mSubscriberId != null) { - builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId)); + builder.append(", subscriberId=").append( + NetworkIdentity.scrubSubscriberId(mSubscriberId)); + } + if (mMatchSubscriberIds != null) { + builder.append(", matchSubscriberIds=").append( + Arrays.toString(NetworkIdentity.scrubSubscriberId(mMatchSubscriberIds))); } if (mNetworkId != null) { builder.append(", networkId=").append(mNetworkId); @@ -201,6 +228,18 @@ public class NetworkTemplate implements Parcelable { return false; } + public boolean isMatchRuleMobile() { + switch (mMatchRule) { + case MATCH_MOBILE_3G_LOWER: + case MATCH_MOBILE_4G: + case MATCH_MOBILE_ALL: + case MATCH_MOBILE_WILDCARD: + return true; + default: + return false; + } + } + public int getMatchRule() { return mMatchRule; } @@ -247,14 +286,16 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { - return ((sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType)) - && Objects.equals(mSubscriberId, ident.mSubscriberId)); + final boolean matchesType = (sForceAllNetworkTypes + || contains(DATA_USAGE_NETWORK_TYPES, ident.mType)); + return matchesType && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); } } /** * Check if mobile network classified 3G or lower with matching IMSI. */ + @Deprecated private boolean matchesMobile3gLower(NetworkIdentity ident) { ensureSubtypeAvailable(); if (ident.mType == TYPE_WIMAX) { @@ -273,6 +314,7 @@ public class NetworkTemplate implements Parcelable { /** * Check if mobile network classified 4G with matching IMSI. */ + @Deprecated private boolean matchesMobile4g(NetworkIdentity ident) { ensureSubtypeAvailable(); if (ident.mType == TYPE_WIMAX) { @@ -368,6 +410,27 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Examine the given template and normalize if it refers to a "merged" + * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * for key purposes, and expand the template to match all other merged + * subscribers. + * <p> + * For example, given an incoming template matching B, and the currently + * active merge set [A,B], we'd return a new template that primarily matches + * A, but also matches B. + */ + public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) { + if (template.isMatchRuleMobile() && ArrayUtils.contains(merged, template.mSubscriberId)) { + // Requested template subscriber is part of the merge group; return + // a template that matches all merged subscribers. + return new NetworkTemplate(template.mMatchRule, merged[0], merged, + template.mNetworkId); + } else { + return template; + } + } + public static final Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() { @Override public NetworkTemplate createFromParcel(Parcel in) { diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index 9589aac..1b02141 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -329,7 +329,7 @@ public class BaseBundle { * @param key a String, or null * @param value a Boolean, or null */ - void putBoolean(String key, boolean value) { + public void putBoolean(String key, boolean value) { unparcel(); mMap.put(key, value); } @@ -497,7 +497,7 @@ public class BaseBundle { * @param key a String, or null * @param value a boolean array object, or null */ - void putBooleanArray(String key, boolean[] value) { + public void putBooleanArray(String key, boolean[] value) { unparcel(); mMap.put(key, value); } @@ -617,7 +617,7 @@ public class BaseBundle { * @param key a String * @return a boolean value */ - boolean getBoolean(String key) { + public boolean getBoolean(String key) { unparcel(); if (DEBUG) Log.d(TAG, "Getting boolean in " + Integer.toHexString(System.identityHashCode(this))); @@ -654,7 +654,7 @@ public class BaseBundle { * @param defaultValue Value to return if key does not exist * @return a boolean value */ - boolean getBoolean(String key, boolean defaultValue) { + public boolean getBoolean(String key, boolean defaultValue) { unparcel(); Object o = mMap.get(key); if (o == null) { @@ -1072,7 +1072,7 @@ public class BaseBundle { * @param key a String, or null * @return a boolean[] value, or null */ - boolean[] getBooleanArray(String key) { + public boolean[] getBooleanArray(String key) { unparcel(); Object o = mMap.get(key); if (o == null) { diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index a9aa570..c5c5372 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -252,18 +252,6 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** - * Inserts a Boolean value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a Boolean, or null - */ - @Override - public void putBoolean(String key, boolean value) { - super.putBoolean(key, value); - } - - /** * Inserts a byte value into the mapping of this Bundle, replacing * any existing value for the given key. * @@ -460,18 +448,6 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** - * Inserts a boolean array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a boolean array object, or null - */ - @Override - public void putBooleanArray(String key, boolean[] value) { - super.putBooleanArray(key, value); - } - - /** * Inserts a byte array value into the mapping of this Bundle, replacing * any existing value for the given key. Either key or value may be null. * @@ -579,31 +555,6 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** - * Returns the value associated with the given key, or false if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @return a boolean value - */ - @Override - public boolean getBoolean(String key) { - return super.getBoolean(key); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return a boolean value - */ - @Override - public boolean getBoolean(String key, boolean defaultValue) { - return super.getBoolean(key, defaultValue); - } - - /** * Returns the value associated with the given key, or (byte) 0 if * no mapping of the desired type exists for the given key. * @@ -939,19 +890,6 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { * value is explicitly associated with the key. * * @param key a String, or null - * @return a boolean[] value, or null - */ - @Override - public boolean[] getBooleanArray(String key) { - return super.getBooleanArray(key); - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null * @return a byte[] value, or null */ @Override diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 3f42d25..a9deaf3 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -168,7 +168,7 @@ public final class Debug public static final int NUM_OTHER_STATS = 17; /** @hide */ - public static final int NUM_DVK_STATS = 5; + public static final int NUM_DVK_STATS = 8; /** @hide */ public static final int NUM_CATEGORIES = 7; @@ -314,6 +314,9 @@ public final class Debug case 19: return ".LinearAlloc"; case 20: return ".GC"; case 21: return ".JITCache"; + case 22: return ".Zygote"; + case 23: return ".NonMoving"; + case 24: return ".IndirectRef"; default: return "????"; } } @@ -1071,9 +1074,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Retrieves the PSS memory used by the process as given by the * smaps. Optionally supply a long array of 1 entry to also - * receive the uss of the process. @hide + * receive the uss of the process, and another array to also + * retrieve the separate memtrack size. @hide */ - public static native long getPss(int pid, long[] outUss); + public static native long getPss(int pid, long[] outUss, long[] outMemtrack); /** @hide */ public static final int MEMINFO_TOTAL = 0; diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java index c01f688..3a44428 100644 --- a/core/java/android/os/PersistableBundle.java +++ b/core/java/android/os/PersistableBundle.java @@ -96,7 +96,8 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa !(value instanceof Double) && !(value instanceof String) && !(value instanceof int[]) && !(value instanceof long[]) && !(value instanceof double[]) && !(value instanceof String[]) && - !(value instanceof PersistableBundle) && (value != null)) { + !(value instanceof PersistableBundle) && (value != null) && + !(value instanceof Boolean) && !(value instanceof boolean[])) { throw new IllegalArgumentException("Bad value in PersistableBundle key=" + key + " value=" + value); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 0062eb2..555f64c 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6128,7 +6128,7 @@ public final class Settings { /** * The number of milliseconds to delay before sending out - * {@link ConnectivityManager#CONNECTIVITY_ACTION} broadcasts. + * {@link ConnectivityManager#CONNECTIVITY_ACTION} broadcasts. Ignored. * * @hide */ diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index ce28d0a..979a01b 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -64,7 +64,7 @@ public class ZenModeConfig implements Parcelable { public static final int[] MINUTE_BUCKETS = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 }; private static final int SECONDS_MS = 1000; private static final int MINUTES_MS = 60 * SECONDS_MS; - private static final int ZERO_VALUE_MS = 20 * SECONDS_MS; + private static final int ZERO_VALUE_MS = 10 * SECONDS_MS; private static final boolean DEFAULT_ALLOW_EVENTS = true; @@ -471,6 +471,8 @@ public class ZenModeConfig implements Parcelable { downtime.startMinute = sleepStartMinute; downtime.endHour = sleepEndHour; downtime.endMinute = sleepEndMinute; + downtime.mode = sleepMode; + downtime.none = sleepNone; return downtime; } @@ -510,7 +512,7 @@ public class ZenModeConfig implements Parcelable { public static final String SYSTEM_AUTHORITY = "android"; // Built-in countdown conditions, e.g. condition://android/countdown/1399917958951 - private static final String COUNTDOWN_PATH = "countdown"; + public static final String COUNTDOWN_PATH = "countdown"; public static Uri toCountdownConditionId(long time) { return new Uri.Builder().scheme(Condition.SCHEME) @@ -536,8 +538,9 @@ public class ZenModeConfig implements Parcelable { return tryParseCountdownConditionId(conditionId) != 0; } - // Built-in downtime conditions, e.g. condition://android/downtime?start=10.00&end=7.00 - private static final String DOWNTIME_PATH = "downtime"; + // Built-in downtime conditions + // e.g. condition://android/downtime?start=10.00&end=7.00&mode=days%3A5%2C6&none=false + public static final String DOWNTIME_PATH = "downtime"; public static Uri toDowntimeConditionId(DowntimeInfo downtime) { return new Uri.Builder().scheme(Condition.SCHEME) @@ -545,6 +548,8 @@ public class ZenModeConfig implements Parcelable { .appendPath(DOWNTIME_PATH) .appendQueryParameter("start", downtime.startHour + "." + downtime.startMinute) .appendQueryParameter("end", downtime.endHour + "." + downtime.endMinute) + .appendQueryParameter("mode", downtime.mode) + .appendQueryParameter("none", Boolean.toString(downtime.none)) .build(); } @@ -562,6 +567,8 @@ public class ZenModeConfig implements Parcelable { downtime.startMinute = start[1]; downtime.endHour = end[0]; downtime.endMinute = end[1]; + downtime.mode = conditionId.getQueryParameter("mode"); + downtime.none = Boolean.toString(true).equals(conditionId.getQueryParameter("none")); return downtime; } @@ -583,6 +590,8 @@ public class ZenModeConfig implements Parcelable { public int startMinute; // 0-59 public int endHour; public int endMinute; + public String mode; + public boolean none; @Override public int hashCode() { @@ -596,7 +605,12 @@ public class ZenModeConfig implements Parcelable { return startHour == other.startHour && startMinute == other.startMinute && endHour == other.endHour - && endMinute == other.endMinute; + && endMinute == other.endMinute + && Objects.equals(mode, other.mode) + && none == other.none; } } + + // built-in next alarm conditions + public static final String NEXT_ALARM_PATH = "next_alarm"; } diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 67f632f..9496b53 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -691,8 +691,8 @@ public abstract class WallpaperService extends Service { if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface + ", frame=" + mWinFrame); - int w = mWinFrame.width() + mOverscanInsets.left + mOverscanInsets.right; - int h = mWinFrame.height() + mOverscanInsets.top + mOverscanInsets.bottom; + int w = mWinFrame.width(); + int h = mWinFrame.height(); if (!fixedSize) { final Rect padding = mIWallpaperEngine.mDisplayPadding; diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java index 7feca30..7b35a3b 100644 --- a/core/java/android/view/RenderNodeAnimator.java +++ b/core/java/android/view/RenderNodeAnimator.java @@ -148,6 +148,10 @@ public class RenderNodeAnimator extends Animator { if (mState != STATE_PREPARE) { throw new IllegalStateException("Animator has already started, cannot change it now!"); } + if (mNativePtr == null) { + throw new IllegalStateException("Animator's target has been destroyed " + + "(trying to modify an animation after activity destroy?)"); + } } static boolean isNativeInterpolator(TimeInterpolator interpolator) { @@ -180,7 +184,10 @@ public class RenderNodeAnimator extends Animator { mState = STATE_DELAYED; applyInterpolator(); - if (mStartDelay <= 0 || !mUiThreadHandlesDelay) { + if (mNativePtr == null) { + // It's dead, immediately cancel + cancel(); + } else if (mStartDelay <= 0 || !mUiThreadHandlesDelay) { nSetStartDelay(mNativePtr.get(), mStartDelay); doStart(); } else { @@ -208,7 +215,9 @@ public class RenderNodeAnimator extends Animator { private void moveToRunningState() { mState = STATE_RUNNING; - nStart(mNativePtr.get(), this); + if (mNativePtr != null) { + nStart(mNativePtr.get()); + } notifyStartListeners(); } @@ -227,7 +236,6 @@ public class RenderNodeAnimator extends Animator { getHelper().removeDelayedAnimation(this); moveToRunningState(); } - nEnd(mNativePtr.get()); final ArrayList<AnimatorListener> listeners = cloneListeners(); final int numListeners = listeners == null ? 0 : listeners.size(); @@ -235,10 +243,7 @@ public class RenderNodeAnimator extends Animator { listeners.get(i).onAnimationCancel(this); } - if (mViewTarget != null) { - // Kick off a frame to flush the state change - mViewTarget.invalidateViewProperty(true, false); - } + end(); } } @@ -249,10 +254,15 @@ public class RenderNodeAnimator extends Animator { getHelper().removeDelayedAnimation(this); doStart(); } - nEnd(mNativePtr.get()); - if (mViewTarget != null) { - // Kick off a frame to flush the state change - mViewTarget.invalidateViewProperty(true, false); + if (mNativePtr != null) { + nEnd(mNativePtr.get()); + if (mViewTarget != null) { + // Kick off a frame to flush the state change + mViewTarget.invalidateViewProperty(true, false); + } + } else { + // It's already dead, jump to onFinish + onFinished(); } } } @@ -281,9 +291,11 @@ public class RenderNodeAnimator extends Animator { } private void setTarget(RenderNode node) { + checkMutable(); if (mTarget != null) { throw new IllegalStateException("Target already set!"); } + nSetListener(mNativePtr.get(), this); mTarget = node; mTarget.addAnimator(this); } @@ -346,6 +358,12 @@ public class RenderNodeAnimator extends Animator { } protected void onFinished() { + if (mState == STATE_PREPARE) { + // Unlikely but possible, the native side has been destroyed + // before we have started. + releaseNativePtr(); + return; + } if (mState == STATE_DELAYED) { getHelper().removeDelayedAnimation(this); notifyStartListeners(); @@ -361,8 +379,14 @@ public class RenderNodeAnimator extends Animator { // Release the native object, as it has a global reference to us. This // breaks the cyclic reference chain, and allows this object to be // GC'd - mNativePtr.release(); - mNativePtr = null; + releaseNativePtr(); + } + + private void releaseNativePtr() { + if (mNativePtr != null) { + mNativePtr.release(); + mNativePtr = null; + } } @SuppressWarnings("unchecked") @@ -484,7 +508,8 @@ public class RenderNodeAnimator extends Animator { private static native void nSetStartDelay(long nativePtr, long startDelay); private static native void nSetInterpolator(long animPtr, long interpolatorPtr); private static native void nSetAllowRunningAsync(long animPtr, boolean mayRunAsync); + private static native void nSetListener(long animPtr, RenderNodeAnimator listener); - private static native void nStart(long animPtr, RenderNodeAnimator finishListener); + private static native void nStart(long animPtr); private static native void nEnd(long animPtr); } diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 14b950f..ad4a048 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -37,6 +37,7 @@ import android.view.View.AttachInfo; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.HashSet; /** @@ -465,11 +466,13 @@ public class ThreadedRenderer extends HardwareRenderer { final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables(); final int count = drawables.size(); + ArrayList<Bitmap> tmpList = new ArrayList<Bitmap>(); for (int i = 0; i < count; i++) { - final Bitmap bitmap = drawables.valueAt(i).getBitmap(); - if (bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888) { - preloadedPointers.add(bitmap.mNativeBitmap); + drawables.valueAt(i).addAtlasableBitmaps(tmpList); + for (int j = 0; j < tmpList.size(); j++) { + preloadedPointers.add(tmpList.get(j).mNativeBitmap); } + tmpList.clear(); } for (int i = 0; i < map.length; i += 4) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index b54d462..2bb1ebc 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -5938,9 +5938,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * layer. * * @param outRects List to which to add clickable areas. + * + * @hide */ - void addClickableRectsForAccessibility(List<RectF> outRects) { - if (isClickable() || isLongClickable()) { + public void addClickableRectsForAccessibility(List<RectF> outRects) { + if (isClickable() || isLongClickable() + || (mListenerInfo != null && mListenerInfo.mOnTouchListener != null)) { RectF bounds = new RectF(); bounds.set(0, 0, getWidth(), getHeight()); outRects.add(bounds); @@ -16059,7 +16062,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * This function is called whenever the view hotspot changes and needs to - * be propagated to drawables managed by the view. + * be propagated to drawables or child views managed by the view. + * <p> + * Dispatching to child views is handled by + * {@link #dispatchDrawableHotspotChanged(float, float)}. * <p> * Be sure to call through to the superclass when overriding this function. * @@ -16070,6 +16076,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mBackground != null) { mBackground.setHotspot(x, y); } + + dispatchDrawableHotspotChanged(x, y); + } + + /** + * Dispatches drawableHotspotChanged to all of this View's children. + * + * @param x hotspot x coordinate + * @param y hotspot y coordinate + * @see #drawableHotspotChanged(float, float) + */ + public void dispatchDrawableHotspotChanged(float x, float y) { } /** diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 1551504..25a70eb 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -161,6 +161,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // Used during drag dispatch private PointF mLocalPoint; + // Lazily-created holder for point computations. + private float[] mTempPoint; + // Layout animation private LayoutAnimationController mLayoutAnimationController; private Animation.AnimationListener mAnimationListener; @@ -880,8 +883,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return true; } + /** + * @hide + */ @Override - void addClickableRectsForAccessibility(List<RectF> outRects) { + public void addClickableRectsForAccessibility(List<RectF> outRects) { int sizeBefore = outRects.size(); super.addClickableRectsForAccessibility(outRects); @@ -2442,6 +2448,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager || child.getAnimation() != null; } + private float[] getTempPoint() { + if (mTempPoint == null) { + mTempPoint = new float[2]; + } + return mTempPoint; + } + /** * Returns true if a child view contains the specified point when transformed * into its coordinate space. @@ -2450,24 +2463,30 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager */ protected boolean isTransformedTouchPointInView(float x, float y, View child, PointF outLocalPoint) { - float localX = x + mScrollX - child.mLeft; - float localY = y + mScrollY - child.mTop; - if (! child.hasIdentityMatrix() && mAttachInfo != null) { - final float[] localXY = mAttachInfo.mTmpTransformLocation; - localXY[0] = localX; - localXY[1] = localY; - child.getInverseMatrix().mapPoints(localXY); - localX = localXY[0]; - localY = localXY[1]; - } - final boolean isInView = child.pointInView(localX, localY); + final float[] point = getTempPoint(); + point[0] = x; + point[1] = y; + transformPointToViewLocal(point, child); + final boolean isInView = child.pointInView(point[0], point[1]); if (isInView && outLocalPoint != null) { - outLocalPoint.set(localX, localY); + outLocalPoint.set(point[0], point[1]); } return isInView; } /** + * @hide + */ + public void transformPointToViewLocal(float[] point, View child) { + point[0] += mScrollX - child.mLeft; + point[1] += mScrollY - child.mTop; + + if (!child.hasIdentityMatrix()) { + child.getInverseMatrix().mapPoints(point); + } + } + + /** * Transforms a motion event into the coordinate space of a particular child view, * filters out irrelevant pointer ids, and overrides its action if necessary. * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead. @@ -3606,6 +3625,44 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } + /** + * Dispatches drawable hotspot changes to child views that meet at least + * one of the following criteria: + * <ul> + * <li>Returns {@code false} from both {@link View#isClickable()} and + * {@link View#isLongClickable()}</li> + * <li>Requests duplication of parent state via + * {@link View#setDuplicateParentStateEnabled(boolean)}</li> + * </ul> + * + * @param x hotspot x coordinate + * @param y hotspot y coordinate + * @see #drawableHotspotChanged(float, float) + */ + @Override + public void dispatchDrawableHotspotChanged(float x, float y) { + final int count = mChildrenCount; + if (count == 0) { + return; + } + + final View[] children = mChildren; + for (int i = 0; i < count; i++) { + final View child = children[i]; + // Children that are clickable on their own should not + // receive hotspots when their parent view does. + final boolean nonActionable = !child.isClickable() && !child.isLongClickable(); + final boolean duplicatesState = (child.mViewFlags & DUPLICATE_PARENT_STATE) != 0; + if (nonActionable || duplicatesState) { + final float[] point = getTempPoint(); + point[0] = x; + point[1] = y; + transformPointToViewLocal(point, child); + child.drawableHotspotChanged(point[0], point[1]); + } + } + } + @Override void dispatchCancelPendingInputEvents() { super.dispatchCancelPendingInputEvents(); @@ -5961,28 +6018,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } @Override - public void drawableHotspotChanged(float x, float y) { - super.drawableHotspotChanged(x, y); - - if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) { - if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) { - throw new IllegalStateException("addStateFromChildren cannot be enabled if a" - + " child has duplicateParentState set to true"); - } - - final View[] children = mChildren; - final int count = mChildrenCount; - - for (int i = 0; i < count; i++) { - final View child = children[i]; - if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) { - child.drawableHotspotChanged(x, y); - } - } - } - } - - @Override protected int[] onCreateDrawableState(int extraSpace) { if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) { return super.onCreateDrawableState(extraSpace); diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java index a218e4d..52912b1 100644 --- a/core/java/android/view/accessibility/AccessibilityCache.java +++ b/core/java/android/view/accessibility/AccessibilityCache.java @@ -78,6 +78,7 @@ final class AccessibilityCache { case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: case AccessibilityEvent.TYPE_VIEW_SELECTED: case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED: + case AccessibilityEvent.TYPE_VIEW_CLICKED: case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { refreshCachedNodeLocked(event.getWindowId(), event.getSourceNodeId()); } break; diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 6927660..d80ad6a 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; import android.graphics.Canvas; +import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.TransitionDrawable; @@ -611,6 +612,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te private final int[] mScrollOffset = new int[2]; private final int[] mScrollConsumed = new int[2]; + private final float[] mTmpPoint = new float[2]; + // Used for offsetting MotionEvents that we feed to the VelocityTracker. // In the future it would be nice to be able to give this to the VelocityTracker // directly, or alternatively put a VT into absolute-positioning mode that only @@ -2509,38 +2512,29 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * Positions the selector in a way that mimics touch. */ void positionSelectorLikeTouch(int position, View sel, float x, float y) { - positionSelectorLikeFocus(position, sel); - - if (mSelector != null && position != INVALID_POSITION) { - mSelector.setHotspot(x, y); - } + positionSelector(position, sel, true, x, y); } /** * Positions the selector in a way that mimics keyboard focus. */ void positionSelectorLikeFocus(int position, View sel) { - // If we're changing position, update the visibility since the selector - // is technically being detached from the previous selection. - final Drawable selector = mSelector; - final boolean manageState = selector != null && mSelectorPosition != position - && position != INVALID_POSITION; - if (manageState) { - selector.setVisible(false, false); - } - - positionSelector(position, sel); - - if (manageState) { + if (mSelector != null && mSelectorPosition != position && position != INVALID_POSITION) { final Rect bounds = mSelectorRect; final float x = bounds.exactCenterX(); final float y = bounds.exactCenterY(); - selector.setVisible(getVisibility() == VISIBLE, false); - selector.setHotspot(x, y); + positionSelector(position, sel, true, x, y); + } else { + positionSelector(position, sel); } } void positionSelector(int position, View sel) { + positionSelector(position, sel, false, -1, -1); + } + + private void positionSelector(int position, View sel, boolean manageHotspot, float x, float y) { + final boolean positionChanged = position != mSelectorPosition; if (position != INVALID_POSITION) { mSelectorPosition = position; } @@ -2560,7 +2554,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te // Update the selector drawable. final Drawable selector = mSelector; if (selector != null) { + if (positionChanged) { + // Wipe out the current selector state so that we can start + // over in the new position with a fresh state. + selector.setVisible(false, false); + selector.setState(StateSet.NOTHING); + } selector.setBounds(selectorRect); + if (positionChanged) { + if (getVisibility() == VISIBLE) { + selector.setVisible(true, false); + } + selector.setState(getDrawableState()); + } + if (manageHotspot) { + selector.setHotspot(x, y); + } } final boolean isChildViewEnabled = mIsChildViewEnabled; @@ -3198,6 +3207,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te // get the selector in the right state, but we don't want to press each child. } + @Override + public void dispatchDrawableHotspotChanged(float x, float y) { + // Don't dispatch hotspot changes to children. We'll manually handle + // calling drawableHotspotChanged on the correct child. + } + /** * Maps a point to a position in the list. * @@ -3256,6 +3271,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mLayoutMode = LAYOUT_NORMAL; if (!mDataChanged) { + final float[] point = mTmpPoint; + point[0] = x; + point[1] = y; + transformPointToViewLocal(point, child); + child.drawableHotspotChanged(point[0], point[1]); child.setPressed(true); setPressed(true); layoutChildren(); @@ -3756,10 +3776,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } // Otherwise, check containment within list bounds. If we're // outside bounds, cancel any active presses. + final View motionView = getChildAt(mMotionPosition - mFirstPosition); final float x = ev.getX(pointerIndex); if (!pointInView(x, y, mTouchSlop)) { setPressed(false); - final View motionView = getChildAt(mMotionPosition - mFirstPosition); if (motionView != null) { motionView.setPressed(false); } @@ -3767,6 +3787,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mPendingCheckForTap : mPendingCheckForLongPress); mTouchMode = TOUCH_MODE_DONE_WAITING; updateSelectorState(); + } else if (motionView != null) { + // Still within bounds, update the hotspot. + final float[] point = mTmpPoint; + point[0] = x; + point[1] = y; + transformPointToViewLocal(point, motionView); + motionView.drawableHotspotChanged(point[0], point[1]); } break; case TOUCH_MODE_SCROLL: @@ -6416,6 +6443,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te // Note: We do place AdapterView.ITEM_VIEW_TYPE_IGNORE in active views. // However, we will NOT place them into scrap views. activeViews[i] = child; + // Remember the position so that setupChild() doesn't reset state. + lp.scrappedFromPosition = firstActivePosition + i; } } } diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index 0c65c50..371b480 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; +import android.graphics.RectF; import android.os.Build; import android.os.Bundle; import android.os.Parcel; @@ -757,10 +758,22 @@ public class HorizontalScrollView extends FrameLayout { } else { super.scrollTo(scrollX, scrollY); } - + awakenScrollBars(); } + /** + * @hide + */ + @Override + public void addClickableRectsForAccessibility(List<RectF> outRects) { + // This class always consumes touch events, therefore if it + // covers a view we do not want to send a click over it. + RectF bounds = new RectF(); + bounds.set(0, 0, getWidth(), getHeight()); + outRects.add(bounds); + } + @Override public boolean performAccessibilityAction(int action, Bundle arguments) { if (super.performAccessibilityAction(action, arguments)) { diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index a31d37e..fe8b08b 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -1385,7 +1385,9 @@ public class ListPopupWindow { clearCallbacks(); final View src = mSrc; - if (!src.isEnabled()) { + if (!src.isEnabled() || src.isLongClickable()) { + // Ignore long-press if the view is disabled or has its own + // handler. return; } @@ -1394,12 +1396,12 @@ public class ListPopupWindow { } // Don't let the parent intercept our events. - mSrc.getParent().requestDisallowInterceptTouchEvent(true); + src.getParent().requestDisallowInterceptTouchEvent(true); // Make sure we cancel any ongoing source event stream. final long now = SystemClock.uptimeMillis(); final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0); - mSrc.onTouchEvent(e); + src.onTouchEvent(e); e.recycle(); mForwarding = true; diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java index 04b5616..75c6184 100644 --- a/core/java/android/widget/RadialTimePickerView.java +++ b/core/java/android/widget/RadialTimePickerView.java @@ -1246,37 +1246,40 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { } final int[] selectionDegrees = mSelectionDegrees; - int type = -1; - int newValue = -1; + final int type; + final int newValue; + final boolean valueChanged; if (mShowHours) { final int snapDegrees = snapOnly30s(degrees, 0) % 360; - if (forceSelection - || selectionDegrees[HOURS] != snapDegrees + valueChanged = selectionDegrees[HOURS] != snapDegrees || selectionDegrees[HOURS_INNER] != snapDegrees - || wasOnInnerCircle != mIsOnInnerCircle) { - selectionDegrees[HOURS] = snapDegrees; - selectionDegrees[HOURS_INNER] = snapDegrees; + || wasOnInnerCircle != mIsOnInnerCircle; - type = HOURS; - newValue = getCurrentHour(); - } + selectionDegrees[HOURS] = snapDegrees; + selectionDegrees[HOURS_INNER] = snapDegrees; + type = HOURS; + newValue = getCurrentHour(); } else { final int snapDegrees = snapPrefer30s(degrees) % 360; - if (forceSelection || selectionDegrees[MINUTES] != snapDegrees) { - selectionDegrees[MINUTES] = snapDegrees; + valueChanged = selectionDegrees[MINUTES] != snapDegrees; - type = MINUTES; - newValue = getCurrentMinute(); - } + selectionDegrees[MINUTES] = snapDegrees; + type = MINUTES; + newValue = getCurrentMinute(); } - if (newValue != -1) { + if (valueChanged || forceSelection || autoAdvance) { + // Fire the listener even if we just need to auto-advance. if (mListener != null) { mListener.onValueSelected(type, newValue, autoAdvance); } - performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); - invalidate(); + + // Only provide feedback if the value actually changed. + if (valueChanged || forceSelection) { + performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); + invalidate(); + } return true; } diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index 4c8aa51..7a22224 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -689,6 +689,10 @@ public class Switch extends CompoundButton { * @return true if (x, y) is within the target area of the switch thumb */ private boolean hitThumb(float x, float y) { + if (mThumbDrawable == null) { + return false; + } + // Relies on mTempRect, MUST be called first! final int thumbOffset = getThumbOffset(); diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index 8e786da..f908fcb 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -128,6 +128,20 @@ public class ArrayUtils } /** + * Checks if given array is null or has zero elements. + */ + public static boolean isEmpty(int[] array) { + return array == null || array.length == 0; + } + + /** + * Checks if given array is null or has zero elements. + */ + public static boolean isEmpty(long[] array) { + return array == null || array.length == 0; + } + + /** * Checks that value is present as at least one of the elements of the array. * @param array the array to check in * @param value the value to check for @@ -157,6 +171,7 @@ public class ArrayUtils * Test if all {@code check} items are contained in {@code array}. */ public static <T> boolean containsAll(T[] array, T[] check) { + if (check == null) return true; for (T checkItem : check) { if (!contains(array, checkItem)) { return false; diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java index e9baaa8..2bd607c 100644 --- a/core/java/com/android/internal/util/XmlUtils.java +++ b/core/java/com/android/internal/util/XmlUtils.java @@ -520,7 +520,7 @@ public class XmlUtils { * Flatten a String[] into an XmlSerializer. The list can later be read back * with readThisStringArrayXml(). * - * @param val The long array to be flattened. + * @param val The String array to be flattened. * @param name Name attribute to include with this array's tag, or null for * none. * @param out XmlSerializer to write the array into. @@ -556,6 +556,45 @@ public class XmlUtils { } /** + * Flatten a boolean[] into an XmlSerializer. The list can later be read back + * with readThisBooleanArrayXml(). + * + * @param val The boolean array to be flattened. + * @param name Name attribute to include with this array's tag, or null for + * none. + * @param out XmlSerializer to write the array into. + * + * @see #writeMapXml + * @see #writeValueXml + * @see #readThisIntArrayXml + */ + public static final void writeBooleanArrayXml(boolean[] val, String name, XmlSerializer out) + throws XmlPullParserException, java.io.IOException { + + if (val == null) { + out.startTag(null, "null"); + out.endTag(null, "null"); + return; + } + + out.startTag(null, "boolean-array"); + if (name != null) { + out.attribute(null, "name", name); + } + + final int N = val.length; + out.attribute(null, "num", Integer.toString(N)); + + for (int i=0; i<N; i++) { + out.startTag(null, "item"); + out.attribute(null, "value", Boolean.toString(val[i])); + out.endTag(null, "item"); + } + + out.endTag(null, "boolean-array"); + } + + /** * Flatten an object's value into an XmlSerializer. The value can later * be read back with readThisValueXml(). * @@ -636,6 +675,9 @@ public class XmlUtils { } else if (v instanceof String[]) { writeStringArrayXml((String[])v, name, out); return; + } else if (v instanceof boolean[]) { + writeBooleanArrayXml((boolean[])v, name, out); + return; } else if (v instanceof Map) { writeMapXml((Map)v, name, out); return; @@ -1169,6 +1211,66 @@ public class XmlUtils { } /** + * Read a boolean[] object from an XmlPullParser. The XML data could + * previously have been generated by writeBooleanArrayXml(). The XmlPullParser + * must be positioned <em>after</em> the tag that begins the list. + * + * @param parser The XmlPullParser from which to read the list data. + * @param endTag Name of the tag that will end the list, usually "string-array". + * @param name An array of one string, used to return the name attribute + * of the list's tag. + * + * @return Returns a newly generated boolean[]. + * + * @see #readListXml + */ + public static final boolean[] readThisBooleanArrayXml(XmlPullParser parser, String endTag, + String[] name) throws XmlPullParserException, java.io.IOException { + + int num; + try { + num = Integer.parseInt(parser.getAttributeValue(null, "num")); + } catch (NullPointerException e) { + throw new XmlPullParserException("Need num attribute in string-array"); + } catch (NumberFormatException e) { + throw new XmlPullParserException("Not a number in num attribute in string-array"); + } + parser.next(); + + boolean[] array = new boolean[num]; + int i = 0; + + int eventType = parser.getEventType(); + do { + if (eventType == parser.START_TAG) { + if (parser.getName().equals("item")) { + try { + array[i] = Boolean.valueOf(parser.getAttributeValue(null, "value")); + } catch (NullPointerException e) { + throw new XmlPullParserException("Need value attribute in item"); + } catch (NumberFormatException e) { + throw new XmlPullParserException("Not a number in value attribute in item"); + } + } else { + throw new XmlPullParserException("Expected item tag at: " + parser.getName()); + } + } else if (eventType == parser.END_TAG) { + if (parser.getName().equals(endTag)) { + return array; + } else if (parser.getName().equals("item")) { + i++; + } else { + throw new XmlPullParserException("Expected " + endTag + " end tag at: " + + parser.getName()); + } + } + eventType = parser.next(); + } while (eventType != parser.END_DOCUMENT); + + throw new XmlPullParserException("Document ended before " + endTag + " end tag"); + } + + /** * Read a flattened object from an XmlPullParser. The XML data could * previously have been written with writeMapXml(), writeListXml(), or * writeValueXml(). The XmlPullParser must be positioned <em>at</em> the @@ -1259,6 +1361,11 @@ public class XmlUtils { name[0] = valueName; //System.out.println("Returning value for " + valueName + ": " + res); return res; + } else if (tagName.equals("boolean-array")) { + res = readThisBooleanArrayXml(parser, "boolean-array", name); + name[0] = valueName; + //System.out.println("Returning value for " + valueName + ": " + res); + return res; } else if (tagName.equals("map")) { parser.next(); res = readThisMapXml(parser, "map", name); diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java index d39bf07..155f5d3 100644 --- a/core/java/com/android/server/BootReceiver.java +++ b/core/java/com/android/server/BootReceiver.java @@ -142,6 +142,8 @@ public class BootReceiver extends BroadcastReceiver { "SYSTEM_LAST_KMSG"); addFileToDropBox(db, prefs, headers, "/cache/recovery/log", -LOG_SIZE, "SYSTEM_RECOVERY_LOG"); + addFileToDropBox(db, prefs, headers, "/cache/recovery/last_kmsg", + -LOG_SIZE, "SYSTEM_RECOVERY_KMSG"); addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_console", -LOG_SIZE, "APANIC_CONSOLE"); addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_threads", diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp index 8440a0e..b44c829 100644 --- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp +++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp @@ -470,6 +470,26 @@ static jint LegacyCameraDevice_nativeDetectSurfaceDimens(JNIEnv* env, jobject th return NO_ERROR; } +static jint LegacyCameraDevice_nativeDetectSurfaceUsageFlags(JNIEnv* env, jobject thiz, + jobject surface) { + ALOGV("nativeDetectSurfaceUsageFlags"); + + sp<ANativeWindow> anw; + if ((anw = getNativeWindow(env, surface)) == NULL) { + jniThrowException(env, "Ljava/lang/UnsupportedOperationException;", + "Could not retrieve native window from surface."); + return BAD_VALUE; + } + int32_t usage = 0; + status_t err = anw->query(anw.get(), NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage); + if(err != NO_ERROR) { + jniThrowException(env, "Ljava/lang/UnsupportedOperationException;", + "Error while querying surface usage bits"); + return err; + } + return usage; +} + static jint LegacyCameraDevice_nativeDetectTextureDimens(JNIEnv* env, jobject thiz, jobject surfaceTexture, jintArray dimens) { ALOGV("nativeDetectTextureDimens"); @@ -713,6 +733,9 @@ static JNINativeMethod gCameraDeviceMethods[] = { { "nativeGetJpegFooterSize", "()I", (void *)LegacyCameraDevice_nativeGetJpegFooterSize }, + { "nativeDetectSurfaceUsageFlags", + "(Landroid/view/Surface;)I", + (void *)LegacyCameraDevice_nativeDetectSurfaceUsageFlags }, }; // Get all the required offsets in java class and register native functions diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index cabe200..fee1ead 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -25,6 +25,7 @@ #include <android_runtime/AndroidRuntime.h> #include <media/AudioSystem.h> +#include <media/AudioPolicy.h> #include <system/audio.h> #include <system/audio_policy.h> @@ -40,6 +41,7 @@ static const char* const kClassPathName = "android/media/AudioSystem"; static jclass gArrayListClass; static struct { jmethodID add; + jmethodID toArray; } gArrayListMethods; static jclass gAudioHandleClass; @@ -102,6 +104,42 @@ static struct { // other fields unused by JNI } gAudioPatchFields; +static jclass gAudioMixClass; +static struct { + jfieldID mRule; + jfieldID mFormat; + jfieldID mRouteFlags; + jfieldID mRegistrationId; + jfieldID mMixType; +} gAudioMixFields; + +static jclass gAudioFormatClass; +static struct { + jfieldID mEncoding; + jfieldID mSampleRate; + jfieldID mChannelMask; + // other fields unused by JNI +} gAudioFormatFields; + +static jclass gAudioMixingRuleClass; +static struct { + jfieldID mCriteria; + // other fields unused by JNI +} gAudioMixingRuleFields; + +static jclass gAttributeMatchCriterionClass; +static struct { + jfieldID mAttr; + jfieldID mRule; +} gAttributeMatchCriterionFields; + +static jclass gAudioAttributesClass; +static struct { + jfieldID mUsage; + jfieldID mSource; +} gAudioAttributesFields; + + static const char* const kEventHandlerClassPathName = "android/media/AudioPortEventHandler"; static jmethodID gPostEventFromNative; @@ -1322,6 +1360,128 @@ android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv *env, jobject thiz, ji return (jint)AudioSystem::getAudioHwSyncForSession((audio_session_t)sessionId); } + + + +static jint convertAudioMixToNative(JNIEnv *env, + AudioMix *nAudioMix, + const jobject jAudioMix) +{ + nAudioMix->mMixType = env->GetIntField(jAudioMix, gAudioMixFields.mMixType); + nAudioMix->mRouteFlags = env->GetIntField(jAudioMix, gAudioMixFields.mRouteFlags); + + jstring jRegistrationId = (jstring)env->GetObjectField(jAudioMix, + gAudioMixFields.mRegistrationId); + const char *nRegistrationId = env->GetStringUTFChars(jRegistrationId, NULL); + nAudioMix->mRegistrationId = String8(nRegistrationId); + env->ReleaseStringUTFChars(jRegistrationId, nRegistrationId); + env->DeleteLocalRef(jRegistrationId); + + jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat); + nAudioMix->mFormat.sample_rate = env->GetIntField(jFormat, + gAudioFormatFields.mSampleRate); + nAudioMix->mFormat.channel_mask = outChannelMaskToNative(env->GetIntField(jFormat, + gAudioFormatFields.mChannelMask)); + nAudioMix->mFormat.format = audioFormatToNative(env->GetIntField(jFormat, + gAudioFormatFields.mEncoding)); + env->DeleteLocalRef(jFormat); + + jobject jRule = env->GetObjectField(jAudioMix, gAudioMixFields.mRule); + jobject jRuleCriteria = env->GetObjectField(jRule, gAudioMixingRuleFields.mCriteria); + env->DeleteLocalRef(jRule); + jobjectArray jCriteria = (jobjectArray)env->CallObjectMethod(jRuleCriteria, + gArrayListMethods.toArray); + env->DeleteLocalRef(jRuleCriteria); + + jint numCriteria = env->GetArrayLength(jCriteria); + if (numCriteria > MAX_CRITERIA_PER_MIX) { + numCriteria = MAX_CRITERIA_PER_MIX; + } + + for (jint i = 0; i < numCriteria; i++) { + AttributeMatchCriterion nCriterion; + + jobject jCriterion = env->GetObjectArrayElement(jCriteria, i); + + nCriterion.mRule = env->GetIntField(jCriterion, gAttributeMatchCriterionFields.mRule); + + jobject jAttributes = env->GetObjectField(jCriterion, gAttributeMatchCriterionFields.mAttr); + if (nCriterion.mRule == RULE_MATCH_ATTRIBUTE_USAGE || + nCriterion.mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) { + nCriterion.mAttr.mUsage = (audio_usage_t)env->GetIntField(jAttributes, + gAudioAttributesFields.mUsage); + } else { + nCriterion.mAttr.mSource = (audio_source_t)env->GetIntField(jAttributes, + gAudioAttributesFields.mSource); + } + env->DeleteLocalRef(jAttributes); + + nAudioMix->mCriteria.add(nCriterion); + env->DeleteLocalRef(jCriterion); + } + + env->DeleteLocalRef(jCriteria); + + return (jint)AUDIO_JAVA_SUCCESS; +} + +static jint +android_media_AudioSystem_registerPolicyMixes(JNIEnv *env, jobject clazz, + jobject jMixesList, jboolean registration) +{ + ALOGV("registerPolicyMixes"); + + if (jMixesList == NULL) { + return (jint)AUDIO_JAVA_BAD_VALUE; + } + if (!env->IsInstanceOf(jMixesList, gArrayListClass)) { + return (jint)AUDIO_JAVA_BAD_VALUE; + } + jobjectArray jMixes = (jobjectArray)env->CallObjectMethod(jMixesList, + gArrayListMethods.toArray); + jint numMixes = env->GetArrayLength(jMixes); + if (numMixes > MAX_MIXES_PER_POLICY) { + numMixes = MAX_MIXES_PER_POLICY; + } + + status_t status; + jint jStatus; + jobject jAudioMix = NULL; + Vector <AudioMix> mixes; + for (jint i = 0; i < numMixes; i++) { + jAudioMix = env->GetObjectArrayElement(jMixes, i); + if (!env->IsInstanceOf(jAudioMix, gAudioMixClass)) { + jStatus = (jint)AUDIO_JAVA_BAD_VALUE; + goto exit; + } + AudioMix mix; + jStatus = convertAudioMixToNative(env, &mix, jAudioMix); + env->DeleteLocalRef(jAudioMix); + jAudioMix = NULL; + if (jStatus != AUDIO_JAVA_SUCCESS) { + goto exit; + } + mixes.add(mix); + } + + ALOGV("AudioSystem::registerPolicyMixes numMixes %d registration %d", numMixes, registration); + status = AudioSystem::registerPolicyMixes(mixes, registration); + ALOGV("AudioSystem::registerPolicyMixes() returned %d", status); + + jStatus = nativeToJavaStatus(status); + if (jStatus != AUDIO_JAVA_SUCCESS) { + goto exit; + } + +exit: + if (jAudioMix != NULL) { + env->DeleteLocalRef(jAudioMix); + } + return jStatus; +} + + + // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = { @@ -1363,6 +1523,9 @@ static JNINativeMethod gMethods[] = { (void *)android_media_AudioSystem_setAudioPortConfig}, {"getAudioHwSyncForSession", "(I)I", (void *)android_media_AudioSystem_getAudioHwSyncForSession}, + {"registerPolicyMixes", "(Ljava/util/ArrayList;Z)I", + (void *)android_media_AudioSystem_registerPolicyMixes}, + }; @@ -1381,6 +1544,7 @@ int register_android_media_AudioSystem(JNIEnv *env) jclass arrayListClass = env->FindClass("java/util/ArrayList"); gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass); gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z"); + gArrayListMethods.toArray = env->GetMethodID(arrayListClass, "toArray", "()[Ljava/lang/Object;"); jclass audioHandleClass = env->FindClass("android/media/AudioHandle"); gAudioHandleClass = (jclass) env->NewGlobalRef(audioHandleClass); @@ -1462,6 +1626,41 @@ int register_android_media_AudioSystem(JNIEnv *env) "(Ljava/lang/Object;IIILjava/lang/Object;)V"); + jclass audioMixClass = env->FindClass("android/media/audiopolicy/AudioMix"); + gAudioMixClass = (jclass) env->NewGlobalRef(audioMixClass); + gAudioMixFields.mRule = env->GetFieldID(audioMixClass, "mRule", + "Landroid/media/audiopolicy/AudioMixingRule;"); + gAudioMixFields.mFormat = env->GetFieldID(audioMixClass, "mFormat", + "Landroid/media/AudioFormat;"); + gAudioMixFields.mRouteFlags = env->GetFieldID(audioMixClass, "mRouteFlags", "I"); + gAudioMixFields.mRegistrationId = env->GetFieldID(audioMixClass, "mRegistrationId", + "Ljava/lang/String;"); + gAudioMixFields.mMixType = env->GetFieldID(audioMixClass, "mMixType", "I"); + + jclass audioFormatClass = env->FindClass("android/media/AudioFormat"); + gAudioFormatClass = (jclass) env->NewGlobalRef(audioFormatClass); + gAudioFormatFields.mEncoding = env->GetFieldID(audioFormatClass, "mEncoding", "I"); + gAudioFormatFields.mSampleRate = env->GetFieldID(audioFormatClass, "mSampleRate", "I"); + gAudioFormatFields.mChannelMask = env->GetFieldID(audioFormatClass, "mChannelMask", "I"); + + jclass audioMixingRuleClass = env->FindClass("android/media/audiopolicy/AudioMixingRule"); + gAudioMixingRuleClass = (jclass) env->NewGlobalRef(audioMixingRuleClass); + gAudioMixingRuleFields.mCriteria = env->GetFieldID(audioMixingRuleClass, "mCriteria", + "Ljava/util/ArrayList;"); + + jclass attributeMatchCriterionClass = + env->FindClass("android/media/audiopolicy/AudioMixingRule$AttributeMatchCriterion"); + gAttributeMatchCriterionClass = (jclass) env->NewGlobalRef(attributeMatchCriterionClass); + gAttributeMatchCriterionFields.mAttr = env->GetFieldID(attributeMatchCriterionClass, "mAttr", + "Landroid/media/AudioAttributes;"); + gAttributeMatchCriterionFields.mRule = env->GetFieldID(attributeMatchCriterionClass, "mRule", + "I"); + + jclass audioAttributesClass = env->FindClass("android/media/AudioAttributes"); + gAudioAttributesClass = (jclass) env->NewGlobalRef(audioAttributesClass); + gAudioAttributesFields.mUsage = env->GetFieldID(audioAttributesClass, "mUsage", "I"); + gAudioAttributesFields.mSource = env->GetFieldID(audioAttributesClass, "mSource", "I"); + AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback); int status = AndroidRuntime::registerNativeMethods(env, diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index e572d22..5a32718 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -70,6 +70,9 @@ enum { HEAP_DALVIK_LINEARALLOC, HEAP_DALVIK_ACCOUNTING, HEAP_DALVIK_CODE_CACHE, + HEAP_DALVIK_ZYGOTE, + HEAP_DALVIK_NON_MOVING, + HEAP_DALVIK_INDIRECT_REFERENCE_TABLE, _NUM_HEAP, _NUM_EXCLUSIVE_HEAP = HEAP_OTHER_MEMTRACK+1, @@ -274,15 +277,21 @@ static void read_mapinfo(FILE *fp, stats_t* stats) if (strstr(name, "/dev/ashmem/dalvik-LinearAlloc") == name) { subHeap = HEAP_DALVIK_LINEARALLOC; } else if ((strstr(name, "/dev/ashmem/dalvik-alloc space") == name) || - (strstr(name, "/dev/ashmem/dalvik-main space") == name) || - (strstr(name, "/dev/ashmem/dalvik-zygote space") == name) || - (strstr(name, "/dev/ashmem/dalvik-non moving space") == name)) { + (strstr(name, "/dev/ashmem/dalvik-main space") == name)) { // This is the regular Dalvik heap. whichHeap = HEAP_DALVIK; subHeap = HEAP_DALVIK_NORMAL; } else if (strstr(name, "/dev/ashmem/dalvik-large object space") == name) { whichHeap = HEAP_DALVIK; subHeap = HEAP_DALVIK_LARGE; + } else if (strstr(name, "/dev/ashmem/dalvik-non moving space") == name) { + whichHeap = HEAP_DALVIK; + subHeap = HEAP_DALVIK_NON_MOVING; + } else if (strstr(name, "/dev/ashmem/dalvik-zygote space") == name) { + whichHeap = HEAP_DALVIK; + subHeap = HEAP_DALVIK_ZYGOTE; + } else if (strstr(name, "/dev/ashmem/dalvik-indirect ref") == name) { + subHeap = HEAP_DALVIK_INDIRECT_REFERENCE_TABLE; } else if (strstr(name, "/dev/ashmem/dalvik-jit-code-cache") == name) { subHeap = HEAP_DALVIK_CODE_CACHE; } else { @@ -486,11 +495,13 @@ static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject o android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object); } -static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jlongArray outUss) +static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jlongArray outUss, + jlongArray outMemtrack) { char line[1024]; jlong pss = 0; jlong uss = 0; + jlong memtrack = 0; unsigned temp; char tmp[128]; @@ -498,7 +509,7 @@ static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jl struct graphics_memory_pss graphics_mem; if (read_memtrack_memory(pid, &graphics_mem) == 0) { - pss = uss = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other; + pss = uss = memtrack = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other; } sprintf(tmp, "/proc/%d/smaps", pid); @@ -541,12 +552,22 @@ static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jl } } + if (outMemtrack != NULL) { + if (env->GetArrayLength(outMemtrack) >= 1) { + jlong* outMemtrackArray = env->GetLongArrayElements(outMemtrack, 0); + if (outMemtrackArray != NULL) { + outMemtrackArray[0] = memtrack; + } + env->ReleaseLongArrayElements(outMemtrack, outMemtrackArray, 0); + } + } + return pss; } static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz) { - return android_os_Debug_getPssPid(env, clazz, getpid(), NULL); + return android_os_Debug_getPssPid(env, clazz, getpid(), NULL, NULL); } enum { @@ -954,7 +975,7 @@ static JNINativeMethod gMethods[] = { (void*) android_os_Debug_getDirtyPagesPid }, { "getPss", "()J", (void*) android_os_Debug_getPss }, - { "getPss", "(I[J)J", + { "getPss", "(I[J[J)J", (void*) android_os_Debug_getPssPid }, { "getMemInfo", "([J)V", (void*) android_os_Debug_getMemInfo }, diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp index 311882d..eb56639 100644 --- a/core/jni/android_view_RenderNodeAnimator.cpp +++ b/core/jni/android_view_RenderNodeAnimator.cpp @@ -177,9 +177,13 @@ static void setAllowRunningAsync(JNIEnv* env, jobject clazz, jlong animatorPtr, animator->setAllowRunningAsync(mayRunAsync); } -static void start(JNIEnv* env, jobject clazz, jlong animatorPtr, jobject finishListener) { +static void setListener(JNIEnv* env, jobject clazz, jlong animatorPtr, jobject finishListener) { BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr); animator->setListener(new AnimationListenerBridge(env, finishListener)); +} + +static void start(JNIEnv* env, jobject clazz, jlong animatorPtr) { + BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr); animator->start(); } @@ -208,7 +212,8 @@ static JNINativeMethod gMethods[] = { { "nSetStartDelay", "(JJ)V", (void*) setStartDelay }, { "nSetInterpolator", "(JJ)V", (void*) setInterpolator }, { "nSetAllowRunningAsync", "(JZ)V", (void*) setAllowRunningAsync }, - { "nStart", "(JLandroid/view/RenderNodeAnimator;)V", (void*) start }, + { "nSetListener", "(JLandroid/view/RenderNodeAnimator;)V", (void*) setListener}, + { "nStart", "(J)V", (void*) start}, { "nEnd", "(J)V", (void*) end }, #endif }; diff --git a/core/res/res/drawable-hdpi/textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/textfield_activated_mtrl_alpha.9.png Binary files differindex b9a81be..9501e7c 100644 --- a/core/res/res/drawable-hdpi/textfield_activated_mtrl_alpha.9.png +++ b/core/res/res/drawable-hdpi/textfield_activated_mtrl_alpha.9.png diff --git a/core/res/res/drawable-hdpi/textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/textfield_default_mtrl_alpha.9.png Binary files differindex 3682629..de5572d 100644 --- a/core/res/res/drawable-hdpi/textfield_default_mtrl_alpha.9.png +++ b/core/res/res/drawable-hdpi/textfield_default_mtrl_alpha.9.png diff --git a/core/res/res/drawable-ldpi/ab_solid_shadow_mtrl.9.png b/core/res/res/drawable-ldpi/ab_solid_shadow_mtrl.9.png Binary files differdeleted file mode 100644 index 098a315..0000000 --- a/core/res/res/drawable-ldpi/ab_solid_shadow_mtrl.9.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/ab_transparent_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/ab_transparent_mtrl_alpha.9.png Binary files differdeleted file mode 100644 index 4d4cb4f..0000000 --- a/core/res/res/drawable-ldpi/ab_transparent_mtrl_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/btn_check_off_mtrl_alpha.png b/core/res/res/drawable-ldpi/btn_check_off_mtrl_alpha.png Binary files differdeleted file mode 100644 index fbe176f..0000000 --- a/core/res/res/drawable-ldpi/btn_check_off_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/btn_check_on_mtrl_alpha.png b/core/res/res/drawable-ldpi/btn_check_on_mtrl_alpha.png Binary files differdeleted file mode 100644 index 5fd18e5..0000000 --- a/core/res/res/drawable-ldpi/btn_check_on_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/btn_radio_off_mtrl_alpha.png b/core/res/res/drawable-ldpi/btn_radio_off_mtrl_alpha.png Binary files differdeleted file mode 100644 index d17081f..0000000 --- a/core/res/res/drawable-ldpi/btn_radio_off_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/btn_radio_off_pressed_mtrl_alpha.png b/core/res/res/drawable-ldpi/btn_radio_off_pressed_mtrl_alpha.png Binary files differdeleted file mode 100644 index ac27576..0000000 --- a/core/res/res/drawable-ldpi/btn_radio_off_pressed_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/btn_radio_on_mtrl_alpha.png b/core/res/res/drawable-ldpi/btn_radio_on_mtrl_alpha.png Binary files differdeleted file mode 100644 index f31d37f..0000000 --- a/core/res/res/drawable-ldpi/btn_radio_on_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/btn_radio_on_pressed_mtrl_alpha.png b/core/res/res/drawable-ldpi/btn_radio_on_pressed_mtrl_alpha.png Binary files differdeleted file mode 100644 index 458abaf..0000000 --- a/core/res/res/drawable-ldpi/btn_radio_on_pressed_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/btn_star_mtrl_alpha.png b/core/res/res/drawable-ldpi/btn_star_mtrl_alpha.png Binary files differdeleted file mode 100644 index ae665fd..0000000 --- a/core/res/res/drawable-ldpi/btn_star_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/expander_close_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/expander_close_mtrl_alpha.9.png Binary files differdeleted file mode 100644 index 19ac6f5..0000000 --- a/core/res/res/drawable-ldpi/expander_close_mtrl_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/expander_open_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/expander_open_mtrl_alpha.9.png Binary files differdeleted file mode 100644 index e51f018..0000000 --- a/core/res/res/drawable-ldpi/expander_open_mtrl_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/ic_cab_done_mtrl_alpha.png b/core/res/res/drawable-ldpi/ic_cab_done_mtrl_alpha.png Binary files differdeleted file mode 100644 index 8ee0546..0000000 --- a/core/res/res/drawable-ldpi/ic_cab_done_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/ic_find_next_mtrl_alpha.png b/core/res/res/drawable-ldpi/ic_find_next_mtrl_alpha.png Binary files differdeleted file mode 100644 index dd6fe20..0000000 --- a/core/res/res/drawable-ldpi/ic_find_next_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/ic_find_previous_mtrl_alpha.png b/core/res/res/drawable-ldpi/ic_find_previous_mtrl_alpha.png Binary files differdeleted file mode 100644 index d4598ba..0000000 --- a/core/res/res/drawable-ldpi/ic_find_previous_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/ic_menu_find_mtrl_alpha.png b/core/res/res/drawable-ldpi/ic_menu_find_mtrl_alpha.png Binary files differdeleted file mode 100644 index c828577..0000000 --- a/core/res/res/drawable-ldpi/ic_menu_find_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/ic_menu_search_mtrl_alpha.png b/core/res/res/drawable-ldpi/ic_menu_search_mtrl_alpha.png Binary files differdeleted file mode 100644 index ec759fb..0000000 --- a/core/res/res/drawable-ldpi/ic_menu_search_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/list_divider_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/list_divider_mtrl_alpha.9.png Binary files differdeleted file mode 100644 index 941d0d7..0000000 --- a/core/res/res/drawable-ldpi/list_divider_mtrl_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/list_section_divider_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/list_section_divider_mtrl_alpha.9.png Binary files differdeleted file mode 100644 index f1a0362..0000000 --- a/core/res/res/drawable-ldpi/list_section_divider_mtrl_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/progress_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/progress_mtrl_alpha.9.png Binary files differdeleted file mode 100644 index cd39bb4..0000000 --- a/core/res/res/drawable-ldpi/progress_mtrl_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/scrubber_control_off_mtrl_alpha.png b/core/res/res/drawable-ldpi/scrubber_control_off_mtrl_alpha.png Binary files differdeleted file mode 100644 index bf6ce6c..0000000 --- a/core/res/res/drawable-ldpi/scrubber_control_off_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/scrubber_control_off_pressed_mtrl_alpha.png b/core/res/res/drawable-ldpi/scrubber_control_off_pressed_mtrl_alpha.png Binary files differdeleted file mode 100644 index df88c4e..0000000 --- a/core/res/res/drawable-ldpi/scrubber_control_off_pressed_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/scrubber_control_on_mtrl_alpha.png b/core/res/res/drawable-ldpi/scrubber_control_on_mtrl_alpha.png Binary files differdeleted file mode 100644 index 85a06b9..0000000 --- a/core/res/res/drawable-ldpi/scrubber_control_on_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/scrubber_control_on_pressed_mtrl_alpha.png b/core/res/res/drawable-ldpi/scrubber_control_on_pressed_mtrl_alpha.png Binary files differdeleted file mode 100644 index 458abaf..0000000 --- a/core/res/res/drawable-ldpi/scrubber_control_on_pressed_mtrl_alpha.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/scrubber_primary_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/scrubber_primary_mtrl_alpha.9.png Binary files differdeleted file mode 100644 index 6f99790..0000000 --- a/core/res/res/drawable-ldpi/scrubber_primary_mtrl_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-ldpi/spinner_mtrl_am_alpha.9.png Binary files differdeleted file mode 100644 index 368a9b0..0000000 --- a/core/res/res/drawable-ldpi/spinner_mtrl_am_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/switch_off_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/switch_off_mtrl_alpha.9.png Binary files differdeleted file mode 100644 index 9cd2df3..0000000 --- a/core/res/res/drawable-ldpi/switch_off_mtrl_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/switch_on_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/switch_on_mtrl_alpha.9.png Binary files differdeleted file mode 100644 index f9b287a..0000000 --- a/core/res/res/drawable-ldpi/switch_on_mtrl_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/text_cursor_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/text_cursor_mtrl_alpha.9.png Binary files differdeleted file mode 100644 index 4aaa79f..0000000 --- a/core/res/res/drawable-ldpi/text_cursor_mtrl_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/textfield_activated_mtrl_alpha.9.png Binary files differdeleted file mode 100644 index d12ec06..0000000 --- a/core/res/res/drawable-ldpi/textfield_activated_mtrl_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/textfield_default_mtrl_alpha.9.png Binary files differdeleted file mode 100644 index 6f0c57f..0000000 --- a/core/res/res/drawable-ldpi/textfield_default_mtrl_alpha.9.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/textfield_activated_mtrl_alpha.9.png Binary files differindex f3d06fe..45db6f7 100644 --- a/core/res/res/drawable-mdpi/textfield_activated_mtrl_alpha.9.png +++ b/core/res/res/drawable-mdpi/textfield_activated_mtrl_alpha.9.png diff --git a/core/res/res/drawable-mdpi/textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/textfield_default_mtrl_alpha.9.png Binary files differindex f0e7db8..8111fcb 100644 --- a/core/res/res/drawable-mdpi/textfield_default_mtrl_alpha.9.png +++ b/core/res/res/drawable-mdpi/textfield_default_mtrl_alpha.9.png diff --git a/core/res/res/drawable-xhdpi/textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/textfield_activated_mtrl_alpha.9.png Binary files differindex 7174b67..8c617fd 100644 --- a/core/res/res/drawable-xhdpi/textfield_activated_mtrl_alpha.9.png +++ b/core/res/res/drawable-xhdpi/textfield_activated_mtrl_alpha.9.png diff --git a/core/res/res/drawable-xhdpi/textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/textfield_default_mtrl_alpha.9.png Binary files differindex 46dad22..240ef7b 100644 --- a/core/res/res/drawable-xhdpi/textfield_default_mtrl_alpha.9.png +++ b/core/res/res/drawable-xhdpi/textfield_default_mtrl_alpha.9.png diff --git a/core/res/res/drawable-xxhdpi/textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/textfield_activated_mtrl_alpha.9.png Binary files differindex 661d5f0..778670a 100644 --- a/core/res/res/drawable-xxhdpi/textfield_activated_mtrl_alpha.9.png +++ b/core/res/res/drawable-xxhdpi/textfield_activated_mtrl_alpha.9.png diff --git a/core/res/res/drawable-xxhdpi/textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/textfield_default_mtrl_alpha.9.png Binary files differindex d7696c3..6dd5d4f 100644 --- a/core/res/res/drawable-xxhdpi/textfield_default_mtrl_alpha.9.png +++ b/core/res/res/drawable-xxhdpi/textfield_default_mtrl_alpha.9.png diff --git a/core/res/res/drawable/spinner_background_material.xml b/core/res/res/drawable/spinner_background_material.xml index 02ea11b..d99e367 100644 --- a/core/res/res/drawable/spinner_background_material.xml +++ b/core/res/res/drawable/spinner_background_material.xml @@ -16,16 +16,17 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true"> - <item android:state_checked="true"> + <item android:state_enabled="false"> <nine-patch android:src="@drawable/spinner_mtrl_am_alpha" - android:tint="?attr/colorControlActivated" /> + android:tint="?attr/colorControlNormal" + android:alpha="?attr/disabledAlpha" /> </item> - <item android:state_pressed="true"> + <item android:state_pressed="false" android:state_focused="false"> <nine-patch android:src="@drawable/spinner_mtrl_am_alpha" - android:tint="?attr/colorControlActivated" /> + android:tint="?attr/colorControlNormal" /> </item> <item> <nine-patch android:src="@drawable/spinner_mtrl_am_alpha" - android:tint="?attr/colorControlNormal" /> + android:tint="?attr/colorControlActivated" /> </item> </selector> diff --git a/core/res/res/drawable/spinner_textfield_background_material.xml b/core/res/res/drawable/spinner_textfield_background_material.xml index 2732d53..fab3dc9 100644 --- a/core/res/res/drawable/spinner_textfield_background_material.xml +++ b/core/res/res/drawable/spinner_textfield_background_material.xml @@ -17,7 +17,21 @@ <inset xmlns:android="http://schemas.android.com/apk/res/android" android:inset="@dimen/control_inset_material"> <selector android:autoMirrored="true"> - <item android:state_checked="false" android:state_pressed="false"> + <item android:state_enabled="false"> + <layer-list android:paddingMode="stack"> + <item> + <nine-patch android:src="@drawable/textfield_activated_mtrl_alpha" + android:tint="?attr/colorControlActivated" + android:alpha="?attr/disabledAlpha" /> + </item> + <item> + <nine-patch android:src="@drawable/spinner_mtrl_am_alpha" + android:tint="?attr/colorControlActivated" + android:alpha="?attr/disabledAlpha" /> + </item> + </layer-list> + </item> + <item android:state_pressed="false" android:state_focused="false"> <layer-list android:paddingMode="stack"> <item> <nine-patch android:src="@drawable/textfield_default_mtrl_alpha" diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 8f1b77b..b2f73e4 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -339,7 +339,7 @@ <string name="permlab_setDebugApp" msgid="3022107198686584052">"habilitar depuración de aplicación"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que la aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden usar este permiso para interrumpir la ejecución de otras aplicaciones."</string> <string name="permlab_changeConfiguration" msgid="4162092185124234480">"modificar ajustes de visualización del sistema"</string> - <string name="permdesc_changeConfiguration" msgid="4372223873154296076">"Permite que la aplicación cambie la configuración actual como, por ejemplo, la configuración local o el tamaño de fuente general."</string> + <string name="permdesc_changeConfiguration" msgid="4372223873154296076">"Permite que la aplicación cambie la configuración actual como, por ejemplo, la configuración local o el tamaño de la fuente general."</string> <string name="permlab_enableCarMode" msgid="5684504058192921098">"habilitar modo coche"</string> <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Permite que la aplicación habilite el modo coche."</string> <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"cerrar otras aplicaciones"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 2092364..fbc1e42 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -541,19 +541,19 @@ <string name="permlab_installLocationProvider" msgid="6578101199825193873">"asenna sijainnintarjoaja"</string> <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"Luo imitoituja sijaintilähteitä testaustarkoituksessa tai asenna uusi sijaintipalvelu. Sovellus voi ohittaa muiden sijaintilähteiden kuten GPS:n ja sijaintipalveluiden palauttaman sijainnin ja/tai tilan."</string> <string name="permlab_accessFineLocation" msgid="1191898061965273372">"tarkka sijainti (GPS- ja verkkopohjainen)"</string> - <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Antaa sovelluksen käyttää tarkkaa sijaintiasi, joka määritetään GPS:n tai verkon sijaintilähteiden kuten radiomastojen ja wifi-verkkojen avulla. Sijaintipalveluiden täytyy olla käytössä ja laitteesi saatavilla, jotta sovellus voi käyttää niitä. Sovellus voi määrittää tämän luvan avulla sijaintisi ja lisätä akun käyttöä."</string> + <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Antaa sovelluksen käyttää tarkkaa sijaintiasi, joka määritetään GPS:n tai verkon sijaintilähteiden kuten radiomastojen ja Wi-Fi-verkkojen avulla. Sijaintipalveluiden täytyy olla käytössä ja laitteesi saatavilla, jotta sovellus voi käyttää niitä. Sovellus voi määrittää tämän luvan avulla sijaintisi ja lisätä akun käyttöä."</string> <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"likimääräinen sijainti (verkkopohjainen)"</string> - <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Antaa sovelluksen käyttää likimääräistä sijaintiasi. Sijainnin määrittävät sijaintipalvelut verkon sijaintilähteiden kuten radiomastojen ja wifi-verkkojen avulla. Sijaintipalveluiden täytyy olla käytössä ja laitteesi saatavilla, jotta sovellus voi käyttää niitä. Sovellus voi määrittää tämän luvan avulla likimääräisen sijaintisi."</string> + <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Antaa sovelluksen käyttää likimääräistä sijaintiasi. Sijainnin määrittävät sijaintipalvelut verkon sijaintilähteiden kuten radiomastojen ja Wi-Fi-verkkojen avulla. Sijaintipalveluiden täytyy olla käytössä ja laitteesi saatavilla, jotta sovellus voi käyttää niitä. Sovellus voi määrittää tämän luvan avulla likimääräisen sijaintisi."</string> <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"käytä SurfaceFlinger-sovellusta"</string> <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Antaa sovelluksen käyttää SurfaceFlingerin matalan tason ominaisuuksia."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lue kehyspuskuria"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Antaa sovelluksen lukea kehyspuskurin sisältöä."</string> <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"InputFlingerin käyttäminen"</string> <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Antaa sovelluksen käyttää InputFlingerin matalan tason ominaisuuksia."</string> - <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"määritä wifi-näyttöjen asetukset"</string> - <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Antaa sovelluksen määrittää wifi-näyttöjä ja muodostaa yhteyden niihin."</string> - <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"hallitse wifi-näyttöjä"</string> - <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Antaa sovelluksen hallita wifi-näyttöjen matalan tason ominaisuuksia."</string> + <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"määritä Wi-Fi-näyttöjen asetukset"</string> + <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Antaa sovelluksen määrittää Wi-Fi-näyttöjä ja muodostaa yhteyden niihin."</string> + <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"hallitse Wi-Fi-näyttöjä"</string> + <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Antaa sovelluksen hallita Wi-Fi-näyttöjen matalan tason ominaisuuksia."</string> <string name="permlab_controlVpn" msgid="2618442789397588200">"Hallita virtuaalisia yksityisverkkoja."</string> <string name="permdesc_controlVpn" msgid="762852603315861214">"Sallii sovelluksen hallita virtuaalisten yksityisverkkojen alempien tasojen ominaisuuksia."</string> <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"äänentoiston kaappaus"</string> @@ -698,14 +698,14 @@ <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Antaa sovelluksen muuttaa internetyhteyden jakamisen tilaa."</string> <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"muuta taustatietojen käyttöasetuksia"</string> <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Antaa sovelluksen muuttaa taustatietojen käyttöasetuksia."</string> - <string name="permlab_accessWifiState" msgid="5202012949247040011">"näytä wifi-yhteydet"</string> - <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Antaa sovelluksen tarkastella wifi-verkkoja koskevia tietoja, kuten onko wifi käytössä ja mihin wifi-laitteisiin on muodostettu yhteys."</string> - <string name="permlab_changeWifiState" msgid="6550641188749128035">"muodosta ja katkaise wifi-yhteys"</string> - <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Antaa sovelluksen yhdistää wifi-tukiasemiin tai katkaista yhteyden sekä tehdä muutoksia määritettyihin wifi-verkkoihin."</string> - <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"anna ottaa vastaan wifi-ryhmälähetyksiä"</string> - <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Antaa sovelluksen vastaanottaa kaikille laitteille, ei vain tablet-laitteellesi, wifi-verkon kautta monilähetystilassa lähetettyjä paketteja. Tämä käyttää enemmän virtaa kuin tavallinen lähetystila."</string> + <string name="permlab_accessWifiState" msgid="5202012949247040011">"näytä Wi-Fi-yhteydet"</string> + <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Antaa sovelluksen tarkastella Wi-Fi-verkkoja koskevia tietoja, kuten onko Wi-Fi käytössä ja mihin Wi-Fi-laitteisiin on muodostettu yhteys."</string> + <string name="permlab_changeWifiState" msgid="6550641188749128035">"muodosta ja katkaise Wi-Fi-yhteys"</string> + <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Antaa sovelluksen yhdistää Wi-Fi-tukiasemiin tai katkaista yhteyden sekä tehdä muutoksia määritettyihin Wi-Fi-verkkoihin."</string> + <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"anna ottaa vastaan Wi-Fi-ryhmälähetyksiä"</string> + <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Antaa sovelluksen vastaanottaa kaikille laitteille, ei vain tablet-laitteellesi, Wi-Fi-verkon kautta monilähetystilassa lähetettyjä paketteja. Tämä käyttää enemmän virtaa kuin tavallinen lähetystila."</string> <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Antaa sovelluksen vastaanottaa paketteja, jotka on lähetetty television lisäksi kaikille laitteille Wi-Fi-verkon kautta monilähetystilassa. Tämä käyttää enemmän virtaa kuin tavallinen lähetystila."</string> - <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Antaa sovelluksen vastaanottaa kaikille laitteille, ei vain puhelimellesi, wifi-verkon kautta monilähetystilassa lähetettyjä paketteja. Tämä käyttää enemmän virtaa kuin tavallinen lähetystila."</string> + <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Antaa sovelluksen vastaanottaa kaikille laitteille, ei vain puhelimellesi, Wi-Fi-verkon kautta monilähetystilassa lähetettyjä paketteja. Tämä käyttää enemmän virtaa kuin tavallinen lähetystila."</string> <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"käytä Bluetooth-asetuksia"</string> <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Antaa sovelluksen määrittää paikallisen Bluetooth-tabletin asetukset sekä tunnistaa muita laitteita ja muodostaa niiden kanssa laitepareja."</string> <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Antaa sovelluksen määrittää television Bluetooth-asetukset, etsiä laitteita ja muodostaa laitepareja."</string> @@ -1335,18 +1335,18 @@ <item quantity="other" msgid="4192424489168397386">"Wi-Fi-verkkoja käytettävissä"</item> </plurals> <plurals name="wifi_available_detailed"> - <item quantity="one" msgid="1634101450343277345">"Avoin wifi-verkko käytettävissä"</item> - <item quantity="other" msgid="7915895323644292768">"Avoimia wifi-verkkoja käytettävissä"</item> + <item quantity="one" msgid="1634101450343277345">"Avoin Wi-Fi-verkko käytettävissä"</item> + <item quantity="other" msgid="7915895323644292768">"Avoimia Wi-Fi-verkkoja käytettävissä"</item> </plurals> - <string name="wifi_available_sign_in" msgid="4029489716605255386">"Kirjaudu wifi-verkkoon"</string> + <string name="wifi_available_sign_in" msgid="4029489716605255386">"Kirjaudu Wi-Fi-verkkoon"</string> <string name="network_available_sign_in" msgid="8495155593358054676">"Kirjaudu verkkoon"</string> <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) --> <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-yhteyden muodostaminen epäonnistui"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" : huono internetyhteys."</string> - <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Suora wifi-yhteys"</string> - <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käynnistä suora wifi-yhteys. Wi-Fi-asiakas/-hotspot poistetaan käytöstä."</string> - <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Suoran wifi-yhteyden käynnistäminen epäonnistui."</string> + <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Suora Wi-Fi-yhteys"</string> + <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käynnistä suora Wi-Fi-yhteys. Wi-Fi-asiakas/-hotspot poistetaan käytöstä."</string> + <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Suoran Wi-Fi-yhteyden käynnistäminen epäonnistui."</string> <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct on käytössä"</string> <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tarkastele asetuksia koskettamalla"</string> <string name="accept" msgid="1645267259272829559">"Hyväksy"</string> @@ -1357,9 +1357,9 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kohde:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Kirjoita pyydetty PIN-koodi:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-koodi:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet-laitteen yhteys wifi-verkkoon katkaistaan väliaikaisesti tabletin ollessa yhdistettynä laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet-laitteen yhteys Wi-Fi-verkkoon katkaistaan väliaikaisesti tabletin ollessa yhdistettynä laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"Television Wi-Fi-yhteys katkeaa tilapäisesti, kun siihen on yhdistetty <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Puhelimen yhteys wifi-verkkoon katkaistaan väliaikaisesti puhelimen ollessa yhdistettynä laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Puhelimen yhteys Wi-Fi-verkkoon katkaistaan väliaikaisesti puhelimen ollessa yhdistettynä laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="select_character" msgid="3365550120617701745">"Lisää merkki"</string> <string name="sms_control_title" msgid="7296612781128917719">"Tekstiviestien lähettäminen"</string> <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> lähettää suuria määriä tekstiviestejä. Annetaanko tämän sovelluksen jatkaa tekstiviestien lähettämistä?"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 70430a3..dd7636a 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -1304,7 +1304,7 @@ <string name="android_upgrading_complete" msgid="1405954754112999229">"Menyelesaikan boot."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> berjalan"</string> <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Sentuh untuk beralih ke apl"</string> - <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Beralih apl?"</string> + <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Beralih aplikasi?"</string> <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Apl lain sudah berjalan dan harus dihentikan agar Anda dapat memulai yang baru."</string> <string name="old_app_action" msgid="493129172238566282">"Kembali ke<xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="old_app_description" msgid="2082094275580358049">"Jangan memulai aplikasi baru."</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index f33425e..9f1c89d 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -1832,8 +1832,8 @@ <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g>이(가) 선택됨"</string> <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> 삭제됨"</string> <string name="managed_profile_label_badge" msgid="2355652472854327647">"업무용 <xliff:g id="LABEL">%1$s</xliff:g>"</string> - <string name="lock_to_app_toast" msgid="7570091317001980053">"화면을 고정 해제하려면 \'뒤로\'와 \'최근 사용\'을 동시에 길게 터치합니다."</string> - <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"화면을 고정 해제하려면 \'최근 사용\'을 길게 터치합니다."</string> + <string name="lock_to_app_toast" msgid="7570091317001980053">"화면 고정을 해제하려면 \'뒤로\'와 \'개요\'를 동시에 길게 터치합니다."</string> + <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"화면 고정을 해제하려면 \'개요\'를 길게 터치합니다."</string> <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"화면이 고정되었습니다. 소속된 조직에서 고정 해제를 허용하지 않습니다."</string> <string name="lock_to_app_start" msgid="6643342070839862795">"화면 고정됨"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"화면 고정 해제됨"</string> diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml index 2a0d4b8..314671b 100644 --- a/core/res/res/values-ne-rNP/strings.xml +++ b/core/res/res/values-ne-rNP/strings.xml @@ -1273,9 +1273,7 @@ <!-- no translation found for whichEditApplicationNamed (1775815530156447790) --> <skip /> <string name="whichSendApplication" msgid="6902512414057341668">"साझेदारी गर्नुहोस्..."</string> - <!-- String.format failed for translation --> - <!-- no translation found for whichSendApplicationNamed (2799370240005424391) --> - <skip /> + <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s सँग साझेदारी गर्नुहोस्"</string> <string name="whichHomeApplication" msgid="4307587691506919691">"गृह अनुप्रयोग चयन गर्नुहोस्"</string> <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"%1$s लाई गृहको रूपमा प्रयोग गर्नुहोस्"</string> <string name="alwaysUse" msgid="4583018368000610438">"यस कार्यको लागि पूर्वनिर्धारितबाट प्रयोग गर्नुहोस्।"</string> @@ -1646,7 +1644,7 @@ <string name="SetupCallDefault" msgid="5834948469253758575">"कल स्वीकार गर्नुहुन्छ?"</string> <string name="activity_resolver_use_always" msgid="8017770747801494933">"सधैँ"</string> <string name="activity_resolver_use_once" msgid="2404644797149173758">"एउटा मात्र"</string> - <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%%१$ को कार्य प्रोफाइल समर्थन गर्दैन"</string> + <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s कार्य प्रोफाइल समर्थन गर्दैन"</string> <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ट्याब्लेट"</string> <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string> <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"फोन"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index ab3d22a..f062a88 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -272,7 +272,7 @@ <string name="permgroupdesc_accessibilityFeatures" msgid="4205196881678144335">"Специальные возможности, которые можно запрашивать"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Читать содержимое окна."</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Распознавать содержимое окна, в котором вы находитесь."</string> - <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Включать изучение касанием."</string> + <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> @@ -1122,9 +1122,9 @@ <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="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> + <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> <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 месяц назад"</string> <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Более месяца назад"</string> <plurals name="num_seconds_ago"> diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml index a8fd8d4..8dad63e 100644 --- a/core/res/res/values/colors_material.xml +++ b/core/res/res/values/colors_material.xml @@ -26,8 +26,8 @@ <color name="primary_dark_material_dark">#ff000000</color> <color name="primary_dark_material_light">#ff757575</color> - <color name="ripple_material_dark">#40ffffff</color> - <color name="ripple_material_light">#40000000</color> + <color name="ripple_material_dark">#4dffffff</color> + <color name="ripple_material_light">#1f000000</color> <color name="accent_material_light">@color/material_deep_teal_500</color> <color name="accent_material_dark">@color/material_deep_teal_200</color> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index d013ee1..6769c85 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1830,6 +1830,9 @@ provisioning, availability etc --> <bool name="config_carrier_volte_available">false</bool> + <!-- Flag specifying whether VoLTE availability is based on provisioning --> + <bool name="config_carrier_volte_provisioned">false</bool> + <!-- Flag specifying whether VT is available on device --> <bool name="config_device_vt_available">false</bool> @@ -1927,9 +1930,19 @@ --> <integer name="config_LTE_RSRP_threshold_type">1</integer> + <!-- Enabled built-in zen mode condition providers --> + <string-array translatable="false" name="config_system_condition_providers"> + <item>countdown</item> + <item>downtime</item> + <item>next_alarm</item> + </string-array> + <!-- Show the next-alarm as a zen exit condition if it occurs in the next n hours. --> <integer name="config_next_alarm_condition_lookahead_threshold_hrs">12</integer> + <!-- Show downtime as a zen exit condition if it starts in the next n hours. --> + <integer name="config_downtime_condition_lookahead_threshold_hrs">4</integer> + <!-- Flags enabling default window features. See Window.java --> <bool name="config_defaultWindowFeatureOptionsPanel">true</bool> <bool name="config_defaultWindowFeatureContextMenu">true</bool> diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml index 8cc2a8a..bdb0324 100644 --- a/core/res/res/values/dimens_material.xml +++ b/core/res/res/values/dimens_material.xml @@ -105,8 +105,8 @@ <dimen name="control_corner_material">2dp</dimen> <dimen name="edit_text_inset_horizontal_material">4dp</dimen> - <dimen name="edit_text_inset_top_material">4dp</dimen> - <dimen name="edit_text_inset_bottom_material">8dp</dimen> + <dimen name="edit_text_inset_top_material">10dp</dimen> + <dimen name="edit_text_inset_bottom_material">7dp</dimen> <dimen name="dialog_padding_material">24dp</dimen> <dimen name="dialog_padding_top_material">18dp</dimen> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 5df3653..4f2ed22 100755 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2017,7 +2017,9 @@ <java-symbol type="string" name="zen_mode_until" /> <java-symbol type="string" name="zen_mode_next_alarm_summary" /> <java-symbol type="string" name="zen_mode_next_alarm_line_one" /> + <java-symbol type="array" name="config_system_condition_providers" /> <java-symbol type="integer" name="config_next_alarm_condition_lookahead_threshold_hrs" /> + <java-symbol type="integer" name="config_downtime_condition_lookahead_threshold_hrs" /> <java-symbol type="string" name="muted_by" /> <java-symbol type="string" name="item_is_selected" /> @@ -2077,6 +2079,7 @@ <java-symbol type="bool" name="imsServiceAllowTurnOff" /> <java-symbol type="bool" name="config_device_volte_available" /> <java-symbol type="bool" name="config_carrier_volte_available" /> + <java-symbol type="bool" name="config_carrier_volte_provisioned" /> <java-symbol type="bool" name="config_device_vt_available" /> <java-symbol type="bool" name="config_carrier_vt_available" /> <java-symbol type="bool" name="useImsAlwaysForEmergencyCall" /> diff --git a/docs/html/about/start.jd b/docs/html/about/start.jd index 727c975..4658141 100644 --- a/docs/html/about/start.jd +++ b/docs/html/about/start.jd @@ -5,12 +5,13 @@ walkthru=0 @jd:body <p>Everything you need to start developing apps for Android is available here on -developer.android.com. You'll find everything from the developer SDK, API documentation, and design -guidelines, to information about the current device landscape and how you can distribute and -monetize your app.</p> +<em>developer.android.com</em>. You'll find everything from the API documentation +and design guidelines, to information about the current device landscape and how you can distribute +and monetize your app.</p> + <p>No two apps are built in the same way, but we've structured the information you need to build an -app into the following three sections that represent the general order for app development. +app into the following three sections that represent the general order for app development. <style> @@ -32,7 +33,7 @@ the Android user experience. Although you may know what a user will <em>do</em> should pause to focus on how a user will <em>interact</em> with it. Your design should be sleek, simple, powerful, and tailored to the Android experience.</p> -<p>So whether you're a one-man shop or a large team, you should study the <a +<p>So whether you're creating an app alone or you're part of a team, study the <a href="{@docRoot}design/index.html">Design</a> guidelines first.</p> </div> @@ -59,6 +60,10 @@ types of devices your app supports. Everything you need to get started with this available in the <a href="{@docRoot}distribute/index.html">Distribute</a> section.</p> </div> +<p style="clear:both;height:0"> </p> -<p style="clear:both">Now that you know what's available, get started by installing the <a -href="{@docRoot}sdk/index.html">Android SDK</a>.</p>
\ No newline at end of file +<h2>Go!</h2> +<p>Get started by installing <a +href="{@docRoot}sdk/index.html">Android Studio</a>—the official IDE for Android development, +which includes the Android SDK tools. Then when you're ready to begin coding, follow the training +for <a href="{@docRoot}training/basics/firstapp/index.html">Building Your First App</a>.</p>
\ No newline at end of file diff --git a/docs/html/design/design_toc.cs b/docs/html/design/design_toc.cs index 2cbdacd..63f5cad 100644 --- a/docs/html/design/design_toc.cs +++ b/docs/html/design/design_toc.cs @@ -26,6 +26,7 @@ <li><a href="<?cs var:toroot ?>design/wear/context.html">Context Awareness</a></li> <li><a href="<?cs var:toroot ?>design/wear/patterns.html">UI Patterns</a></li> <li><a href="<?cs var:toroot ?>design/wear/style.html">Style</a></li> + <li><a href="<?cs var:toroot ?>design/wear/watchfaces.html">Watch Faces</a></li> </ul> </li> <li class="nav-section"> @@ -106,4 +107,4 @@ <div class="nav-section-header empty"><a href="<?cs var:toroot ?>design/videos/index.html">Videos</a></div> </li> -</ul>
\ No newline at end of file +</ul> diff --git a/docs/html/design/downloads/index.jd b/docs/html/design/downloads/index.jd index a073428..16d61e7 100644 --- a/docs/html/design/downloads/index.jd +++ b/docs/html/design/downloads/index.jd @@ -137,7 +137,84 @@ modify to match your theme, plus source files.</p> </div> +<div class="layout-content-row"> + <div class="layout-content-col span-5"> + <h4>Watch faces UI toolkit</h4> +<p>Detailed specifications and measurements for the the background canvas, notification cards, and +system indicators. +</p> + + </div> + <div class="layout-content-col span-4"> + + <img src="{@docRoot}design/media/downloads_wear_DesignSpec_Icon.png" width="220"> + + </div> + <div class="layout-content-col span-4"> + <a class="download-button" onClick="ga('send', 'event', 'Design', 'Download', 'Wear Watch Face Specifications');" + href="{@docRoot}downloads/design/AndroidWear_DesignSpec_11.13.pdf">PDF Toolkit</a> + </div> +</div> + + +<div class="layout-content-row"> + <div class="layout-content-col span-5"> + <h4>Slide watch face</h4> +<p>Example of a watch face design in AI format. +</p> + + </div> + <div class="layout-content-col span-4"> + + <img src="{@docRoot}design/media/downloads_wear_Slide_Ai_Icon.png" width="150" + style="width:150px;margin:0 auto;display:block"> + + </div> + <div class="layout-content-col span-4"> + <a class="download-button" onClick="ga('send', 'event', 'Design', 'Download', 'Wear Watch Face Example');" + href="{@docRoot}downloads/design/Slide.ai">Adobe® Illustrator® Design</a> + </div> +</div> + +<div class="layout-content-row"> + <div class="layout-content-col span-5"> + <h4>Slide watch face specifications</h4> +<p>Design specifications for the Slide watch face in PSD format. +</p> + + </div> + <div class="layout-content-col span-4"> + + <img src="{@docRoot}design/media/downloads_wear_Slide_Psd_Icon.png" width="150" + style="width:150px;margin:0 auto;display:block"> + + </div> + <div class="layout-content-col span-4"> + <a class="download-button" onClick="ga('send', 'event', 'Design', 'Download', 'Wear Watch Face Example Specifications');" + href="{@docRoot}downloads/design/Slide.psd">Adobe® Photoshop® Specifications</a> + </div> +</div> + + +<div class="layout-content-row"> + <div class="layout-content-col span-5"> + <h4>Watch face icon example</h4> +<p>Template for creating watch face icons for the carousel on Android Wear devices. +</p> + + </div> + <div class="layout-content-col span-4"> + + <img src="{@docRoot}design/media/downloads_wear_Slide_IconExample.png" width="150" + style="width:150px;margin:0 auto;display:block"> + + </div> + <div class="layout-content-col span-4"> + <a class="download-button" onClick="ga('send', 'event', 'Design', 'Download', 'Wear Watch Face Example Specifications');" + href="{@docRoot}downloads/design/Slide_IconExample.psd">Adobe® Photoshop® Icon</a> + </div> +</div> diff --git a/docs/html/design/material/index.jd b/docs/html/design/material/index.jd index db18a83..4d9a1a7 100644 --- a/docs/html/design/material/index.jd +++ b/docs/html/design/material/index.jd @@ -5,6 +5,40 @@ page.image=design/material/images/MaterialLight.png @jd:body +<!-- developer docs box --> +<a class="notice-developers right" href="{@docRoot}training/material/index.html"> + <div> + <h3>Developer Docs</h3> + <p>Creating Apps with Material Design</p> + </div> +</a> + +<!-- video box --> +<a class="notice-developers-video" href="https://www.youtube.com/watch?v=p4gmvHyuZzw"> +<div> + <h3>Video</h3> + <p>Introduction to Material Design</p> +</div> +</a> + +<!-- video box --> +<a class="notice-developers-video" href="https://www.youtube.com/watch?v=YaG_ljfzeUw"> +<div> + <h3>Video</h3> + <p>Paper and Ink: The Materials that Matter</p> +</div> +</a> + +<!-- video box --> +<a class="notice-developers-video" href="https://www.youtube.com/watch?v=XOcCOBe8PTc"> +<div> + <h3>Video</h3> + <p>Material Design in the Google I/O App</p> +</div> +</a> + + + <p itemprop="description">Material design is a comprehensive guide for visual, motion, and interaction design across platforms and devices. Android now includes support for material design apps. To use material design in your Android apps, follow the guidelines defined diff --git a/docs/html/design/media/downloads_wear_DesignSpec_Icon.png b/docs/html/design/media/downloads_wear_DesignSpec_Icon.png Binary files differnew file mode 100644 index 0000000..c3d16133 --- /dev/null +++ b/docs/html/design/media/downloads_wear_DesignSpec_Icon.png diff --git a/docs/html/design/media/downloads_wear_Slide_Ai_Icon.png b/docs/html/design/media/downloads_wear_Slide_Ai_Icon.png Binary files differnew file mode 100644 index 0000000..69291b9 --- /dev/null +++ b/docs/html/design/media/downloads_wear_Slide_Ai_Icon.png diff --git a/docs/html/design/media/downloads_wear_Slide_IconExample.png b/docs/html/design/media/downloads_wear_Slide_IconExample.png Binary files differnew file mode 100644 index 0000000..227bd92 --- /dev/null +++ b/docs/html/design/media/downloads_wear_Slide_IconExample.png diff --git a/docs/html/design/media/downloads_wear_Slide_Psd_Icon.png b/docs/html/design/media/downloads_wear_Slide_Psd_Icon.png Binary files differnew file mode 100644 index 0000000..7b7d2ab --- /dev/null +++ b/docs/html/design/media/downloads_wear_Slide_Psd_Icon.png diff --git a/docs/html/design/media/wear/CardsRender_Build.png b/docs/html/design/media/wear/CardsRender_Build.png Binary files differnew file mode 100644 index 0000000..cf1fbb8 --- /dev/null +++ b/docs/html/design/media/wear/CardsRender_Build.png diff --git a/docs/html/design/media/wear/CompanionApp_Build.png b/docs/html/design/media/wear/CompanionApp_Build.png Binary files differnew file mode 100644 index 0000000..ecf17ba --- /dev/null +++ b/docs/html/design/media/wear/CompanionApp_Build.png diff --git a/docs/html/design/media/wear/DeviceSettings_Build.png b/docs/html/design/media/wear/DeviceSettings_Build.png Binary files differnew file mode 100644 index 0000000..4bbf4b7 --- /dev/null +++ b/docs/html/design/media/wear/DeviceSettings_Build.png diff --git a/docs/html/design/media/wear/Hotword_Cropped.png b/docs/html/design/media/wear/Hotword_Cropped.png Binary files differnew file mode 100644 index 0000000..a947e1f --- /dev/null +++ b/docs/html/design/media/wear/Hotword_Cropped.png diff --git a/docs/html/design/media/wear/Indicators_Cropped.png b/docs/html/design/media/wear/Indicators_Cropped.png Binary files differnew file mode 100644 index 0000000..9449c02 --- /dev/null +++ b/docs/html/design/media/wear/Indicators_Cropped.png diff --git a/docs/html/design/media/wear/Render_1Bit.png b/docs/html/design/media/wear/Render_1Bit.png Binary files differnew file mode 100644 index 0000000..53cbc07 --- /dev/null +++ b/docs/html/design/media/wear/Render_1Bit.png diff --git a/docs/html/design/media/wear/Render_Albumem.png b/docs/html/design/media/wear/Render_Albumem.png Binary files differnew file mode 100644 index 0000000..054fe6b --- /dev/null +++ b/docs/html/design/media/wear/Render_Albumem.png diff --git a/docs/html/design/media/wear/Render_Ambient.png b/docs/html/design/media/wear/Render_Ambient.png Binary files differnew file mode 100644 index 0000000..07e8c58 --- /dev/null +++ b/docs/html/design/media/wear/Render_Ambient.png diff --git a/docs/html/design/media/wear/Render_Episode.png b/docs/html/design/media/wear/Render_Episode.png Binary files differnew file mode 100644 index 0000000..2d545bb --- /dev/null +++ b/docs/html/design/media/wear/Render_Episode.png diff --git a/docs/html/design/media/wear/Render_Interactive.png b/docs/html/design/media/wear/Render_Interactive.png Binary files differnew file mode 100644 index 0000000..a1e260b --- /dev/null +++ b/docs/html/design/media/wear/Render_Interactive.png diff --git a/docs/html/design/media/wear/Render_LowBit.png b/docs/html/design/media/wear/Render_LowBit.png Binary files differnew file mode 100644 index 0000000..83ac365 --- /dev/null +++ b/docs/html/design/media/wear/Render_LowBit.png diff --git a/docs/html/design/media/wear/Render_Next.png b/docs/html/design/media/wear/Render_Next.png Binary files differnew file mode 100644 index 0000000..e080943 --- /dev/null +++ b/docs/html/design/media/wear/Render_Next.png diff --git a/docs/html/design/media/wear/Render_Saturn.png b/docs/html/design/media/wear/Render_Saturn.png Binary files differnew file mode 100644 index 0000000..500018c --- /dev/null +++ b/docs/html/design/media/wear/Render_Saturn.png diff --git a/docs/html/design/media/wear/ScreenShapes_Invert.png b/docs/html/design/media/wear/ScreenShapes_Invert.png Binary files differnew file mode 100644 index 0000000..bc6c135 --- /dev/null +++ b/docs/html/design/media/wear/ScreenShapes_Invert.png diff --git a/docs/html/design/media/wear/ScreenShapes_Pyramids.png b/docs/html/design/media/wear/ScreenShapes_Pyramids.png Binary files differnew file mode 100644 index 0000000..7d907ce --- /dev/null +++ b/docs/html/design/media/wear/ScreenShapes_Pyramids.png diff --git a/docs/html/design/media/wear/ScreenShapes_Rift.png b/docs/html/design/media/wear/ScreenShapes_Rift.png Binary files differnew file mode 100644 index 0000000..9d32916 --- /dev/null +++ b/docs/html/design/media/wear/ScreenShapes_Rift.png diff --git a/docs/html/design/wear/style.jd b/docs/html/design/wear/style.jd index bb2e17f..abd3a9a 100644 --- a/docs/html/design/wear/style.jd +++ b/docs/html/design/wear/style.jd @@ -68,7 +68,7 @@ href="{@docRoot}design/wear/patterns.html#Continuing">Continuing activities on p <h2 id="KeepMinimum" style="clear:both">Keep Notifications to a Minimum</h2> -<p>Don’t abuse the user’s attention. Active notifications (that is, those that cause the device to vibrate) should only be used in cases that are both timely and involve a contact, for example receiving a message from a friend. Non-urgent notifications should be silently added to the Context Stream. See also the general <a href={@docRoot}design/patterns/notifications.html">Android Notifications Guidelines</a>.</p> +<p>Don’t abuse the user’s attention. Active notifications (that is, those that cause the device to vibrate) should only be used in cases that are both timely and involve a contact, for example receiving a message from a friend. Non-urgent notifications should be silently added to the Context Stream. See also the general <a href="{@docRoot}design/patterns/notifications.html">Android Notifications Guidelines</a>.</p> diff --git a/docs/html/design/wear/watchfaces.jd b/docs/html/design/wear/watchfaces.jd new file mode 100644 index 0000000..ef700ee --- /dev/null +++ b/docs/html/design/wear/watchfaces.jd @@ -0,0 +1,338 @@ +page.title=Watch Faces for Android Wear +@jd:body + + +<!-- developer docs box --> +<a class="notice-developers right" href="{@docRoot}training/wearables/watch-faces/index.html" + style="clear:left;margin-bottom:70px"> + <div> + <h3>Developer Docs</h3> + <p>Creating Custom Watch Faces</p> + </div> +</a> + +<p>Android Wear supports custom watch faces with designs that can show contextually relevant +information to users. Designing a watch face requires a careful blending of data and visual +elements that informs users without requiring close attention. Simple, attractive layouts that +can adjust to different screen shapes and sizes, provide options for color and presentation, let +users create a deeply personalized experience with the Wear device that fits them best. Watch +faces exist as part of the Wear user interface, so it is important to provide interactive and +ambient modes, and consider how system user interface elements will interact with your design.</p> + +<p>Follow the guidelines in this page to design your custom watch faces.</p> + +<!-- H2 creative vision --> +<div style="float:right;margin-top:-100px;margin-bottom:20px;margin-left:20px"> + <img src="{@docRoot}design/media/wear/Render_Next.png" + width="200" height="195" alt="" style="margin-right:5px"/><br/> + <img src="{@docRoot}design/media/wear/Render_Interactive.png" + width="200" height="195" alt="" style="margin-right:5px"/> +</div> +<h2 id="CreativeVision">Creative Vision</h2> + +<p>Creating a watch face for Android Wear is an exercise centered around visualizing time clearly. +Android Wear devices provide a unique digital canvas to reimagine the ways in which we tell time. +Android Wear also lets you integrate data on watch faces for a higher level of personalization and +contextual relevance.</p> + +<p>These powerful new tools to create watch faces run the risk of overcomplicating a design. The +most successful watch face designs leverage these advanced capabilities while delivering a +singular, elegant expression of information.</p> + +<p>Glanceability is the single most important principle to consider when creating a watch face +design. Your watch face designs should deliver a singular expression of time and related data. +Experiment with bold, minimal, and expressive design directions that are highly readable at a +distance.</p> + + + +<h2 id="SquareRound">Plan for Square and Round Devices</h2> + +<p>Android Wear devices come in different shapes and sizes. You will need to consider both +square and round faces as well as different resolutions. Some concepts work better in a certain +format, but a little planning will allow users to enjoy your watch face regardless of screen +format.</p> + +<p>These guidelines help your concepts align across devices:</p> + +<div class="layout-content-row" style="margin-top:20px"> +<div class="layout-content-col span-6"> + <h3>Create flexible concepts</h3> + <p>Ideally, the visual functionality of the watch face works for both round and square + formats. In this example, the visual functionality of the watch face is flexible enough + to work well in either format without any adjustment. However, other design concepts require + different executions for square and round screens.</p> +</div> +<div class="layout-content-col span-7"> + <img src="{@docRoot}design/media/wear/ScreenShapes_Invert.png" width="400" + height="221" alt="" style="margin-top:-30px"> +</div> +</div> + +<div class="layout-content-row" style="margin-top:20px"> +<div class="layout-content-col span-6"> + <h3>Use a common design language</h3> + <p>Try using a common set of colors, line weights, shading, and other design elements + to draw a visual connection between your square and round versions. By using similar color + palettes and a few consistent visual elements, the overall appearance of square and round + can be appropriately customized while still feeling like part of the same visual system.</p> +</div> +<div class="layout-content-col span-7"> + <img src="{@docRoot}design/media/wear/ScreenShapes_Pyramids.png" width="400" + height="221" alt="" style="margin-top:-30px"> +</div> +</div> + +<div class="layout-content-row" style="margin-top:20px"> +<div class="layout-content-col span-6"> + <h3>Adjust for analog concepts</h3> + <p>Some of your concepts will naturally take the shape of an analog clock, like a center + dial with hour and minute hands. In this case, consider the corner areas that are exposed + when translating to a square format. Try extending and exploring this extra space.</p> +</div> +<div class="layout-content-col span-7"> + <img src="{@docRoot}design/media/wear/ScreenShapes_Rift.png" width="400" + height="221" alt="" style="margin-top:-30px"> +</div> +</div> + + + +<!-- H2: plan for all display modes --> +<div style="float:right;margin-top:35px;margin-left:20px"> + <img src="{@docRoot}design/media/wear/Render_Interactive.png" + width="200" height="195" alt="" style="margin-right:5px"/><br/> + <img src="{@docRoot}design/media/wear/Render_Ambient.png" + width="200" height="195" alt="" style="margin-right:5px"/> +</div> +<h2 id="DisplayModes">Plan for All Display Modes</h2> + +<p>Android Wear devices operate in two main modes: ambient and interactive. Your watch face +designs should take these modes into account. Generally, if your watch face design looks great +in ambient mode, it will look even better in interactive mode. The opposite is not always +true.</p> + +<p>In ambient mode, the screen is only updated once every minute. Only show hours and minutes +in ambient mode; do not show seconds in this mode.</p> + +<h3>Interactive mode</h3> +<p>When the user moves their wrist to glance at their watch, the screen goes into interactive +mode. Your design can use full color with fluid animation in this mode.</p> + +<h3>Ambient mode</h3> +<p>Ambient mode helps the device conserve power. In this mode, the screen only displays shades +of grey, black, and white. Your watch face is notified when the device switches to ambient mode, +and you should thoughtfully design for it.</p> + + + + +<h2 id="SpecialScreens">Optimize for Special Screens</h2> + +<p>Android Wear devices feature a variety of screen technologies, each with their own advantages +and considerations. One important consideration when designing the ambient mode display for your +watch face is how it affects battery life and screen burn-in on some screens.</p> + +<p>You can configure your watch face to display different ambient designs depending on the kind +of screen available on the device. Consider the best design for your watch faces on all +screens.</p> + +<div class="layout-content-row" style="margin-top:20px"> +<div class="layout-content-col span-9"> + <h3>Low bit</h3> + <p>Pixels on some screens (including OLED and transflective LED) in ambient mode are either + "on" or "off", also known as "low-bit". When designing for low-bit ambient mode, use only black + and white, avoid grayscale colors, and disable antialiasing in your paint styles. Make sure to + test your design on devices with low-bit ambient mode.</p> +</div> +<div class="layout-content-col span-4"> + <img src="{@docRoot}design/media/wear/Render_LowBit.png" width="200" + height="" alt="" style="margin-top:-30px;margin-left:13px"> +</div> +</div> + +<div class="layout-content-row" style="margin-top:20px"> +<div class="layout-content-col span-9"> + <h3>Burn protection techniques</h3> + <p>When designing for OLED screens, you should consider power efficiency and the screen + burn-in effect. When these screens are in ambient mode, the system shifts the contents of + the screen periodically by a few pixels to avoid pixel burn-in. Do not use large blocks of + pixels in your ambient mode designs and keep 95% of the pixels black. Replace solid shapes in + your regular ambient mode designs with outlined shapes in burn-protected ambient mode. Replace + also filled images with pixel patterns. For analog watch face designs, hollow out the center + where the hands meet to avoid pixel burn-in in this mode.</p> +</div> +<div class="layout-content-col span-4"> + <img src="{@docRoot}design/media/wear/Render_1Bit.png" width="200" + height="" alt="" style="margin-top:-30px;margin-left:13px"> +</div> +</div> + + + +<h2 id="SystemUI">Accomodate System UI Elements</h2> + +<p>Your watch face designs should accommodate Android Wear UI elements. These elements give the +user the status of the wearable and show notifications from services on the user's phone. Try +to keep critical elements in your watch face designs from being obscured by the UI elements.</p> + +<div class="layout-content-row" style="margin-top:20px"> +<div class="layout-content-col span-9"> + <h3>Cards</h3> +<p>Cards are the notification system that bridges information between the wearable and a +mobile device. Cards are also how most applications communicate with users. The user will be +notified on the wearable about items such as emails and messages. As a watch face developer, +you need to accommodate both large and small cards in your design. Your watch face can specify a +preference for the card size, but users may override this setting. Users can also temporarily +hide cards by swiping down on them.</p> +<p>The peek card is the top card in the stream that is partially visible at the bottom of the +screen. A variable peek card has a height that is determined by the amount of text within a given +notification. A small peek card leaves more room for your design. Round faces with analog hands +should have a small peek card. If the time signature is clearly visible above the maximum height +of the variable peek card, you may choose to include the variable peek card. The benefit of a +variable peek card is that it displays more notification information. Faces with information on +the bottom half of the face should leverage the small peek card instead.</p> +<p>The system notifies your watch face when the bounds of a peek card change, so you can +rearrange the elements in your design if necessary.</p> +</div> +<div class="layout-content-col span-4"> + <img src="{@docRoot}design/media/wear/CardsRender_Build.png" width="200" + height="" alt="" style="margin-top:20px;margin-left:13px"> +</div> +</div> + +<div class="layout-content-row" style="margin-top:20px"> +<div class="layout-content-col span-9"> + <h3>Indicators</h3> +<p>Indicators tell the user the status of the wearable, such as charging and airplane mode. +When designing a watch face, consider how the indicator will fall over the watch face.</p> +<p>The indicators can be placed in several fixed locations on the wearable. If you have a +large peek card, the indicators should go on the top or on the center of the screen. When you +position the status icons or the hotword on the bottom of the screen, the system forces small +peek cards. If the edge of the watch face contains strong visual elements, such as +ticks or numbers, place the indicators on the center of the screen.</p> +</div> +<div class="layout-content-col span-4"> + <img src="{@docRoot}design/media/wear/Indicators_Cropped.png" width="200" + height="" alt="" style="margin-top:0px;margin-left:13px"> +</div> +</div> + +<div class="layout-content-row" style="margin-top:20px"> +<div class="layout-content-col span-9"> + <h3>The hotword</h3> +<p>The hotword is the phrase "OK Google", which tells the user that they can interact with +the watch using voice commands. When a user turns on the wearable, the hotword appears on +the screen for a few seconds.</p> +<p>The hotword no longer appears after the user says "OK Google" five times, so the placement of +this element is not as critical. You should still avoid covering up elements of your +watch face. Finally, background protection for the hotword and the indicators should be +turned on unless your design is tailored to have these elements appear on top of them, for example +using dark solid colors with no patterns.</p> +</div> +<div class="layout-content-col span-4"> + <img src="{@docRoot}design/media/wear/Hotword_Cropped.png" width="200" + height="" alt="" style="margin-top:0px;margin-left:13px"> +</div> +</div> + +<p>For more information about measurements and positioning of system UI elements, see +<a href="#SpecsAssets">Specifications and Assets</a>.</p> + + + +<h2 id="DataIntegration">Design Data-Integrated Watch Faces</h2> + +<p>Your watch face can show users contextually relevant data and react to it by changing styles +and colors in your design.</p> + +<div class="layout-content-row" style="margin-top:20px"> +<div class="layout-content-col span-9"> + <h3>What do you want your user to know?</h3> +<p>The first step in designing a data-integrated watch face is to define a conceptual user +outcome based on available data. First, generate a strong concept or outcome you believe is +supported by real user needs. What do you want your users to know after they have glanced +at your design? Once you have identified your outcome, you need to determine how to obtain +the required data.</p> +</div> +<div class="layout-content-col span-4"> + <img src="{@docRoot}design/media/wear/Render_Saturn.png" width="200" + height="" alt="" style="margin-top:-10px;margin-left:13px"> +</div> +</div> + +<div class="layout-content-row" style="margin-top:20px"> +<div class="layout-content-col span-9"> + <h3>A watch dial is a timeline; add data to it</h3> +<p>Your watch face concept may include use of data beyond time, such as weather, calendar +and fitness data. Consider the inclusion of data integration creatively. Avoid simply +overlaying a time-based watch face with extra data. Rather, think about how the data can +be expressed through the lens of time. For example, instead of designing a weather-related +watch face as a clock with an indication of the current temperature in degrees overlayed, +you might design a watch face that describes how the temperature will change over the +course of the day.</p> +</div> +<div class="layout-content-col span-4"> + <img src="{@docRoot}design/media/wear/Render_Episode.png" width="200" + height="" alt="" style="margin-top:-10px;margin-left:13px"> +</div> +</div> + +<div class="layout-content-row" style="margin-top:20px"> +<div class="layout-content-col span-9"> + <h3>Stick to one message</h3> +<p>Once you have solidified your conceptual direction or desired outcome, you will need to +begin visualizing your watch face. The strongest watch face designs are highly glanceable +and deliver a singular expression of data. In order to identify your singular message, you +must identify the most important supporting data point. For instance, instead of displaying +an entire month of calendar events, you might decide to display only the next +upcoming event. By a process of reduction, you should arrive at a powerful singular +expression of data to include in your design.</p> +</div> +<div class="layout-content-col span-4"> + <img src="{@docRoot}design/media/wear/Render_Albumem.png" width="200" + height="" alt="" style="margin-top:-10px;margin-left:13px"> +</div> +</div> + +<h3>Begin with some insight and test as you go</h3> +<p>Make sure your approach begins with insight into the needs and expectations of your users. +Test your designs with users to check any assumptions you might have made about your design along +the way. Try making a rough sketch on paper and asking a friend to tell you what it means. +Try your concept out with lots of different types of data and scenarios. Test your designs +with an actual watch screen before you start coding.</p> + + + +<h2 id="CompanionApp">Support the Android Wear Companion App</h2> + +<p>The Android Wear companion app gives the user access to all installed watch faces and their +settings.</p> + +<div style="margin:0 auto;width:600px"> +<img src="{@docRoot}design/media/wear/CompanionApp_Build.png" width="350" + height="" alt="" style=""> +<img src="{@docRoot}design/media/wear/DeviceSettings_Build.png" width="200" + height="" alt="" style=""> +</div> + +<h3>Don't use a launcher icon</h3> +<p>All available watch faces are accessible from the Android Wear companion app or from your +bundled third party app. There is no need for a stand-alone launcher icon for Android Wear +watch faces.</p> + +<h3>Settings</h3> +<p>Each watch face that has useful settings can have a Settings panel, accessible from the +watch itself and from the companion app on the phone. Standard UI components work in most cases, +but you can explore other creative executions once you have built a foundation designing watch +faces.</p> +<p>Settings on the watch should be limited to binary selections or scrollable lists. Settings +on the phone may include any complex configuration items in addition to the settings +available on the watch.</p> + + + +<h2 id="SpecsAssets">Specifications and Assets</h2> + +<p>To obtain watch face design examples and detailed measurements for the system UI elements, see +the <a href="{@docRoot}design/downloads/index.html#Wear">Design Downloads for Android Wear</a>.</p> diff --git a/docs/html/distribute/essentials/quality/wear.jd b/docs/html/distribute/essentials/quality/wear.jd index d3689dd..a233241 100644 --- a/docs/html/distribute/essentials/quality/wear.jd +++ b/docs/html/distribute/essentials/quality/wear.jd @@ -50,9 +50,8 @@ page.image=/distribute/images/gp-wear-quality.png </p> <p class="note"> - <strong>Note:</strong> You will soon be able to submit your apps for Android Wear review. - Stay tuned for more information about how to submit your apps for Android Wear review through - the <a href="https://play.google.com/apps/publish/signup/">Google Play Developer Console</a>. + <strong>Note:</strong> For information about how to publish your Wear apps in Google Play, see <a + href="{@docRoot}distribute/googleplay/wear.html">Distributing to Android Wear</a>. </p> <div class="headerLine"> @@ -109,7 +108,8 @@ page.image=/distribute/images/gp-wear-quality.png </td> <td> <p style="margin-bottom:.5em;"> - Wearable apps that run directly on the device are packaged inside the primary handheld app. + Wearable apps that are dependent on a handheld app for functionality are packaged inside that + handheld app. (<a href="{@docRoot}training/wearables/apps/packaging.html">Learn how</a>) </p> </td> @@ -187,6 +187,22 @@ page.image=/distribute/images/gp-wear-quality.png </td> </tr> +<tr> + <td rowspan="1" id="watchface"> + Watch Face + </td> + + <td id="WR-WF"> + WR-WF + </td> + <td> + <p style="margin-bottom:.5em;"> + Apps that include watch faces use the official Watch Face API. + (<a href="{@docRoot}training/wearables/watch-faces/index.html">Learn how</a>) + </p> + </td> +</tr> + </table> @@ -248,8 +264,9 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6"> </td> <td> <p style="margin-bottom:.5em;"> - App user interface is formatted appropriately for round displays. App content fits within - the physical display area and no text or controls are cut off by the screen edges. + App user interface is formatted appropriately for round displays including devices with an + inset (or "chin") at the bottom of the screen. App content fits within the physical display + area and no text or controls are cut off by the screen edges. <br/> (<a href="{@docRoot}training/wearables/ui/layouts.html">Learn how</a>) </p> @@ -367,6 +384,7 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6"> </td> </tr> + </table> @@ -399,9 +417,8 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6"> for Wear <a href="#ux">design and interaction</a>. </p> <p class="note"> - <strong>Note:</strong> You will be able to submit your apps for Android Wear review soon. - Stay tuned for more information about how to submit your apps for Android Wear review through - the <a href="https://play.google.com/apps/publish/signup/">Google Play Developer Console</a>. + <strong>Note:</strong> For information about how to publish your Wear apps in Google Play, see <a + href="{@docRoot}distribute/googleplay/wear.html">Distributing to Android Wear</a>. </p> diff --git a/docs/html/distribute/googleplay/googleplay_toc.cs b/docs/html/distribute/googleplay/googleplay_toc.cs index b3aa9bf..92475ff 100644 --- a/docs/html/distribute/googleplay/googleplay_toc.cs +++ b/docs/html/distribute/googleplay/googleplay_toc.cs @@ -30,6 +30,12 @@ </div> </li> <li class="nav-section"> + <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/wear.html"> + <span class="en">Distributing to <span style="white-space:nowrap">Android Wear</span></span> + </a> + </div> + </li> + <li class="nav-section"> <div class="nav-section-header" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/edu/about.html"> <span class="en">Google Play for Education</span> </a> diff --git a/docs/html/distribute/googleplay/wear.jd b/docs/html/distribute/googleplay/wear.jd new file mode 100644 index 0000000..c0a0017 --- /dev/null +++ b/docs/html/distribute/googleplay/wear.jd @@ -0,0 +1,275 @@ +page.title=Distributing to Android Wear +page.image=/design/media/wear/ContextualExample.008_2x.png +meta.tags="wear", "publish", "quality" +page.tags="wear", "publish", "googleplay" +page.metaDescription=Distribute your apps, games, and content to Android Wear. + +@jd:body + +<div id="qv-wrapper"><div id="qv"> +<h2>How to Participate</h2> +<ol> +<li><a href="#understand_guidelines">Understand the guidelines</a></li> +<li><a href="#develop_app">Develop a great app for Wear</a></li> +<li><a href="#test_app">Test for Wear App Quality</a></li> +<li><a href="#opt_in">Opt-in</a></li> +<li><a href="#track_review">Track your review</a></li> +</ol> + +<h2>You Should Also Read</h2> +<ol> +<li><a href="{@docRoot}distribute/essentials/quality/wear.html">Wear App Quality</a></li> +<li><a href="{@docRoot}distribute/essentials/quality/core.html">Core App Quality</a></li> +</ol> + +</div></div> + +<p> + If you've got a great app, Android Wear and Google Play can help you bring it to users. While all + apps are able to send basic notifications to Android Wear devices, you can go much further. + Extend your apps to support custom Wear interactions and offer a refined, engaging user + experience across all Wear devices. If your apps meet core app quality guidelines on handsets and + provide a high-quality experience for Android Wear devices, Google Play will showcase your apps + for easy discovery. +</p> + +<p> + To get started, review the sections in this document to learn how to distribute your Wear apps + to users through Google Play. Be sure to read <a + href="{@docRoot}distribute/essentials/quality/wear.html">Wear App Quality</a> for information on + the usability and quality standards that your apps should meet. When your app is ready, you can + opt-in for designation as an Android Wear app from the Developer Console. +</p> + +<h2 id="how_to_participate"> + How to Participate +</h2> + +<p> + Google Play lets you make your Wear apps more discoverable for Wear users. You can develop and + publish using your existing Developer Console account and your current distribution and pricing + settings. It's easy to participate — the sections below outline the process. +</p> + +<h3 id="understand_guidelines"> + 1. Understand guidelines and requirements +</h3> + +<div style="float:right;margin:1em 0 1.5em 2em;"> + <img src="{@docRoot}images/gp-wear-process.png"> +</div> + +<p> + To prepare for a successful launch on Android Wear, start by reviewing the guidelines for + creating great app experiences on Wear. See the <a href="{@docRoot}design/wear/index.html">Android + Wear design guidelines</a> for ideas on extending your app for Wear and details on design and + usability. +</p> + +<p> + As you get started designing your Wear experience, make sure to read and understand the quality + criteria for Wear apps. Only apps that are usable on Wear will be designated as Wear apps on + Google Play — your apps can participate if they meet a set of basic quality criteria. See <a + href="{@docRoot}distribute/essentials/quality/wear.html">Wear App Quality</a> for details. +</p> + +<h3 id="develop_app">2. Develop a great app for Wear</h3> + +<p> +Once you have read the guidelines, the next step is to develop your app. The following sections +describe how to start building a great app experience for Wear. +</p> + +<h4>Design first</h4> + +<p> + Android Wear aims to provide users with just the right information at just the right time. Great + Android Wear experiences are launched automatically, glanceable, and + require zero or low user interaction. Although all apps can send basic notifications to Wear + devices without any modification, great apps built for Wear are refined to offer a polished and + high-quality experience, work on different screen layouts, and deliver a compelling feature set + for users. +</p> + +<p> + As you consider your Wear app, review the <a href= + "{@docRoot}training/building-wearables.html">developer documentation</a> and <a + href="{@docRoot}design/wear/index.html">usability guidelines</a> and plan on utilizing them to the + greatest extent possible. You can design a great notification experience for users with the APIs + provided in the SDK and support library. You may also choose to build an app that runs directly + on the wearable. +</p> + +<h4>Package your app</h4> + +<p> + We recommend that you deliver your Wear experience as part of your existing app for phones, + tablets, and other devices, using the same package name and store listing. This lets users + upgrade to your Wear experience seamlessly and also lets you take advantage of the reviews and + ratings you’ve earned in your app for phones and tablets. For wearable apps that depend on an + app for functionality, you should always package it within that app. To learn how, read <a + href="{@docRoot}training/wearables/apps/packaging.html">Packaging Wearable Apps</a>. +</p> + +<h4>Test on a variety of devices</h4> + +<p> + Throughout design and development, it's important to have suitable devices on which to prototype + and test your user experience. It's highly recommended that you acquire one or more Android Wear + devices or develop with different emulator configurations and set up your testing environment as + early as possible. It’s important that you optimize your design on both square and round layouts. +</p> + +<h3 id="test_app">3. Test for Wear App Quality</h3> + +<p> + Your Wear apps should be designed to perform well and look great on Android Wear, and they should + offer the best user experience possible. Google Play will showcase selected high-quality Wear + apps for easy discovery. Here’s how you can participate and deliver an Android Wear app that + users will enjoy: +</p> + +<ul> + <li>Meet Core App Quality guidelines + <ul> + <li>Follow <a href="{@docRoot}design/index.html">Android Design + guidelines</a>. Pay special attention to using <a href= + "http://www.google.com/design/spec/material-design/introduction.html">material + design</a> in your app. + </li> + + <li>Test your apps against the <a href= + "{@docRoot}distribute/essentials/quality/core.html">Core App Quality + guidelines</a>. + </li> + </ul> + </li> + <li>Meet <a href="{@docRoot}distribute/essentials/quality/wear.html">Wear App + Quality</a> criteria + <ul> + <li>Follow our best practices for <a href="{@docRoot}training/building-wearables.html"> + Wear app development</a></li> + <li>Make sure your app meets all of the <a href= + "{@docRoot}distribute/essentials/quality/wear.html">Wear App Quality</a> criteria</li> + </ul> + </li> +</ul> + +<h3 id="opt_in">4. Opt-in to Android Wear and publish</h3> + +<p> + When you've built your release-ready APK and tested to ensure that it meets all of the <a + href="{@docRoot}distribute/essentials/quality/wear.html">Wear App Quality</a> criteria, upload it + to the Developer Console. Update your store listing with Wear screenshots and set distribution + options as needed. If you aren't familiar with how to prepare for launch on Google Play, see the + <a href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch Checklist.</a> +</p> + +<p> + Before you publish to users, you may opt-in to Android Wear from the <strong>Pricing and + Distribution</strong> section of the Developer Console. Opt-in means that you want your app to + be made more discoverable to Android Wear users through Google Play, and that your app meets <a + href="{@docRoot}distribute/essentials/quality/wear.html">Wear App Quality</a> criteria. +</p> + +<p> + After you've opted-in and saved changes, you can publish your app as usual. In addition, Google + Play submits your app for review against the <a + href="{@docRoot}distribute/essentials/quality/wear.html">Wear App Quality</a> criteria and + notifies you of the result. See the next section for details on how to track the approval status + of your app. +</p> + +<p> + If your app meets all <a href="{@docRoot}distribute/essentials/quality/wear.html">Wear App + Quality</a> criteria, Google Play makes it more discoverable to Android Wear users. Your app is + also eligible for higher-visibility featuring in app collections and promotions. +</p> + +<p> + Note that opt-in and review do not affect the availability of your app in the Google Play Store + — your app is available as soon as you publish. +</p> + +<p> + Here are the steps to opt-in to Android Wear in the Developer Console: +</p> + +<ol> + <li>Make sure your app meets all <a href= + "{@docRoot}distribute/essentials/quality/wear.html">Wear App Quality</a> criteria + </li> + + <li>Add Wear screenshots to the app’s store listing + </li> + + <li>In the <strong>All Applications</strong> page, click the app you want to opt-in. + </li> + + <li>Under <strong>Pricing and Distribution</strong>, scroll down to find <em>Android Wear</em> + and the opt-in checkbox. + </li> + + <li>Click the checkbox next to <em>Distribute your app on Android Wear</em>. + </li> + + <li>Click <strong>Save</strong> to save your Pricing and Distribution changes. + </li> +</ol> + +<div style="padding-top:1em"> + <img style="border:2px solid #ddd;" src="{@docRoot}images/gp-wear-opt-in.png"> + <p class="caption"> + <strong>Opt-in for Wear:</strong> Include your app in Android Wear by opting-in from the + Developer Console. + </p> +</div> + +<h3 id="track_review">5. Track your review and approval</h3> + +<p> + If your app meets the technical and quality criteria for Android Wear, as described above, your + app will be made more discoverable for users on Android Wear. If your app doesn’t meet the + criteria, you’ll receive a <strong>notification email sent to your developer account + address</strong>, with a summary of the areas that you need to address. When you’ve made the + necessary adjustments, you can upload a new version of your app to the Developer Console. +</p> + +<p> + At any time, you can check the review and approval status of your app in the Developer Console, + under <em>Android Wear</em> in the app's <strong>Pricing and Distribution</strong> + page. +</p> + +<p> + There are three approval states: +</p> + +<ul> + <li> + <em>Pending</em> — Your app was sent for review and the review is not yet complete. + </li> + + <li> + <em>Approved</em> — Your app was reviewed and approved. The app will be made more discoverable + to Android Wear users. + </li> + + <li> + <em>Not approved</em> — Your app was reviewed and not approved. Check the notification email + for information about why the app was not approved. You can address any issues and opt-in and + publish again to initiate another review. + </li> +</ul> + +<p>To understand how your apps are evaluated, please see the <a href= +"{@docRoot}distribute/essentials/quality/wear.html">Wear App Quality</a> document. </p> + + + <h3>Related resources</h3> + + <div class="resource-widget resource-flow-layout col-13" + data-query="collection:wearlanding" + data-cardSizes="6x2" + data-maxResults="3"> + </div> diff --git a/docs/html/google/play-services/index.jd b/docs/html/google/play-services/index.jd index 8578f96..b3cd4cf 100644 --- a/docs/html/google/play-services/index.jd +++ b/docs/html/google/play-services/index.jd @@ -134,6 +134,22 @@ enables you to get a ready-to-use Street View panorama. when compiling your app. For more details, see the Android Studio setup instructions in <a href="{@docRoot}google/play-services/setup.html">Setting Up Google Play Services</a>. + </li> + <li><strong>Deprecated clients</strong> - The {@code ActivityRecognitionClient}, + {@code LocationClient}, and {@code PlusClient} classes are deprecated. If + you used those APIs in your app and want to call Google Play services 6.5 + or higher APIs, you must switch to the new programming model that utilizes + <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code GoogleApiClient}</a>. For more information about using <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code GoogleApiClient}</a>, see <a href="{@docRoot}google/auth/api-client.html">Accessing Google APIs</a>. + <p>Use these APIs instead of the deprecated APIs:</p> + <ul> + <li>If you were previously using {@code ActivityRecognitionClient}, call + <a href="{@docRoot}reference/com/google/android/gms/location/ActivityRecognition.html">{@code ActivityRecognition}</a> instead.</li> + <li>If you were previously using {@code LocationClient}, call the APIs in the + <a href="{@docRoot}reference/com/google/android/gms/location/package-summary.html">{@code com.google.android.gms.location} package</a> instead.</li> + <li>If you were previously using {@code PlusClient}, call the APIs in the + <a href="{@docRoot}reference/com/google/android/gms/plus/package-summary.html">{@code com.google.android.gms.plus} package</a> instead.</li> + </ul> + </li> </ul> </dd> </dl> diff --git a/docs/html/images/gp-wear-opt-in.png b/docs/html/images/gp-wear-opt-in.png Binary files differnew file mode 100644 index 0000000..139ce50 --- /dev/null +++ b/docs/html/images/gp-wear-opt-in.png diff --git a/docs/html/images/gp-wear-process.png b/docs/html/images/gp-wear-process.png Binary files differnew file mode 100644 index 0000000..4b55aed --- /dev/null +++ b/docs/html/images/gp-wear-process.png diff --git a/docs/html/images/tools/projectview01.png b/docs/html/images/tools/projectview01.png Binary files differindex 90589fb..2deb752 100644 --- a/docs/html/images/tools/projectview01.png +++ b/docs/html/images/tools/projectview01.png diff --git a/docs/html/images/tools/studio-cloudmodule.png b/docs/html/images/tools/studio-cloudmodule.png Binary files differindex b7c4fb7..cffa2d5 100644 --- a/docs/html/images/tools/studio-cloudmodule.png +++ b/docs/html/images/tools/studio-cloudmodule.png diff --git a/docs/html/images/tools/studio-helloworld-design.png b/docs/html/images/tools/studio-helloworld-design.png Binary files differindex ff90c6b..a355e7a 100644 --- a/docs/html/images/tools/studio-helloworld-design.png +++ b/docs/html/images/tools/studio-helloworld-design.png diff --git a/docs/html/images/tools/studio-helloworld-text.png b/docs/html/images/tools/studio-helloworld-text.png Binary files differindex 5dde675..28e39fe 100644 --- a/docs/html/images/tools/studio-helloworld-text.png +++ b/docs/html/images/tools/studio-helloworld-text.png diff --git a/docs/html/images/tools/studio-projectview_scripts.png b/docs/html/images/tools/studio-projectview_scripts.png Binary files differindex 3e7b9cd..a0565c5 100644 --- a/docs/html/images/tools/studio-projectview_scripts.png +++ b/docs/html/images/tools/studio-projectview_scripts.png diff --git a/docs/html/images/tools/studio-samples-githubaccess.png b/docs/html/images/tools/studio-samples-githubaccess.png Binary files differindex 991bf69..3980361 100644 --- a/docs/html/images/tools/studio-samples-githubaccess.png +++ b/docs/html/images/tools/studio-samples-githubaccess.png diff --git a/docs/html/images/tools/studio-setup-wizard.png b/docs/html/images/tools/studio-setup-wizard.png Binary files differindex f84660a..ccd92d3 100644 --- a/docs/html/images/tools/studio-setup-wizard.png +++ b/docs/html/images/tools/studio-setup-wizard.png diff --git a/docs/html/images/tools/studio-tvwearsupport.png b/docs/html/images/tools/studio-tvwearsupport.png Binary files differindex 02bf484..88343a6 100644 --- a/docs/html/images/tools/studio-tvwearsupport.png +++ b/docs/html/images/tools/studio-tvwearsupport.png diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js index f483e31..1b7cfc9 100644 --- a/docs/html/jd_collections.js +++ b/docs/html/jd_collections.js @@ -67,6 +67,7 @@ var RESOURCE_COLLECTIONS = { "resources": [ "distribute/googleplay/guide.html", "distribute/googleplay/tv.html", + "distribute/googleplay/wear.html", "distribute/googleplay/edu/about.html" ] }, @@ -996,6 +997,14 @@ var RESOURCE_COLLECTIONS = { "training/tv/index.html" ] }, + "wearlanding": { + "title": "", + "resources": [ + "design/wear/index.html", + "training/building-wearables.html", + "training/wearables/ui/index.html" + ] + }, "play_dev_guide": { "title": "", "resources": [ diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd index 8412609..986862b 100644 --- a/docs/html/sdk/index.jd +++ b/docs/html/sdk/index.jd @@ -1,8 +1,8 @@ -page.title=Android Studio +page.title=Download Android Studio and SDK Tools page.tags=download page.template=sdk header.hide=1 -page.metaDescription=Download the official Android developer tools to build apps for Android phones, tablets, wearables, TVs, and more. +page.metaDescription=Download the official Android IDE and developer tools to build apps for Android phones, tablets, wearables, TVs, and more. studio.version=1.0.0 @@ -281,7 +281,7 @@ This is the Android Software Development Kit License Agreement <img src="{@docRoot}images/tools/studio-hero.png" srcset="{@docRoot}images/tools/studio-hero_2x.png 2x, {@docRoot}images/tools/studio-hero.png 1x" -width="760" height="400" alt="" style="margin-bottom:60px" /> +width="760" height="400" alt="" style="margin-bottom:80px" /> <div style="color: #fff; width:226px; height:0; overflow:visible; position:absolute; top:40px; left:25px"> @@ -311,6 +311,8 @@ href="http://developer.android.com/sdk/index.html">developer.android.com/sdk/</a <li><a href="#Requirements">System Requirements</a></li> <li><a href="#Other">Other Download Options</a></li> <li><a href="{@docRoot}sdk/installing/migrate.html">Migrating to Android Studio</a></li> + <li><a href="https://docs.google.com/a/google.com/forms/d/1mjsyfzv3HAnDY-_Kfj-3QJKdpuksyMFs9e73CRwmT6Q/viewform" +target="_blank">Take a Survey</a></li> </ul> </div> @@ -427,8 +429,9 @@ read the guide to <a href="{@docRoot}tools/studio/index.html" </div> -<p>If you've been using Eclipse with ADT, be aware that the ADT plugin is no longer in active -development, so you should migrate to Android Studio as soon as possible. For help moving projects, +<p>If you have been using Eclipse with ADT, be aware that Android Studio is now the official IDE +for Android, so you should migrate to Android Studio to receive all the +latest IDE updates. For help moving projects, see <a href="{@docRoot}sdk/installing/migrate.html">Migrating to Android Studio</a>.</p> diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd index 744ce15..14d274f 100644 --- a/docs/html/sdk/installing/index.jd +++ b/docs/html/sdk/installing/index.jd @@ -28,9 +28,8 @@ p.paging-links { <!-- ################ STUDIO ##################### --> <div id="studio" heading="Installing Android Studio" style="display:none"> -<p>Android Studio provides the tools you need to start developing apps, including -the Android Studio IDE (powered by IntelliJ) and guides you to install -the Android SDK tools to streamline your Android app development.</p> +<p>Android Studio provides everything you need to start developing apps for Android, including +the Android Studio IDE and the Android SDK tools.</p> <p>If you didn't download Android Studio, go <a href="{@docRoot}sdk/index.html" ><b>download Android Studio now</b></a>, or switch to the @@ -39,7 +38,8 @@ install</a> instructions.</p> <p>Before you set up Android Studio, be sure you have installed -JDK 6 or greater (the JRE alone is not sufficient). To check if you +JDK 6 or higher (the JRE alone is not sufficient)—JDK 7 is required when +developing for Android 5.0 and higher. To check if you have JDK installed (and which version), open a terminal and type <code>javac -version</code>. If the JDK is not available or the version is lower than 6, <a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html" class="external-link" @@ -57,7 +57,7 @@ style="float:right;font-size:13px"><a href='' onclick='showAll();return false;' <p><b>To set up Android Studio on Windows:</b></p> <ol> <li>Launch the <code>.exe</code> file you just downloaded.</li> - <li>Follow the setup wizard to install Android Studio and the SDK Tools. + <li>Follow the setup wizard to install Android Studio and any necessary SDK tools. <p>On some Windows systems, the launcher script does not find where Java is installed. If you encounter this problem, @@ -88,7 +88,7 @@ where they are installed. For example:</p> <ol> <li>Launch the {@code .dmg} file you just downloaded.</li> <li>Drag and drop Android Studio into the Applications folder. - <li>Open Android Studio and follow the instructions to set up the SDK. + <li>Open Android Studio and follow the setup wizard to install any necessary SDK tools. <p> Depending on your security settings, when you attempt to open Android Studio, you might see a warning that says the package is damaged and should be moved to the trash. If this @@ -118,7 +118,7 @@ you can access them at:</p> <p>You may want to add {@code android-studio/bin/} to your PATH environmental variable so that you can start Android Studio from any directory.</p> </li> - <li>Follow the links to install the SDK tools outside of the Android Studio directories.</li> + <li>Follow the setup wizard to install any necessary SDK tools.</li> </ol> </div><!-- end linux --> @@ -226,8 +226,7 @@ the SDK tools from the command line.</p> <li><a href="https://help.ubuntu.com/community/Java">https://help.ubuntu.com/community/JavaInstallation</a></li> </ul> </li> - <li>Here are the steps to install Java and Eclipse, prior to installing - the Android SDK and ADT Plugin. + <li>Here are the steps to install Java: <ol> <li><p>If you are running a 64-bit distribution on your development machine, you need to install additional packages first. For Ubuntu 13.10 (Saucy Salamander) @@ -241,13 +240,6 @@ sudo apt-get install libncurses5:i386 libstdc++6:i386 zlib1g:i386</pre> <pre class="no-pretty-print">apt-get install ia32-libs</pre> </li> <li>Next, install Java: <pre class="no-pretty-print">apt-get install sun-java6-jdk</pre></li> - <li>The Ubuntu package manager does not currently offer an Eclipse 3.7 - version for download, so we recommend that you download Eclipse from - eclipse.org (<a - href="http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a>). - A Java or RCP version of Eclipse is recommended.</li> - <li>Follow the steps given in previous sections to install the SDK - and the ADT plugin. </li> </ol> </li> </ul> @@ -272,47 +264,6 @@ Continue: Adding SDK Packages</a></p> -<!-- ################### ADT BUNDLE ####################### --> -<div id="adt" heading="Installing the Eclipse ADT Bundle" style="display:none"> - - -<p>The Eclipse ADT Bundle provides everything you need to start developing apps, including -the Android SDK tools and a version of the Eclipse IDE with built-in ADT -(Android Developer Tools) to streamline your Android app development.</p> - -<p>If you didn't download the Eclipse ADT bundle, go <a href="{@docRoot}tools/eclipse/index.html" -><b>download the Eclipse ADT bundle now</b></a>, or switch to the -<a href="{@docRoot}sdk/installing/index.html?pkg=studio">Android Studio -install</a> or <a href="{@docRoot}sdk/installing/index.html?pkg=tools">stand-alone SDK Tools -install</a> instructions</i>.</p> - -<div class="procedure-box"> -<p><b>To set up the ADT Bundle:</b></p> -<ol> -<li>Unpack the ZIP file -(named {@code adt-bundle-<os_platform>.zip}) and save it to an appropriate location, -such as a "Development" directory in your home directory.</li> -<li>Open the {@code adt-bundle-<os_platform>/eclipse/} directory and launch -<strong>Eclipse</strong>.</li> -</ol> - -<p class="caution"><strong>Caution:</strong> Do not move any of the files or directories -from the {@code adt-bundle-<os_platform>} directory. If you move the {@code eclipse/} -or {@code sdk/} directory, ADT will not be able to locate the SDK and you'll -need to manually update the ADT preferences.</p> -</div> - -<p>Eclipse with ADT is now ready and loaded with the Android developer tools, but there are still -a couple packages you should add to make your Android SDK complete.</p> - -<p class="paging-links"> -<a href="{@docRoot}sdk/installing/adding-packages.html" class="next-page-link"> -Continue: Adding SDK Packages</a></p> - - -</div> -<!-- ################ END ADT BUNDLE ##################### --> - @@ -368,10 +319,6 @@ if (package == "tools") { // Show the SDK Tools (other IDE) instructions $("h1").text($("#tools").attr('heading')); $("#tools").show(); -} else if (package == "adt") { - // Show the ADT instructions - $("h1").text($("#adt").attr('heading')); - $("#adt").show(); } else if (package == "studio") { // Show the Android Studio instructions $("h1").text($("#studio").attr('heading')); diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd index c8200aa..0114848 100644 --- a/docs/html/sdk/installing/installing-adt.jd +++ b/docs/html/sdk/installing/installing-adt.jd @@ -15,12 +15,18 @@ of Eclipse to let you quickly set up new Android projects, build an app UI, debug your app, and export signed (or unsigned) app packages (APKs) for distribution. </p> -<p class="note"><strong>Note:</strong> You should install the ADT plugin -only if you already have an Eclipse installation that you want to continue using. If you do not -have Eclipse installed, you should instead <b><a href="{@docRoot}sdk/index.html">install -the complete Android SDK</a></b>, which includes the latest IDE for Android developers.</p> - -<p>Your existing Eclipse installation must meet these requirements:</p> +<p class="note"><strong>Note:</strong> +If you have been using Eclipse with ADT, be aware that <a +href="{@docRoot}tools/studio/index.html">Android Studio</a> is now the official IDE +for Android, so you should migrate to Android Studio to receive all the +latest IDE updates. For help moving projects, +see <a href="/sdk/installing/migrate.html">Migrating to Android +Studio</a>.</p> + + +<p>You should install the ADT plugin +only if you already have an Eclipse installation that you want to continue using. +Your existing Eclipse installation must meet these requirements:</p> <ul> <li><a href="http://eclipse.org/mobile/">Eclipse</a> 3.7.2 (Indigo) or greater <p class="note"><strong>Note:</strong> Eclipse 3.6 (Helios) is no longer diff --git a/docs/html/sdk/installing/migrate.jd b/docs/html/sdk/installing/migrate.jd index c99cc30..3c04cb4 100644 --- a/docs/html/sdk/installing/migrate.jd +++ b/docs/html/sdk/installing/migrate.jd @@ -6,7 +6,8 @@ page.title=Migrating to Android Studio <div id="qv"> <h2>See also</h2> <ul> - <li><a href="http://confluence.jetbrains.com/display/IntelliJIDEA/FAQ+on+Migrating+to+IntelliJ+IDEA">IntelliJ FAQ on migrating to IntelliJ IDEA</a></li> + <li><a href="http://confluence.jetbrains.com/display/IntelliJIDEA/FAQ+on+Migrating+to+IntelliJ+IDEA" + class="external-link">IntelliJ FAQ on migrating to IntelliJ IDEA</a></li> <li><a href="http://confluence.jetbrains.com/display/IntelliJIDEA/Working+in+Eclipse+Compatibility+Mode" class="external-link" >Eclipse Compatibility Mode</a></li> <li><a href="http://confluence.jetbrains.com/display/IntelliJIDEA/FAQ+on+Migrating+to+IntelliJ+IDEA" class="external-link" @@ -15,41 +16,27 @@ page.title=Migrating to Android Studio </div> </div> -<p>If you're currently using Eclipse with ADT, we recommend you migrate to -<a href="{@docRoot}tools/studio/index.html">Android Studio</a> as soon as possible, because -the ADT plugin for Eclipse is no longer in active development.</p> +<p>If you have been using <a href="{@docRoot}tools/help/adt.html">Eclipse with ADT</a>, be aware +that <a href="{@docRoot}tools/studio/index.html">Android Studio</a> is now the official IDE for +Android, so you should migrate to Android Studio to receive all the latest IDE updates.</p> -<p>To migrate existing Android projects from Eclipse, -you should export your projects from Eclipse in order to generate -Gradle build files:</p> - -<ol> - <li>In Eclipse, select <strong>File > Export</strong>.</li> - <li>Select <strong>Generate Gradle build files</strong> inside the Android folder, then click - <strong>Next</strong>.</li> - <li>Click <strong>Browse</strong> to find your project to export.</li> - <li>Select your project from the list, click <strong>OK</strong>, then <strong>Finish</strong>.</li> -</ol> - - -<p>You can then import the project into Android Studio:</p> +<p>To migrate existing Android projects, simply import them using Android Studio:</p> <ol> <li>In Android Studio, close any projects currently open. You should see the <strong>Welcome to Android Studio</strong> window.</li> - <li>Click <strong>Import Project</strong>.</li> + <li>Click <strong>Import Non-Android Studio project</strong>.</li> <li>Locate the project you exported from Eclipse, expand it, select the <strong>build.gradle</strong> file and click <strong>OK</strong>.</li> <li>In the following dialog, leave <strong>Use gradle wrapper</strong> selected and click <strong>OK</strong>. (You do not need to specify the Gradle home.)</li> </ol> -<p>It's possible to import an existing Android project to Android Studio even if you -don't generate a Gradle build file from Eclipse—Android Studio will successfully build and -run projects using an existing Ant build file. However, in order to take advantage of build -variants and other advanced features in the future, -you should generate a Gradle build file using -the ADT plugin or write your own Gradle build file for use with Android Studio.</p> +<p>Android Studio properly updates the project structure and creates the appropriate +Gradle build file.</p> -<p><a href="{@docRoot}tools/studio/index.html">Learn more about Android Studio</a>.</p> +<p>For more help getting started with Android Studio and the IntelliJ user experience, +<a href="{@docRoot}tools/studio/index.html">learn more about Android Studio</a> and +read <a href="http://confluence.jetbrains.com/display/IntelliJIDEA/FAQ+on+Migrating+to+IntelliJ+IDEA" + class="external-link">FAQ on Migrating to IntelliJ IDEA</a>.</p> diff --git a/docs/html/sdk/installing/studio-build.jd b/docs/html/sdk/installing/studio-build.jd index c80368f..4fe9071 100644 --- a/docs/html/sdk/installing/studio-build.jd +++ b/docs/html/sdk/installing/studio-build.jd @@ -13,7 +13,7 @@ page.title=Build System Overview <li><a href="{@docRoot}sdk/installing/studio.html"> Getting Started with Android Studio</a></li> <li><a href="{@docRoot}tools/studio/index.html">Android Studio Basics</a></li> - <li><a href="{@docRoot}tools/eclipse/migrate-adt.html">Migrating from Eclipse</a></li> + <li><a href="{@docRoot}sdk/installing/migrate.html">Migrating from Eclipse</a></li> </div> </div> diff --git a/docs/html/sdk/installing/studio-tips.jd b/docs/html/sdk/installing/studio-tips.jd index fba7a70..8e7e345 100644 --- a/docs/html/sdk/installing/studio-tips.jd +++ b/docs/html/sdk/installing/studio-tips.jd @@ -40,25 +40,19 @@ For example, if you add a button to the layout without specifying the <em>width< add all missing attributs</em>. Clicking the message adds the missing attributes to the layout.</p> -<h2>Output window message filtering</h2> -<p>When checking build results, you can filter messages by <em>message type</em> to quickly -locate messages of interest.</p> -<img src="{@docRoot}images/tools/studio-outputwindowmsgfiltering.png" style="width:200px"style="width:200px" /> -<p class="img-caption"><strong>Figure 14.</strong> Filter Build Messages</p> - <h3> Bitmap rendering in the debugger</h3> <p>While debugging, you can now right-click on bitmap variables in your app and invoke <em>View Bitmap</em>. This fetches the associated data from the debugged process and renders the bitmap in the debugger. </p> <p><img src="{@docRoot}images/tools/studio-bitmap-rendering.png" style="width:350px"/></p> -<p class="img-caption"><strong>Figure 2.</strong> Bitmap Rendering</p> +<p class="img-caption"><strong>Figure 1.</strong> Bitmap Rendering</p> <h3>Output window message filtering</h3> <p>When checking build results, you can filter messages by <em>message type</em> to quickly locate messages of interest.</p> <img src="{@docRoot}images/tools/studio-outputwindowmsgfiltering.png" style="width:200px"style="width:200px" /> -<p class="img-caption"><strong>Figure 3.</strong> Filter Build Messages</p> +<p class="img-caption"><strong>Figure 2.</strong> Filter Build Messages</p> <h3>Hierarchical parent setting</h3> @@ -79,7 +73,7 @@ including the preview device, layout theme, platform version and more. To previe multiple devices simultaneously, select <strong>Preview All Screen Sizes</strong> from the device drop-down.</p> <p><img src="{@docRoot}images/tools/studio-previewall.png" style="width:350px"/></p> -<p class="img-caption"><strong>Figure 4.</strong> Preview All Screens</p> +<p class="img-caption"><strong>Figure 3.</strong> Preview All Screens</p> <p>You can switch to the graphical editor by clicking <strong>Design</strong> at the bottom of the window. While editing in the Design view, you can show and hide the @@ -166,7 +160,7 @@ resolved values for the various attributes that are pulled in.</p> </strong> <code>F1</code>, see the theme inheritance hierarchy, and resolved values for the various attributes.</p> <img src="{@docRoot}images/tools/studio-allocationtracker.png" style="width:300px" /> -<p class="img-caption"><strong>Figure 1.</strong> Allocation Tracker</p> +<p class="img-caption"><strong>Figure 4.</strong> Allocation Tracker</p> <h3 id="key-commands">Keyboard Commands</h3> diff --git a/docs/html/tools/eclipse/index.jd b/docs/html/tools/eclipse/index.jd deleted file mode 100644 index c8a998b..0000000 --- a/docs/html/tools/eclipse/index.jd +++ /dev/null @@ -1,37 +0,0 @@ -page.title=Eclipse ADT -@jd:body - - -<div id="qv-wrapper"> -<div id="qv"> - <h2>See also</h2> - <ol> - <li><a href="{@docRoot}tools/sdk/index.html">Downloading Android Studio</a></li> - <li><a href="{@docRoot}tools/studio/index.html">Android Studio</a></li> - <li><a href="{@docRoot}tools/eclipse/migrate-adt.html">Migrating to Android Studio</a></li> - </ol> -</div> -</div> - - -<p>The Android Developer Tools (ADT) plugin for Eclipse provides a professional-grade development -environment for building Android apps. It's a full Java IDE with advanced features to help you build, -test, debug, and package your Android apps. </p> - -<p>Android developers are encouraged to <a href="{@docRoot}tools/eclipse/migrate-adt.html">migrate -to Android Studio</a> as the Eclipse ADT is no longer in active development. -</p> - -<p>The Android Studio build system replaces the Apache Ant build software used with Eclipse ADT -with an Android plugin for <em>Gradle</em>. <a href="http://www.gradle.org/">Gradle</a> is an -advanced build toolkit that manages dependencies and allows you to define custom build logic. Android -Studio also adds support for Maven-based build dependencies, build variants, advanced code -completion and refactoring. For more details about Android Studio, see the -<a href="{@docRoot}tools/studio/index.html">Android Studio</a> guide. - -<p>If you still wish to get started with the ADT plugin, -<a href="{@docRoot}tools/eclipse/installing-adt.html">download and install the Eclipse ADT plugin.</a> -</p> - -</div> -</div> diff --git a/docs/html/tools/help/adt.jd b/docs/html/tools/help/adt.jd index 1bb3015..0130524 100644 --- a/docs/html/tools/help/adt.jd +++ b/docs/html/tools/help/adt.jd @@ -24,63 +24,30 @@ page.tags=adt </li> <li><a href="#refactoring">Layout Factoring Support</a></li> - <li><a href="#Updating">Updating the ADT Plugin</h2> + <li><a href="#Updating">Updating the ADT Plugin</a></li> </ol> - - <h2>Related videos</h2> - - <ol> - <li><a href="{@docRoot}videos/index.html#v=Oq05KqjXTvs">Android Developer Tools - Google I/O Session</a> - </li> - </ol> - - <h2>See also</h2> - - <ol> - <li><a href="http://tools.android.com/recent">Android Tools change blog</a></li> - </ol> </div> </div> <p>ADT (Android Developer Tools) is a plugin for Eclipse that provides a suite of tools that are integrated with the Eclipse IDE. It offers you access to many features that help - you develop Android applications quickly. ADT + you develop Android applications. ADT provides GUI access to many of the command line SDK tools as well as a UI design tool for rapid prototyping, designing, and building of your application's user interface.</p> - <p>Because ADT is a plugin for Eclipse, you get the functionality of a well-established IDE, - along with Android-specific features that are bundled with ADT. The following - describes important features of Eclipse and ADT:</p> +<p class="note"><strong>Note:</strong> +If you have been using Eclipse with ADT, be aware that <a +href="{@docRoot}tools/studio/index.html">Android Studio</a> is now the official IDE +for Android, so you should migrate to Android Studio to receive all the +latest IDE updates. For help moving projects, +see <a href="/sdk/installing/migrate.html">Migrating to Android +Studio</a>.</p> - <dl> - <dt><strong>Integrated Android project creation, building, packaging, installation, and - debugging</strong></dt> - - <dd>ADT integrates many development workflow tasks into Eclipse, making it easy for you to - rapidly develop and test your Android applications.</dd> - - <dt><strong>SDK Tools integration</strong></dt> - - <dd>Many of the <a href="#tools">SDK tools</a> are integrated into Eclipse's menus, - perspectives, or as a part of background processes ran by ADT.</dd> - - <dt><strong>Java programming language and XML editors</strong></dt> - - <dd>The Java programming language editor contains common IDE features such as compile time - syntax checking, auto-completion, and integrated documentation for the Android framework APIs. - ADT also provides custom XML editors that let you - edit Android-specific XML files in a form-based UI. A graphical layout editor lets you design - user interfaces with a drag and drop interface.</dd> - - <dt><strong>Integrated documentation for Android framework APIs</strong></dt> - <dd>You can access documentation by hovering over classes, methods, or variables.</dd> - </dl> +<p>If you still wish to use the ADT plugin for Eclipse, see +<a href="{@docRoot}sdk/installing/installing-adt.html">Installing Eclipse Plugin.</a> +</p> - <p>You can find the most up-to-date and more detailed information about changes and new features -on the <a href="http://tools.android.com/recent">Recent Changes</a> page at the Android Tools -Project site.</p> <h2 id="tools">SDK Tools Integration</h2> @@ -568,5 +535,6 @@ to install it. </p> <p>If you encounter problems during the update, remove the existing ADT plugin from Eclipse, then -perform a fresh installation, using the instructions for <a href="#installing">Installing the ADT +perform a fresh installation, using the instructions for <a +href="{@docRoot}sdk/installing/installing-adt.html">Installing the ADT Plugin</a>.</p> diff --git a/docs/html/tools/revisions/build-tools.jd b/docs/html/tools/revisions/build-tools.jd index 4afdf13..593770a 100644 --- a/docs/html/tools/revisions/build-tools.jd +++ b/docs/html/tools/revisions/build-tools.jd @@ -1,4 +1,5 @@ -page.title=Build Tools +page.title=SDK Build Tools Release Notes + @jd:body <div id="qv-wrapper"> diff --git a/docs/html/tools/revisions/platforms.jd b/docs/html/tools/revisions/platforms.jd index ef8575a..75b3cef 100644 --- a/docs/html/tools/revisions/platforms.jd +++ b/docs/html/tools/revisions/platforms.jd @@ -1,4 +1,5 @@ -page.title=Platforms +page.title=SDK Platforms Release Notes + @jd:body <div id="qv-wrapper"> @@ -20,10 +21,16 @@ Highlights and APIs</a></li> -<p>This document provides information about Android platform releases. In order to compile your -application against a particular platform release, you must download and install the SDK Platform -for that release. If you want to test your application on an emulator, you must also download at -least one system image for that platform release.</p> +<p>This document provides release information about the SDK Platform packages required +for app development. If you want details about the features and APIs added in each Android +version, instead read the highlights in the <a href="{@docRoot}about/index.html">About</a> +section.</p> + +<p>In order to compile your application against a particular version of Android, you must use the +<a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> to download and install the SDK +Platform for that release. If you want to test your application on an emulator, you must also +download at least one System Image for that Android version.</p> + <p>Each platform release includes system images that support a specific processor architecture, such as ARM EABI, Intel x86 or MIPS. Platform releases also include a system image that contains @@ -44,7 +51,7 @@ platform system images under each platform version header, for example:</p> <p class="caution"><strong>Important:</strong> To download the most recent Android system components from the Android SDK Manager, you must first update the SDK Tools to the most recent release and restart the SDK Manager. If you do not, the latest Android system -components will not be available for download.</p> +packages may not be available for download.</p> <h2 id="5.0">Android 5.0</h2> @@ -58,6 +65,8 @@ class="toggle-content-img" alt="" />Revision 1</a> <em>(October 2014)</em> <div class="toggle-content-toggleme"> <p>Initial release for Android 5.0 (API level 21).</p> + <p>Also see the + <a href="{@docRoot}about/versions/android-5.0.html">Android 5.0 APIs overview</a>.</p> <p>Dependencies:</p> <ul> <li>Android SDK Platform-tools r21 or higher is required.</li> @@ -82,7 +91,7 @@ class="toggle-content-img" alt="" />Revision 1</a> <em>(October 2014)</em> <div class="toggle-content open"> <p><a href="#" onclick="return toggleContent(this)"> - <img src="{@docRoot}assets/images/triangle-open.png" + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt="" />Revision 2</a> <em>(October 2014)</em> </p> @@ -135,6 +144,8 @@ class="toggle-content-img" alt="" />Revision 2</a> <em>(December 2013)</em> <div class="toggle-content-toggleme"> <p>Maintenance release. The system version is 4.4.2.</p> + <p>Also see the + <a href="{@docRoot}about/versions/android-4.4.html">Android 4.4 APIs overview</a>.</p> <dl> <dt>Dependencies:</dt> <dd>Android SDK Platform-tools r19 or higher is required.</dd> @@ -153,6 +164,8 @@ class="toggle-content-img" alt="" />Revision 1</a> <em>(October 2013)</em> <div class="toggle-content-toggleme"> <p>Initial release. The system version is 4.4.</p> + <p>Also see the + <a href="{@docRoot}about/versions/android-4.4.html">Android 4.4 APIs overview</a>.</p> <dl> <dt>Dependencies:</dt> <dd>Android SDK Platform-tools r19 or higher is required.</dd> diff --git a/docs/html/tools/revisions/studio.jd b/docs/html/tools/revisions/studio.jd index fe3b99b..422beaa 100644 --- a/docs/html/tools/revisions/studio.jd +++ b/docs/html/tools/revisions/studio.jd @@ -1,4 +1,4 @@ -page.title=Android Studio Revisions +page.title=Android Studio Release Notes @jd:body @@ -26,8 +26,8 @@ everything you need to begin developing Android apps:</p> <li>A version of the Android system image for the emulator</li> </ul> -<p>For an introduction to Android Studio, make sure to read -<a href="{@docRoot}tools/studio/basics.html">Android Studio Basics</a>.</p> +<p>For an introduction to Android Studio, read the +<a href="{@docRoot}tools/studio/index.html">Android Studio</a> guide.</p> <p>Periodic updates are pushed to Android Studio without requiring you to update from here. To manually check for updates, select <strong>Help > Check for updates</strong> (on Mac, select @@ -39,10 +39,21 @@ manually check for updates, select <strong>Help > Check for updates</strong> (on <p>The sections below provide notes about successive releases of Android Studio, as denoted by revision number. </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=""/>Android Studio v1.0</a> <em>(December 2014)</em> + </p> + + <div class="toggle-content-toggleme"> + <p>Initial release of Android Studio.</p> + </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=""/>Android Studio v0.8.14</a> <em>(October 2014)</em> </p> diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd index deafed5..c3a4dea 100644 --- a/docs/html/tools/sdk/eclipse-adt.jd +++ b/docs/html/tools/sdk/eclipse-adt.jd @@ -1,4 +1,4 @@ -page.title=ADT Plugin +page.title=ADT Plugin Release Notes @jd:body @@ -15,29 +15,25 @@ Plugin</a></li> </div> <p>Android Development Tools (ADT) is a plugin for the Eclipse IDE -that is designed to give you a powerful, integrated environment in which -to build Android applications.</p> - -<p>ADT extends the capabilities of Eclipse to let you quickly set up new Android +that extends the capabilities of Eclipse to let you quickly set up new Android projects, create an application UI, add packages based on the Android Framework API, debug your applications using the Android SDK tools, and even export signed (or unsigned) {@code .apk} files in order to distribute your application.</p> -<p>Developing in Eclipse with ADT is highly recommended and is the fastest way -to get started. With the guided project setup it provides, as well as tools -integration, custom XML editors, and debug output pane, ADT gives you an -incredible boost in developing Android applications. </p> +<p class="note"><strong>Note:</strong> +If you have been using Eclipse with ADT, be aware that <a +href="{@docRoot}tools/studio/index.html">Android Studio</a> is now the official IDE +for Android, so you should migrate to Android Studio to receive all the +latest IDE updates. For help moving projects, +see <a href="/sdk/installing/migrate.html">Migrating to Android +Studio</a>.</p> -<p>This document provides step-by-step instructions on how to download the ADT -plugin and install it into your Eclipse development environment. Note that +<p>Note that before you can install or use ADT, you must have compatible versions of both the Eclipse IDE and the Android SDK installed. For details, make sure to read <a href="{@docRoot}sdk/installing/installing-adt.html">Installing the Eclipse Plugin</a>. </p> -<p>If you are already using ADT, this document also provides instructions on -how to update ADT to the latest version or how to uninstall it, if necessary. -</p> <p>For information about the features provided by the ADT plugin, such as code editor features, SDK tool integration, and the graphical layout editor (for drag-and-drop layout diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd index 3e3cb4b..80edb4f 100644 --- a/docs/html/tools/sdk/tools-notes.jd +++ b/docs/html/tools/sdk/tools-notes.jd @@ -1,19 +1,15 @@ -page.title=SDK Tools +page.title=SDK Tools Release Notes excludeFromSuggestions=true @jd:body <p>SDK Tools is a downloadable component for the Android SDK. It includes the -complete set of development and debugging tools for the Android SDK.</p> - -<p>If you are new to the Android SDK, the <a -href="{@docRoot}sdk/index.html">SDK starter package</a> installs the -latest revision of the SDK Tools in the <code><sdk>/tools</code> directory.</p> +complete set of development and debugging tools for the Android SDK. It is included +with <a href="{@docRoot}tools/studio/index.html">Android Studio</a>.</p> <p>If you are already using the SDK and you want to update to the latest version -of the SDK Tools, use the <em>Android SDK Manager</em> to get the -update, rather than downloading a new SDK starter package. For more information -about how to update, see <a -href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</p> +of the SDK Tools, use the <a +href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> to get the +update.</p> <h2 id="notes">Revisions</h2> @@ -29,6 +25,33 @@ href="http://tools.android.com/knownissues">http://tools.android.com/knownissues <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 24.0.0</a> <em>(December 2014)</em> + </p> + + <div class="toggle-content-toggleme"> + + <dl> + <dt>Dependencies:</dt> + + <dd> + <ul> + <li>Android SDK Platform-tools revision 19 or later.</li> + </ul> + </dd> + + <dt>General Notes:</dt> + <dd> + <ul> + <li>Added support for Andriod Studio 1.0 and emulator enhancements.</li> + </ul> + </dd> + </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 23.0.5</a> <em>(October 2014)</em> </p> diff --git a/docs/html/tools/studio/index.jd b/docs/html/tools/studio/index.jd index 1b9dd18..258fedb 100644 --- a/docs/html/tools/studio/index.jd +++ b/docs/html/tools/studio/index.jd @@ -1,4 +1,4 @@ -page.title=Android Studio +page.title=Android Studio Overview @jd:body <div id="qv-wrapper"> @@ -44,7 +44,7 @@ Android Studio offers:</p> <li>And much more</li> </ul> -<p><b><a href="{@docRoot}tools/sdk/index.html">Download Android Studio now</a></b>. </p> +<p><b><a href="{@docRoot}sdk/index.html">Download Android Studio now</a></b>. </p> <p>If you're new to Android Studio or the IntelliJ IDEA interface, this page provides an introduction to some key Android @@ -102,9 +102,8 @@ the <strong>Project</strong drop-down. </p> <h3>New Project and Directory Structure</h3> -<p>When you use the <em>Project</em> view of a new project in Android Studio or -(<a href="{@docRoot}tools/eclipse/migrate-adt.html"> a project migrated from Eclipse</a>), you -should notice that the project structure appears different than you may be used to. Each +<p>When you use the <em>Project</em> view of a new project in Android Studio, you +should notice that the project structure appears different than you may be used to in Eclipse. Each instance of Android Studio contains a project with one or more application modules. Each application module folder contains the complete source sets for that module, including {@code src/main} and {@code src/androidTest} directories, resources, build @@ -115,8 +114,9 @@ specification and the files under {@code src/androidTest} directory for test cas <p> <img src="{@docRoot}images/tools/studio-project-layout.png" alt="" /></p> <p> <class="img-caption"><strong>Figure 3.</strong> Android Studio project structure</p> -<p>For more information, see <a href="http://confluence.jetbrains.com/display/IntelliJIDEA/Project +Organization"class="external-link">IntelliJ project organization</a> and -<a href="{@docRoot}tools/workflow/project/index.html">Managing Projects</a>.</p> +<p>For more information, see +<a href="http://confluence.jetbrains.com/display/IntelliJIDEA/Project+Organization"class="external-link">IntelliJ project organization</a> and +<a href="{@docRoot}tools/projects/index.html">Managing Projects</a>.</p> <h3>Creating new files</h3> diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs index a8c588a..9437c1b 100644 --- a/docs/html/tools/tools_toc.cs +++ b/docs/html/tools/tools_toc.cs @@ -122,7 +122,7 @@ <li class="nav-section"> <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/debugging/index.html"><span class="en">Debugging</span></a></div> <ul> - <li><a href="<?cs var:toroot ?>tools/debugging/debugging-projects.html"><span class="en">From Eclipse with ADT</span></a></li> + <li><a href="<?cs var:toroot ?>tools/debugging/debugging-studio.html"><span class="en">From Android Studio</span></a></li> <li><a href="<?cs var:toroot ?>tools/debugging/debugging-projects-cmdline.html"><span class="en">From Other IDEs</span></a></li> <li><a href="<?cs var:toroot ?>tools/debugging/ddms.html"><span class="en">Using DDMS</span></a></li> <li><a href="<?cs var:toroot ?>tools/debugging/debugging-log.html"><span class="en">Reading and Writing Logs</span></a></li> @@ -145,27 +145,12 @@ </ul> </li> - <li class="nav-section"> - <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/support-library/index.html"><span -class="en">Support Library</span></a></div> - <ul> - <li><a href="<?cs var:toroot ?>tools/support-library/features.html">Features</a></li> - <li><a href="<?cs var:toroot ?>tools/support-library/setup.html">Setup</a></li> - </ul> - </li> <li class="nav-section"> <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/help/index.html"><span class="en">Tools Help</span></a></div> <ul> <li><a href="<?cs var:toroot ?>tools/help/adb.html">adb</a></li> - <li class="nav-section"> - <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/help/adt.html">ADT</a></div> - <ul> - <li><a href="<?cs var:toroot ?>sdk/installing/installing-adt.html"> - <span class="en">Installing the Eclipse Plugin</span></a></li> - </ul> - </li> <li><a href="<?cs var:toroot ?>tools/help/android.html">android</a></li> <li><a href="<?cs var:toroot ?>tools/help/avd-manager.html">AVD Manager</a></li> <li><a href="<?cs var:toroot ?>tools/help/bmgr.html">bmgr</a> @@ -262,10 +247,10 @@ class="en">Support Library</span></a></div> <span class="en">SDK Tools</span> </a></li> <li><a href="<?cs var:toroot ?>tools/revisions/build-tools.html"> - <span class="en">Build Tools</span> + <span class="en">SDK Build Tools</span> </a></li> <li><a href="<?cs var:toroot ?>tools/revisions/platforms.html"> - <span class="en">Platforms</span></a></li> + <span class="en">SDK Platforms</span></a></li> <li><a href="<?cs var:toroot ?>tools/sdk/eclipse-adt.html"> <span class="en">ADT Plugin</span></a></li> </ul> @@ -293,11 +278,13 @@ class="en">Support Library</span></a></div> <li class="nav-section"> <div class="nav-section-header"> - <a href="<?cs var:toroot ?>tools/eclipse/index.html"> + <a href="<?cs var:toroot ?>tools/help/adt.html"> <span class="en">Eclipse with ADT</span></a> </div> <ul> <li><a href="<?cs var:toroot ?>sdk/installing/migrate.html">Migrating to Android Studio</a></li> + <li><a href="<?cs var:toroot ?>sdk/installing/installing-adt.html"> + <span class="en">Installing the Eclipse Plugin</span></a></li> <li><a href="<?cs var:toroot ?>tools/projects/projects-eclipse.html">Managing Projects</a></li> <li><a href="<?cs var:toroot ?>tools/building/building-eclipse.html">Building and Running</a></li> <li><a href="<?cs var:toroot ?>tools/building/building-cmdline-ant.html">Building with Ant</a></li> diff --git a/docs/html/tools/workflow/index.jd b/docs/html/tools/workflow/index.jd index f76df75..6a114c7 100644 --- a/docs/html/tools/workflow/index.jd +++ b/docs/html/tools/workflow/index.jd @@ -1,9 +1,9 @@ -page.title=Introduction +page.title=Developer Workflow @jd:body -<p>To develop apps for Android devices, you use a set of tools that are included in the Android SDK. -Once you've downloaded Android Studio and the Android SDK tools you can access these tools directly. -You can also access most of the SDK tools from the command line. Developing with Android Studio is the +<p>To develop apps for Android, you use a set of tools that are included in Android Studio. +In addition to using the tools from Android Studio, +you can also access most of the SDK tools from the command line. Developing with Android Studio is the preferred method because it can directly invoke the tools that you need while developing applications.</p> <p>However, you may choose to develop with another IDE or a simple text editor and invoke the diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 7a0e413..f883e25 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -834,6 +834,38 @@ include the action bar on devices running Android 2.1 or higher." </li> </ul> </li> + + <li class="nav-section"> + <div class="nav-section-header"> + <a href="<?cs var:toroot ?>training/wearables/watch-faces/index.html" + description="How to create custom watch faces for wearables." + >Creating Custom Watch Faces</a> + </div> + <ul> + <li> + <a href="<?cs var:toroot ?>training/wearables/watch-faces/designing.html">Designing Watch Faces</a> + </li> + <li> + <a href="<?cs var:toroot ?>training/wearables/watch-faces/service.html">Building a Watch Face Service</a> + </li> + <li> + <a href="<?cs var:toroot ?>training/wearables/watch-faces/drawing.html">Drawing Watch Faces</a> + </li> + <li> + <a href="<?cs var:toroot ?>training/wearables/watch-faces/information.html">Showing Information in Watch Faces</a> + </li> + <li> + <a href="<?cs var:toroot ?>training/wearables/watch-faces/configuration.html">Providing Configuration Activities</a> + </li> + <li> + <a href="<?cs var:toroot ?>training/wearables/watch-faces/issues.html">Addressing Common Issues</a> + </li> + <li> + <a href="<?cs var:toroot ?>training/wearables/watch-faces/performance.html">Optimizing Performance and Battery Life</a> + </li> + </ul> + </li> + <li> <a href="<?cs var:toroot ?>training/articles/wear-location-detection.html" description= diff --git a/docs/html/training/wearables/apps/layouts.jd b/docs/html/training/wearables/apps/layouts.jd index a35acb0..4eeb281 100644 --- a/docs/html/training/wearables/apps/layouts.jd +++ b/docs/html/training/wearables/apps/layouts.jd @@ -116,7 +116,13 @@ dependencies { <li><code>CircledImageView</code> - An image view surrounded by a circle.</li> <li><code>ConfirmationActivity</code> - An activity that displays confirmation animations after the user completes an action.</li> + <li><code>CrossFadeDrawable</code> - A drawable that contains two child drawables and provides + methods to directly adjust the blend between the two.</li> + <li><code>DelayedConfirmationView</code> - A view that provides a circular countdown timer, + typically used to automatically confirm an operation after a short delay has elapsed.</li> <li><code>DismissOverlayView</code> - A view for implementing long-press-to-dismiss.</li> + <li><code>DotsPageIndicator</code> - A page indicator for GridViewPager that identifies the + current page in relation to all available pages on the current row.</li> <li><code>GridViewPager</code> - A layout manager that allows the user to both vertically and horizontally through pages of data. You supply an implementation of a GridPagerAdapter to generate the pages that the view shows.</li> @@ -132,6 +138,18 @@ dependencies { </li> </ul> -<p class="note"><a href="{@docRoot}shareables/training/wearable-support-docs.zip">Download the full API -reference documentation</a> for the classes above. The documentation goes over how to use -each UI widget.</p> +<h3 id="UiLibReference">Wear UI library API reference</h3> + +<p>The reference documentation explains how to use each UI widget in detail. Download the +<a href="{@docRoot}shareables/training/wearable-support-docs.zip">API reference documentation</a> +for the classes above.</p> + +<h3 id="UiLibEclipse">Download the Wearable UI library for Eclipse ADT</h3> + +<p>If you are using the ADT plugin for Eclipse, download the +<a href="{@docRoot}shareables/training/wearable-support-lib.zip">Wearable UI library</a> to +include the Wearable UI library as a dependency in your project.</p> + +<p class="note"><strong>Note:</strong> We recommend +<a href="{@docRoot}sdk/index.html">Android Studio</a> for Android Wear app +development.</p> diff --git a/docs/html/training/wearables/apps/packaging.jd b/docs/html/training/wearables/apps/packaging.jd index b538d6e..180f730 100644 --- a/docs/html/training/wearables/apps/packaging.jd +++ b/docs/html/training/wearables/apps/packaging.jd @@ -14,7 +14,7 @@ page.title=Packaging Wearable Apps </div> </div> -<p>When publishing to users, you must package a wearable app inside of a handheld app, +<p>When publishing to users, you must package a wearable app inside of a handheld app, because users cannot browse and install apps directly on the wearable. If packaged properly, when users download the handheld app, the system automatically pushes the wearable app to the paired wearable. @@ -29,6 +29,14 @@ Android Studio directly to the wearable is required.</p> <p>To properly package a wearable app in Android Studio:</p> <ol> + <li>Include all the permissions declared in the manifest file of the wearable app module + in the manifest file of the handheld app module. For example, if you specify the {@link + android.Manifest.permission#VIBRATE} permission for the wearable app, you must also add that + permission to the handheld app.</li> + + <li>Ensure that both the wearable and handheld app modules have the same package name and + version number.</li> + <li>Declare a Gradle dependency in the handheld app's <code>build.gradle</code> file that points to the wearable app module: <pre> @@ -43,39 +51,21 @@ dependencies { to specify your release keystore and sign your app. Android Studio exports the signed handheld app with the wearable app embedded in it automatically into your project's root folder. - <p>Alternatively, you can create a <code>signingConfig</code> rule in the wearable and handheld - modules' <code>build.gradle</code> file to sign them with your release key. Both apps must be - signed to have the automatic pushing of the wearable app work. + <p>Alternatively, you can sign both apps from the command line using the + <a href="{@docRoot}sdk/installing/studio-build.html#gradleWrapper">Gradle wrapper</a>. Both apps + must be signed to have the automatic pushing of the wearable app work.</p> -<pre> -android { - ... - signingConfigs { - release { - keyAlias 'myAlias' - keyPassword 'myPw' - storeFile file('path/to/release.keystore') - storePassword 'myPw' - } - } - buildTypes { - release { - ... - signingConfig signingConfigs.release - } - } - ... -} + <p>Store your key file location and credentials in environment variables and run the Gradle + wrapper as follows:</p> + +<pre class="no-pretty-print"> +./gradlew assembleRelease \ + -Pandroid.injected.signing.store.file=$KEYFILE \ + -Pandroid.injected.signing.store.password=$STORE_PASSWORD \ + -Pandroid.injected.signing.key.alias=$KEY_ALIAS \ + -Pandroid.injected.signing.key.password=$KEY_PASSWORD </pre> - <p>Build the handheld app by clicking the Gradle button on the right vertical toolbar of - Android Studio and running the <b>assembleRelease</b> task. The task is located under - <b>Project name > Handheld module name > assembleRelease</b>. - </p> - -<p class="note"><b>Note:</b>This example embeds the password in your Gradle file, which might be undesirable. See -<a href="{@docRoot}sdk/installing/studio-build.html#configureSigning">Configure signing settings</a> -for information about how to create an environment variable for the passwords instead. -</p> + </li> </ol> <h3>Signing the wearable and handheld app separately</h3> @@ -101,6 +91,12 @@ if you are using another IDE or another method of building. </p> <ol> + <li>Include all the permissions declared in the manifest file of the wearable app + in the manifest file of the mobile app. For example, if you specify the {@link + android.Manifest.permission#VIBRATE} permission for the wearable app, you must also add that + permission to the mobile app.</li> + <li>Ensure that both the wearable and mobile APKs have the same package name and version + number.</li> <li>Copy the signed wearable app to your handheld project's <code>res/raw</code> directory. We'll refer to the APK as <code>wearable_app.apk</code>.</li> <li>Create a <code>res/xml/wearable_app_desc.xml</code> file that contains the version and @@ -115,8 +111,8 @@ if you are using another IDE or another method of building. <p> The <code>package</code>, <code>versionCode</code>, and <code>versionName</code> are the -same values specified in the wearable app's <code>AndroidManifest.xml</code> file. -The <code>rawPathResId</code> is the static variable name of the APK resource. For example, +same values specified in the wearable app's <code>AndroidManifest.xml</code> file. +The <code>rawPathResId</code> is the static variable name of the APK resource. For example, for <code>wearable_app.apk</code>, the static variable name is <code>wearable_app</code>. </p> </li> @@ -124,7 +120,7 @@ for <code>wearable_app.apk</code>, the static variable name is <code>wearable_ap Add a <code>meta-data</code> tag to your handheld app's <code><application></code> tag to reference the <code>wearable_app_desc.xml</code> file. <pre> - <meta-data android:name="com.google.android.wearable.beta.app" + <meta-data android:name="com.google.android.wearable.beta.app" android:resource="@xml/wearable_app_desc"/> </pre> </li> diff --git a/docs/html/training/wearables/watch-faces/configuration.jd b/docs/html/training/wearables/watch-faces/configuration.jd new file mode 100644 index 0000000..edc7eac --- /dev/null +++ b/docs/html/training/wearables/watch-faces/configuration.jd @@ -0,0 +1,144 @@ +page.title=Providing Configuration Activities + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#Intent">Specify an Intent for Configuration Activities</a></li> + <li><a href="#WearableActivity">Create a Wearable Configuration Activity</a></li> + <li><a href="#CompanionActivity">Create a Companion Configuration Activity</a></li> +</ol> +<h2>You should also read</h2> +<ul> + <li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li> +</ul> +</div> +</div> + +<p>When users install a handheld app that contains a <a +href="{@docRoot}training/wearables/apps/index.html">wearable app</a> with watch faces, these +watch faces become available in the Android Wear companion app on the companion device and in +the watch face picker on the wearable. Users can choose the active watch face for their wearable +device by selecting it on the companion app or using the watch face picker on the wearable +device.</p> + +<p>Some watch faces support configuration parameters to let users customize how the watch face +looks and behaves. For example, some watch faces let users pick a custom background color, and +watch faces that tell time for two different time zones can let users select which time zones +they are interested in.</p> + +<p>Watch faces that support configuration parameters can let users customize a watch face using +an activity in the wearable app, an activity on the handheld app, or both. Users can start the +wearable configuration activity on the wearable device, and they can start the companion +configuration activity from the Android Wear companion app.</p> + +<p>The digital watch face from the <em>WatchFace</em> sample in the Android SDK demonstrates how to +implement handheld and wearable configuration activities and how to update a watch face in +response to configuration changes. This sample is located in the +<code>android-sdk/samples/android-21/wearable/WatchFace</code> directory.</p> + + + +<h2 id="Intent">Specify an Intent for Configuration Activities</h2> + +<p>If your watch face includes configuration activities, add the following metadata entries to +the service declaration in the manifest file of the wearable app:</p> + +<pre> +<service + android:name=".DigitalWatchFaceService" ... /> + <!-- companion configuration activity --> + <meta-data + android:name= + "com.google.android.wearable.watchface.companionConfigurationAction" + android:value= + "com.example.android.wearable.watchface.CONFIG_DIGITAL" /> + <!-- wearable configuration activity --> + <meta-data + android:name= + "com.google.android.wearable.watchface.wearableConfigurationAction" + android:value= + "com.example.android.wearable.watchface.CONFIG_DIGITAL" /> + ... +</service> +</pre> + +<p>Provide values for these entries that are preceded by the package name of your app. +Configuration activities register intent filters for this intent, and the system fires this +intent when users want to configure your watch face.</p> + +<p>If your watch face only includes a companion or a wearable configuration activity, you only +need to include the corresponding metadata entry from the example above.</p> + + + +<h2 id="WearableActivity">Create a Wearable Configuration Activity</h2> + +<p>Wearable configuration activities provide a limited set of customization choices for a +watch face, because complex menus are hard to navigate on smaller screens. Your wearable +configuration activity should provide binary choices and just a few selections to customize +the main aspects of your watch face.</p> + +<p>To create a wearable configuration activity, add a new activity to your wearable app module +and declare the following intent filter in the manifest file of the wearable app:</p> + +<pre> +<activity + android:name=".DigitalWatchFaceWearableConfigActivity" + android:label="@string/digital_config_name"> + <intent-filter> + <action android:name= + "com.example.android.wearable.watchface.CONFIG_DIGITAL" /> + <category android:name= + "com.google.android.wearable.watchface.category.WEARABLE_CONFIGURATION" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> +</activity> +</pre> + +<p>The name of the action in this intent filter must match the intent name you defined in +<a href="#Intent">Specify an Intent for Configuration Activities</a>.</p> + +<p>In your configuration activity, build a simple UI that provides selections for users to +customize your watch face. When users make a selection, use the <a +href="{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer API</a> to +communicate the configuration change to the watch face activity.</p> + +<p>For more details, see the <code>DigitalWatchFaceWearableConfigActivity</code> and +<code>DigitalWatchFaceUtil</code> classes in the <em>WatchFace</em> sample.</p> + + + +<h2 id="CompanionActivity">Create a Companion Configuration Activity</h2> + +<p>Companion configuration activities give users access to the full set of configuration choices +for a watch face, because it is easier to interact with complex menus on the larger screen of +a handheld device. For example, a configuration activity on a handheld device enables you to +present users with elaborate color pickers to select the background color of a watch face.</p> + +<p>To create a companion configuration activity, add a new activity to your handheld app module and +declare the same intent filter for this activity as the one in <a href="#WearableActivity">Create +a Wearable Configuration Activity</a>.</p> + +<p>In your configuration activity, build a UI that provides options to customize all the +configurable elements of your watch face. When users make a selection, use the <a +href="{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer API</a> to +communicate the configuration change to the watch face activity.</p> + +<p>For more details, see the <code>DigitalWatchFaceCompanionConfigActivity</code> class in the +<em>WatchFace</em> sample.</p> + + + +<h2 id="Listener">Create a Listener Service in the Wearable App</h2> + +<p>To receive updated configuration parameters from the configuration activities, create a +service that implements the <code>WearableListenerService</code> interface from the <a +href="{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer API</a> in your +wearable app. Your watch face implementation can redraw the watch face when the configuration +parameters change.</p> + +<p>For more details, see the <code>DigitalWatchFaceConfigListenerService</code> and +<code>DigitalWatchFaceService</code> classes in the <em>WatchFace</em> sample.</p> diff --git a/docs/html/training/wearables/watch-faces/designing.jd b/docs/html/training/wearables/watch-faces/designing.jd new file mode 100644 index 0000000..b7fcfd4 --- /dev/null +++ b/docs/html/training/wearables/watch-faces/designing.jd @@ -0,0 +1,108 @@ +page.title=Designing Watch Faces + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#DesignGuidelines">Conform to the Design Guidelines</a></li> + <li><a href="#ImplementationStrategy">Create an Implementation Strategy</a></li> +</ol> +<h2>You should also read</h2> +<ul> + <li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li> +</ul> +</div> +</div> + +<p>Similar to the process of designing a traditional watch face, creating one for +Android Wear is an exercise in visualizing time clearly. Android Wear devices +provide advanced capabilities for watch faces that you can leverage in your designs, such as +vibrant colors, dynamic backgrounds, animations, and data integration. However, there are +also many design considerations that you must take into account.</p> + +<p>This lesson provides a summary of the design considerations for watch faces and general +guidelines to get started implementing a design. For more information, read the <a +href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a> design guide.</p> + + + +<h2 id="DesignGuidelines">Conform to the Design Guidelines</h2> + +<p>As you plan the look of your watch face and what kind of information it should present +to users, consider these design guidelines:</p> + +<div style="float:right;margin-top:-5px;margin-left:20px"> + <img src="{@docRoot}training/wearables/watch-faces/images/Render_Next.png" + width="200" height="195" alt="" style="margin-right:5px"/><br> + <img src="{@docRoot}training/wearables/watch-faces/images/Render_Interactive.png" + width="200" height="195" alt="" style="margin-right:5px"/> + <p class="img-caption" style="margin-top:0px;margin-left:10px"> + <strong>Figure 1.</strong> Example watch faces.</p> +</div> + +<dl> +<dt><em>Plan for square and round devices</em></dt> +<dd>Your design should work for both square and round Android Wear devices, including devices with +<a href="{@docRoot}training/wearables/ui/layouts.html#same-layout">insets on the bottom of the +screen</a>.</dd> + +<dt><em>Support all display modes</em></dt> +<dd>Your watch face should support ambient mode with limited color and interactive mode with +full color and animations.</dd> + +<dt><em>Optimize for special screen technologies</em></dt> +<dd>In ambient mode, your watch face should keep most pixels black. Depending on the screen +technology, you may need to avoid large blocks of white pixels, use only black and white, and +disable anti-aliasing.</dd> + +<dt><em>Accomodate system UI elements</em></dt> +<dd>Your design should ensure that system indicators remain visible and that users can still +read the time when notification cards appear on the screen.</dd> + +<dt><em>Integrate data</em></dt> +<dd>Your watch face can leverage sensors and cellular connectivity on the companion mobile +device to show user data relevant to the context, such as the weather for the day or their next +calendar event.</dd> + +<dt><em>Provide configuration options</em></dt> +<dd>You can let users configure some aspects of your design (like colors and sizes) on the +wearable or on the Android Wear companion app.</dd> +</dl> + +<p>For more information about designing watch faces for Android Wear, see the <a +href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a> design guide.</p> + + + +<h2 id="ImplementationStrategy">Create an Implementation Strategy</h2> + +<p>After you finalize the design for your watch face, you need to determine how to obtain any +necessary data and draw the watch face on the wearable device. Most implementations +consist of the following components:</p> + +<ul> +<li>One or more background images</li> +<li>Application code to retrieve the required data</li> +<li>Application code to draw text and shapes over the background images</li> +</ul> + +<p>You typically use one background image in interactive mode and a different background image +in ambient mode. The background in ambient mode is often completely black. Background images for +Android Wear devices with a screen density of hdpi should be 320 by 320 pixels in size to fit +both square and round devices. The corners of the background image are not visible on round +devices. In your code, you can detect the size of the device screen and scale down the background +image if the device has a lower resolution than your image. To improve performance, you should +scale the background image only once and store the resulting bitmap.</p> + +<p>You should run the application code to retrieve contextual data only as often as required +and store the results to reuse the data every time you draw the watch face. For example, you +don't need to fetch weather updates every minute.</p> + +<p>To increase battery life, the application code that draws your watch face in ambient mode +should be relatively simple. You usually draw outlines of shapes using a limited set of colors +in this mode. In interactive mode, you can use full color, complex shapes, gradients, and +animations to draw your watch face.</p> + +<p>The remaining lessons in this class show you how to implement watch faces in detail.</p> diff --git a/docs/html/training/wearables/watch-faces/drawing.jd b/docs/html/training/wearables/watch-faces/drawing.jd new file mode 100644 index 0000000..9afdd80 --- /dev/null +++ b/docs/html/training/wearables/watch-faces/drawing.jd @@ -0,0 +1,509 @@ +page.title=Drawing Watch Faces + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#Initialize">Initialize Your Watch Face</a></li> + <li><a href="#SystemUI">Configure the System UI</a></li> + <li><a href="#Screen">Obtain Information About the Device Screen</a></li> + <li><a href="#Modes">Respond to Changes Between Modes</a></li> + <li><a href="#Drawing">Draw Your Watch Face</a></li> +</ol> +<h2>You should also read</h2> +<ul> + <li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li> +</ul> +</div> +</div> + +<p>After you have configured your project and added a class that implements the watch +face service, you can start writing code to initialize and draw your custom watch face.</p> + +<p>This lesson explains how the system invokes the methods in the +watch face service using examples from the <em>WatchFace</em> sample +included in the Android SDK. This sample is located in the +<code>android-sdk/samples/android-21/wearable/WatchFace</code> directory. Many aspects of the +service implementations described here (such as initialization and detecting device features) +apply to any watch face, so you can reuse some of the code in your own watch faces.</p> + + +<img src="{@docRoot}training/wearables/watch-faces/images/preview_analog.png" + width="180" height="180" alt="" style="margin-top:12px"/> +<img src="{@docRoot}training/wearables/watch-faces/images/preview_digital.png" + width="180" height="180" alt="" style="margin-left:25px;margin-top:12px"/> +<p class="img-caption"> +<strong>Figure 1.</strong> The analog and digital watch faces in +the <em>WatchFace</em> sample.</p> + + +<h2 id="Initialize">Initialize Your Watch Face</h2> + +<p>When the system loads your service, you should allocate and initialize most of the resources +that your watch face needs, including loading bitmap resources, creating timer objects to run +custom animations, configuring paint styles, and performing other computations. You can usually +perform these operations only once and reuse their results. This practice improves the performance +of your watch face and makes it easier to maintain your code.</p> + +<p>To initialize your watch face, follow these steps:</p> + +<ol> +<li>Declare variables for a custom timer, graphic objects, and other elements.</li> +<li>Initialize the watch face elements in the <code>Engine.onCreate()</code> method.</li> +<li>Initialize the custom timer in the <code>Engine.onVisibilityChanged()</code> method.</li> +</ol> + +<p>The following sections describe these steps in detail.</p> + +<h3 id="Variables">Declare variables</h3> + +<p>The resources that you intialize when the system loads your service need to be accessible +at different points throughout your implementation, so you can reuse them. You achieve this +by declaring member variables for these resources in your <code>WatchFaceService.Engine</code> +implementation.</p> + +<p>Declare variables for the following elements:</p> + +<dl> +<dt><em>Graphic objects</em></dt> +<dd>Most watch faces contain at least one bitmap image used as the background of the watch face, +as described in +<a href="{@docRoot}training/wearables/watch-faces/designing.html#ImplementationStrategy">Create an +Implementation Strategy</a>. You can use additional bitmap images that represent clock hands or +other design elements of your watch face.</dd> +<dt><em>Periodic timer</em></dt> +<dd>The system notifies the watch face once a minute when the time changes, but some watch faces +run animations at custom time intervals. In these cases, you need to provide a custom timer that +ticks with the frequency required to update your watch face.</dd> +<dt><em>Time zone change receiver</em></dt> +<dd>Users can adjust their time zone when they travel, and the system broadcasts this event. +Your service implementation must register a broadcast receiver that is notified when the time +zone changes and update the time accordingly.</dd> +</dl> + +<p>The <code>AnalogWatchFaceService.Engine</code> class in the <em>WatchFace</em> sample defines +these variables as shown in the snippet below. The custom timer is implemented as a +{@link android.os.Handler} instance that sends and processes delayed messages using the thread's +message queue. For this particular watch face, the custom timer ticks once every second. When the +timer ticks, the handler calls the <code>invalidate()</code> method and the system then calls +the <code>onDraw()</code> method to redraw the watch face.</p> + +<pre> +private class Engine extends CanvasWatchFaceService.Engine { + static final int MSG_UPDATE_TIME = 0; + + /* a time object */ + Time mTime; + + /* device features */ + boolean mLowBitAmbient; + + /* graphic objects */ + Bitmap mBackgroundBitmap; + Bitmap mBackgroundScaledBitmap; + Paint mHourPaint; + Paint mMinutePaint; + ... + + /* handler to update the time once a second in interactive mode */ + final Handler mUpdateTimeHandler = new Handler() { + @Override + public void handleMessage(Message message) { + switch (message.what) { + case MSG_UPDATE_TIME: + invalidate(); + if (shouldTimerBeRunning()) { + long timeMs = System.currentTimeMillis(); + long delayMs = INTERACTIVE_UPDATE_RATE_MS + - (timeMs % INTERACTIVE_UPDATE_RATE_MS); + mUpdateTimeHandler + .sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs); + } + break; + } + } + }; + + /* receiver to update the time zone */ + final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mTime.clear(intent.getStringExtra("time-zone")); + mTime.setToNow(); + } + }; + + /* service methods (see other sections) */ + ... +} +</pre> + +<h3 id="InitializeElements">Initialize watch face elements</h3> + +<p>After you have declared member variables for bitmap resources, paint styles, and other +elements that you reuse every time your redraw your watch face, initialize them when the system +loads your service. Initializing these elements only once and reusing them improves performance +and battery life.</p> + +<p>In the <code>Engine.onCreate()</code> method, initialize the following elements:</p> + +<ul> +<li>Load the background image.</li> +<li>Create styles and colors to draw graphic objects.</li> +<li>Allocate an object to hold the time.</li> +<li>Configure the system UI.</li> +</ul> + +<p>The <code>Engine.onCreate()</code> method in the <code>AnalogWatchFaceService</code> class +initializes these elements as follows:</p> + +<pre> +@Override +public void onCreate(SurfaceHolder holder) { + super.onCreate(holder); + + /* configure the system UI (see next section) */ + ... + + /* load the background image */ + Resources resources = AnalogWatchFaceService.this.getResources(); + Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg); + mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap(); + + /* create graphic styles */ + mHourPaint = new Paint(); + mHourPaint.setARGB(255, 200, 200, 200); + mHourPaint.setStrokeWidth(5.0f); + mHourPaint.setAntiAlias(true); + mHourPaint.setStrokeCap(Paint.Cap.ROUND); + ... + + /* allocate an object to hold the time */ + mTime = new Time(); +} +</pre> + +<p>The background bitmap is loaded only once when the system initializes the watch face. The +graphic styles are instances of the {@link android.graphics.Paint} class. You later use these +styles to draw the elements of your watch face inside the <code>Engine.onDraw()</code> method, +as described in <a href="#Drawing">Drawing Your Watch Face</a>.</p> + +<h3 id="Timer">Initialize the custom timer</h3> + +<p>As a watch face developer, you can decide how often you want to update your watch face by +providing a custom timer that ticks with the required frequency while the device is in +interactive mode. This enables you to create custom animations and other visual effects. In +ambient mode, you should disable the timer to let the CPU sleep and update the watch face +only when the time changes. For more information, see +<a href="{@docRoot}training/wearables/watch-faces/performance.html">Optimizing Performance and +Battery Life</a>.</p> + +<p>An example timer definition from the <code>AnalogWatchFaceService</code> class that ticks once +every second is shown in <a href="#Variables">Declare variables</a>. In the +<code>Engine.onVisibilityChanged()</code> method, start the custom timer if these two +conditions apply:</p> + +<ul> +<li>The watch face is visible.</li> +<li>The device is in interactive mode.</li> +</ul> + +<p>The timer should not run under any other conditions, since this watch face does not +draw the second hand in ambient mode to conserve power. The <code>AnalogWatchFaceService</code> +class schedules the next timer tick if required as follows:</p> + +<pre> +private void updateTimer() { + mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME); + if (shouldTimerBeRunning()) { + mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME); + } +} + +private boolean shouldTimerBeRunning() { + return isVisible() && !isInAmbientMode(); +} +</pre> + +<p>This custom timer ticks once every second, as described in <a href="#Variables">Declare +variables</a>.</p> + +<p>In the <code>Engine.onVisibilityChanged()</code> method, start the timer if required and +and register the receiver for time zone changes as follows:</p> + +<pre> +@Override +public void onVisibilityChanged(boolean visible) { + super.onVisibilityChanged(visible); + + if (visible) { + registerReceiver(); + + // Update time zone in case it changed while we weren't visible. + mTime.clear(TimeZone.getDefault().getID()); + mTime.setToNow(); + } else { + unregisterReceiver(); + } + + // Whether the timer should be running depends on whether we're visible and + // whether we're in ambient mode), so we may need to start or stop the timer + updateTimer(); +} +</pre> + +<p>When the watch face is visible, the <code>onVisibilityChanged()</code> method registers +the receiver for time zone changes and starts the custom timer if the device is in interactive +mode. When the watch face is not visible, this method stops the custom timer and unregisters +the receiver for time zone changes. The <code>registerReceiver()</code> and +<code>unregisterReceiver()</code> methods are implemented as follows:</p> + +<pre> +private void registerReceiver() { + if (mRegisteredTimeZoneReceiver) { + return; + } + mRegisteredTimeZoneReceiver = true; + IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED); + AnalogWatchFaceService.this.registerReceiver(mTimeZoneReceiver, filter); +} + +private void unregisterReceiver() { + if (!mRegisteredTimeZoneReceiver) { + return; + } + mRegisteredTimeZoneReceiver = false; + AnalogWatchFaceService.this.unregisterReceiver(mTimeZoneReceiver); +} +</pre> + + + +<h3 id="TimeTick">Invalidate the canvas when the time changes</h3> + +<p>The system calls the <code>Engine.onTimeTick()</code> method every minute. In ambient mode, +it is usually sufficient to update your watch face once per minute. To update your watch face +more often while in interactive mode, you provide a custom timer as described in +<a href="#Timer">Initialize the custom timer</a>.</p> + +<p>Most watch face implementations just invalidate the canvas to redraw the watch face when +the time changes:</p> + +<pre> +@Override +public void onTimeTick() { + super.onTimeTick(); + + invalidate(); +} +</pre> + + + +<h2 id="SystemUI">Configure the System UI</h2> + +<p>Watch faces should not interfere with system UI elements, as described in +<a href="{@docRoot}design/wear/watchfaces.html#SystemUI">Accommodate System UI Elements</a>. +If your watch face has a light background or shows information near the bottom of the screen, +you may have to configure the size of notification cards or enable background protection.</p> + +<p>Android Wear enables you to configure the following aspects of the system UI when your watch +face is active:</p> + +<ul> +<li>Specify how far the first notification card peeks into the screen.</li> +<li>Specify whether the system draws the time over your watch face.</li> +<li>Show or hide cards when in ambient mode.</li> +<li>Protect the system indicators with a solid background around them.</li> +<li>Specify the positioning of the system indicators.</li> +</ul> + +<p>To configure these aspects of the system UI, create a <code>WatchFaceStyle</code> instance +and pass it to the <code>Engine.setWatchFaceStyle()</code> method.</p> + +<p>The <code>AnalogWatchFaceService</code> class configures the system UI as follows:</p> + +<pre> +@Override +public void onCreate(SurfaceHolder holder) { + super.onCreate(holder); + + /* configure the system UI */ + setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this) + .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT) + .setBackgroundVisibility(WatchFaceStyle + .BACKGROUND_VISIBILITY_INTERRUPTIVE) + .setShowSystemUiTime(false) + .build()); + ... +} +</pre> + +<p>The code snippet above configures peeking cards to be a single line tall, the background +of a peeking card to show only briefly and only for interruptive notifications, and the system +time not to be shown (since this watch face draws its own time representation).</p> + +<p>You can configure the style of the system UI at any point in your watch face implementation. +For example, if the user selects a white background, you can add background protection for the +system indicators.</p> + +<p>For more details about configuring the system UI, see the +<a href="{@docRoot}shareables/training/wearable-support-docs.zip">API reference</a> for the +<code>WatchFaceStyle</code> class.</p> + + + +<h2 id="Screen">Obtain Information About the Device Screen</h2> + +<p>The system calls the <code>Engine.onPropertiesChanged()</code> method when it determines +the properties of the device screen, such as whether the device uses low-bit ambient mode and +whether the screen requires burn-in protection.</p> + +<p>The following code snippet shows how to obtain these properties:</p> + +<pre> +@Override +public void onPropertiesChanged(Bundle properties) { + super.onPropertiesChanged(properties); + mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false); + mBurnInProtection = properties.getBoolean(PROPERTY_BURN_IN_PROTECTION, + false); +} +</pre> + +<p>You should take these device properties into account when drawing your watch face:</p> + +<ul> +<li>For devices that use low-bit ambient mode, the screen supports fewer bits for each color +in ambient mode, so you should disable anti-aliasing.</li> +<li>For devices that require burn-in protection, avoid using large blocks of white pixels in +ambient mode and do not place content within 10 pixels of the edge of the screen, since the +system shifts the content periodically to avoid pixel burn-in.</li> +</ul> + +<p>For more information about low-bit ambient mode and burn-in protection, see +<a href="{@docRoot}design/wear/watchfaces.html#SpecialScreens">Optimize for Special +Screens</a>.</p> + + +<h2 id="Modes">Respond to Changes Between Modes</h2> + +<p>When the device switches between ambient and interactive modes, the system calls the +<code>Engine.onAmbientModeChanged()</code> method. Your service implementation should make +any necessary adjustments to switch between modes and then call the <code>invalidate()</code> +method for the system to redraw the watch face.</p> + +<p>The following snippet shows how this method is implemented in the +<code>AnalogWatchFaceService</code> class inside the <em>WatchFace</em> sample:</p> + +<pre> +@Override +public void onAmbientModeChanged(boolean inAmbientMode) { + + boolean wasInAmbientMode = isInAmbientMode(); + super.onAmbientModeChanged(inAmbientMode); + + if (inAmbientMode != wasInAmbientMode) { + if (mLowBitAmbient) { + boolean antiAlias = !inAmbientMode; + mHourPaint.setAntiAlias(antiAlias); + mMinutePaint.setAntiAlias(antiAlias); + mSecondPaint.setAntiAlias(antiAlias); + mTickPaint.setAntiAlias(antiAlias); + } + invalidate(); + updateTimer(); + } +} +</pre> + +<p>This example makes adjustments to some graphic styles and invalidates the canvas so the +system can redraw the watch face.</p> + + + +<h2 id="Drawing">Draw Your Watch Face</h2> + +<p>To draw a custom watch face, the system calls the <code>Engine.onDraw()</code> method with a +{@link android.graphics.Canvas} instance and the bounds in which you should draw your watch face. +The bounds account for any inset areas, such as the "chin" on the bottom of some round devices. +You can use this canvas to draw your watch face directly as follows:</p> + +<ol> +<li>If this is the first invocation of the <code>onDraw()</code> method, scale your background +to fit.</li> +<li>Check whether the device is in ambient mode or interactive mode.</li> +<li>Perform any required graphic computations.</li> +<li>Draw your background bitmap on the canvas.</li> +<li>Use the methods in the {@link android.graphics.Canvas} class to draw your watch face.</li> +</ol> + +<p>The <code>AnalogWatchFaceService</code> class in the <em>WatchFace</em> sample follows these +steps to implement the <code>onDraw()</code> method as follows:</p> + +<pre> +@Override +public void onDraw(Canvas canvas, Rect bounds) { + // Update the time + mTime.setToNow(); + + int width = bounds.width(); + int height = bounds.height(); + + // Draw the background, scaled to fit. + if (mBackgroundScaledBitmap == null + || mBackgroundScaledBitmap.getWidth() != width + || mBackgroundScaledBitmap.getHeight() != height) { + mBackgroundScaledBitmap = Bitmap.createScaledBitmap(mBackgroundBitmap, + width, height, true /* filter */); + } + canvas.drawBitmap(mBackgroundScaledBitmap, 0, 0, null); + + // Find the center. Ignore the window insets so that, on round watches + // with a "chin", the watch face is centered on the entire screen, not + // just the usable portion. + float centerX = width / 2f; + float centerY = height / 2f; + + // Compute rotations and lengths for the clock hands. + float secRot = mTime.second / 30f * (float) Math.PI; + int minutes = mTime.minute; + float minRot = minutes / 30f * (float) Math.PI; + float hrRot = ((mTime.hour + (minutes / 60f)) / 6f ) * (float) Math.PI; + + float secLength = centerX - 20; + float minLength = centerX - 40; + float hrLength = centerX - 80; + + // Only draw the second hand in interactive mode. + if (!mAmbient) { + float secX = (float) Math.sin(secRot) * secLength; + float secY = (float) -Math.cos(secRot) * secLength; + canvas.drawLine(centerX, centerY, centerX + secX, centerY + + secY, mSecondPaint); + } + + // Draw the minute and hour hands. + float minX = (float) Math.sin(minRot) * minLength; + float minY = (float) -Math.cos(minRot) * minLength; + canvas.drawLine(centerX, centerY, centerX + minX, centerY + minY, + mMinutePaint); + float hrX = (float) Math.sin(hrRot) * hrLength; + float hrY = (float) -Math.cos(hrRot) * hrLength; + canvas.drawLine(centerX, centerY, centerX + hrX, centerY + hrY, + mHourPaint); +} +</pre> + +<p>This method computes the required positions for the clock hands based on the current time +and draws them on top of the background bitmap using the graphic styles initialized in the +<code>onCreate()</code> method. The second hand is only drawn in interactive mode, not in +ambient mode.</p> + +<p>For more information about drawing on a Canvas instance, see <a +href="{@docRoot}guide/topics/graphics/2d-graphics.html">Canvas and Drawables</a>.</p> + +<p>The <em>WatchFace</em> sample in the Android SDK includes additional watch faces that you +can refer to as examples of how to implement the <code>onDraw()</code> method.</p> diff --git a/docs/html/training/wearables/watch-faces/images/AnalogNoCard.png b/docs/html/training/wearables/watch-faces/images/AnalogNoCard.png Binary files differnew file mode 100644 index 0000000..a6b5d4f --- /dev/null +++ b/docs/html/training/wearables/watch-faces/images/AnalogNoCard.png diff --git a/docs/html/training/wearables/watch-faces/images/AnalogWithCard.png b/docs/html/training/wearables/watch-faces/images/AnalogWithCard.png Binary files differnew file mode 100644 index 0000000..242d3fe --- /dev/null +++ b/docs/html/training/wearables/watch-faces/images/AnalogWithCard.png diff --git a/docs/html/training/wearables/watch-faces/images/BitmapFilterDisabled.png b/docs/html/training/wearables/watch-faces/images/BitmapFilterDisabled.png Binary files differnew file mode 100644 index 0000000..3291137 --- /dev/null +++ b/docs/html/training/wearables/watch-faces/images/BitmapFilterDisabled.png diff --git a/docs/html/training/wearables/watch-faces/images/BitmapFilterEnabled.png b/docs/html/training/wearables/watch-faces/images/BitmapFilterEnabled.png Binary files differnew file mode 100644 index 0000000..6492318 --- /dev/null +++ b/docs/html/training/wearables/watch-faces/images/BitmapFilterEnabled.png diff --git a/docs/html/training/wearables/watch-faces/images/ClockHandCropped.png b/docs/html/training/wearables/watch-faces/images/ClockHandCropped.png Binary files differnew file mode 100644 index 0000000..69c746b --- /dev/null +++ b/docs/html/training/wearables/watch-faces/images/ClockHandCropped.png diff --git a/docs/html/training/wearables/watch-faces/images/ClockHandFull.png b/docs/html/training/wearables/watch-faces/images/ClockHandFull.png Binary files differnew file mode 100644 index 0000000..2d08920 --- /dev/null +++ b/docs/html/training/wearables/watch-faces/images/ClockHandFull.png diff --git a/docs/html/training/wearables/watch-faces/images/Indicators_Cropped.png b/docs/html/training/wearables/watch-faces/images/Indicators_Cropped.png Binary files differnew file mode 100644 index 0000000..9449c02 --- /dev/null +++ b/docs/html/training/wearables/watch-faces/images/Indicators_Cropped.png diff --git a/docs/html/training/wearables/watch-faces/images/Render_Episode.png b/docs/html/training/wearables/watch-faces/images/Render_Episode.png Binary files differnew file mode 100644 index 0000000..2d545bb --- /dev/null +++ b/docs/html/training/wearables/watch-faces/images/Render_Episode.png diff --git a/docs/html/training/wearables/watch-faces/images/Render_Interactive.png b/docs/html/training/wearables/watch-faces/images/Render_Interactive.png Binary files differnew file mode 100644 index 0000000..a1e260b --- /dev/null +++ b/docs/html/training/wearables/watch-faces/images/Render_Interactive.png diff --git a/docs/html/training/wearables/watch-faces/images/Render_Next.png b/docs/html/training/wearables/watch-faces/images/Render_Next.png Binary files differnew file mode 100644 index 0000000..e080943 --- /dev/null +++ b/docs/html/training/wearables/watch-faces/images/Render_Next.png diff --git a/docs/html/training/wearables/watch-faces/images/Render_Saturn.png b/docs/html/training/wearables/watch-faces/images/Render_Saturn.png Binary files differnew file mode 100644 index 0000000..500018c --- /dev/null +++ b/docs/html/training/wearables/watch-faces/images/Render_Saturn.png diff --git a/docs/html/training/wearables/watch-faces/images/preview_analog.png b/docs/html/training/wearables/watch-faces/images/preview_analog.png Binary files differnew file mode 100644 index 0000000..fa71546 --- /dev/null +++ b/docs/html/training/wearables/watch-faces/images/preview_analog.png diff --git a/docs/html/training/wearables/watch-faces/images/preview_calendar.png b/docs/html/training/wearables/watch-faces/images/preview_calendar.png Binary files differnew file mode 100644 index 0000000..928aa1f --- /dev/null +++ b/docs/html/training/wearables/watch-faces/images/preview_calendar.png diff --git a/docs/html/training/wearables/watch-faces/images/preview_digital.png b/docs/html/training/wearables/watch-faces/images/preview_digital.png Binary files differnew file mode 100644 index 0000000..4853a64 --- /dev/null +++ b/docs/html/training/wearables/watch-faces/images/preview_digital.png diff --git a/docs/html/training/wearables/watch-faces/index.jd b/docs/html/training/wearables/watch-faces/index.jd new file mode 100644 index 0000000..c510fb2 --- /dev/null +++ b/docs/html/training/wearables/watch-faces/index.jd @@ -0,0 +1,62 @@ +page.title=Creating Custom Watch Faces + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + <h2>Dependencies and Prerequisites</h2> + <ul> + <li>Android Studio 1.0.0 or later and Gradle 1.0 or later</li> + <li>Android 4.3 (API level 18) or higher on the handheld device</li> + <li>Android 5.0 (API level 21) or higher on the wearable device</li> + </ul> +</div> +</div> + +<p>Watch faces in Android Wear leverage a dynamic digital canvas to tell time using colors, +animations, and relevant contextual information. The <a +href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app">Android +Wear companion app</a> provides watch faces with different styles and shapes. When +users select one of the available watch faces on the wearable or on the companion app, the +wearable device previews the watch face and lets the user set configuration options.</p> + +<p>Android Wear enables you to create custom watch faces for Wear devices. When users install a +handheld app that contains a <a href="{@docRoot}training/wearables/apps/index.html">wearable +app</a> with watch faces, they become available in the Android Wear companion app +on the handheld device and in the watch face picker on the wearable device.</p> + +<p>This class teaches you to implement custom watch faces and to package them inside a wearable +app. This class also covers design considerations and implementation tips to ensure that your +designs integrate with system UI elements and are power-efficient.</p> + +<p class="note"><strong>Note:</strong> We recommend using <a +href="{@docRoot}sdk/index.html">Android Studio</a> for Android Wear development as +it provides project setup, library inclusion, and packaging conveniences that aren't available +in the Eclipse Android Developer Tools. This training assumes you are using Android Studio.</p> + + +<h2>Lessons</h2> + +<dl> +<dt><a href="{@docRoot}training/wearables/watch-faces/designing.html"> +Designing Watch Faces</a></dt> +<dd>Learn how to design a watch face that works on any Android Wear device.</dd> +<dt><a href="{@docRoot}training/wearables/watch-faces/service.html"> +Building a Watch Face Service</a></dt> +<dd>Learn how to respond to important events during the lifecycle of your watch face.</dd> +<dt><a href="{@docRoot}training/wearables/watch-faces/drawing.html"> +Drawing Watch Faces</a></dt> +<dd>Learn how to draw your watch face on a Wear device screen.</dd> +<dt><a href="{@docRoot}training/wearables/watch-faces/information.html"> +Showing Information in Watch Faces</a></dt> +<dd>Learn how to incorporate contextual information into your watch face.</dd> +<dt><a href="{@docRoot}training/wearables/watch-faces/configuration.html"> +Providing Configuration Activities</a></dt> +<dd>Learn how to create watch faces with configurable parameters.</dd> +<dt><a href="{@docRoot}training/wearables/watch-faces/issues.html"> +Addressing Common Issues</a></dt> +<dd>Learn how to fix common problems when developing a watch face.</dd> +<dt><a href="{@docRoot}training/wearables/watch-faces/performance.html"> +Optimizing Performance and Battery Life</a></dt> +<dd>Learn how to improve the frame rate of your animations and how to save power.</dd> +</dl> diff --git a/docs/html/training/wearables/watch-faces/information.jd b/docs/html/training/wearables/watch-faces/information.jd new file mode 100644 index 0000000..41319a1 --- /dev/null +++ b/docs/html/training/wearables/watch-faces/information.jd @@ -0,0 +1,213 @@ +page.title=Showing Information in Watch Faces + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#Experience">Create a Compelling Experience</a></li> + <li><a href="#AddData">Add Data to Your Watch Face</a></li> +</ol> +<h2>You should also read</h2> +<ul> + <li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li> +</ul> +</div> +</div> + +<p>In addition to telling time, Android Wear devices provide users with contextually relevant +information in the form of cards, notifications, and other wearable apps. Creating a custom +watch face not only gives you the opportunity to tell time in visually compelling ways, but +also to show users relevant information whenever they glance at their device.</p> + +<p>Like any other wearable app, your watch face can communicate with apps running on the handheld +device using the <a href="{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer +API</a>. In some cases, you need to create an activity in the handheld app module of your project +that retrieves data from the Internet or from the user's profile and then shares it with your +watch face.</p> + +<img src="{@docRoot}training/wearables/watch-faces/images/Render_Saturn.png" + width="200" height="196" alt="" style="margin-top:12px;margin-left:-20px"/> +<img src="{@docRoot}training/wearables/watch-faces/images/Render_Episode.png" + width="200" height="196" alt="" style="margin-top:12px;margin-left:-25px"/> +<p class="img-caption"> +<strong>Figure 1.</strong> Examples of watch faces with integrated data.</p> + + +<h2 id="Experience">Create a Compelling Experience</h2> + +<p>Before you design and implement a contextually-aware watch face, answer the following +questions:</p> + +<ul> +<li>What kind of data do you want to incorporate?</li> +<li>Where can you obtain this data?</li> +<li>How often does the data change significantly?</li> +<li>How can you present the data such that users understand it at a glance?</li> +</ul> + +<p>Android Wear devices are usually paired with a companion device that has a GPS sensor and +cellular connectivity, so you have endless possibilities to integrate different kinds of data +in your watch face, such as location, calendar events, social media trends, picture feeds, stock +market quotes, news events, sports scores, and so on. However, not all kinds of data are +appropriate for a watch face, so you should consider what kinds of data are most relevant to +your users throughout the day. Your watch face should also gracefully handle the case where the +wearable is not paired with a companion device or when an Internet connection is not available.</p> + +<p>The active watch face on an Android Wear device is an app that runs continuously, so you +must retrieve data in a battery-efficient manner. For example, you can obtain the current +weather every ten minutes and store the results locally, instead of requesting an update every +minute. You can also refresh contextual data when the device switches from ambient to interactive +mode, since the user is more likely to glance at the watch when this transition occurs.</p> + +<p>You should summarize contextual information on your watch face, since there is limited +space available on the screen and users just glance at their watch for a second or two at a +time. Sometimes the best way to convey contextual information is to react to it using graphics +and colors. For example, a watch face could change its background image depending on the current +weather.</p> + + + +<h2 id="AddData">Add Data to Your Watch Face</h2> + +<div style="float:right;margin-left:20px"> +<img src="{@docRoot}training/wearables/watch-faces/images/preview_calendar.png" + width="180" height="180" alt="" style="margin-left:10px;margin-top:10px"/> +<p class="img-caption"><strong>Figure 2.</strong> The calendar watch face.</p> +</div> + +<p>The <em>WatchFace</em> sample in the Android SDK demonstrates how to obtain calendar data +from the user’s profile in the <code>CalendarWatchFaceService</code> class and shows how many +meetings there are in the following twenty-four hours. This sample is located in the +<code>android-sdk/samples/android-21/wearable/WatchFace</code> directory.</p> + +<p>To implement a watch face that incorporates contextual data, follow these steps:</p> + +<ol> +<li>Provide a task that retrieves the data.</li> +<li>Create a custom timer to invoke your task periodically, or notify your watch face service + when external data changes.</li> +<li>Redraw your watch face with the updated data.</li> +</ol> + +<p>The following sections describe these steps in detail.</p> + +<h3 id="Task">Provide a task to retrieve data</h3> + +<p>Create a class inside your <code>CanvasWatchFaceService.Engine</code> implementation that +extends {@link android.os.AsyncTask} and add the code to retrieve the data you’re interested +in.</p> + +<p>The <code>CalendarWatchFaceService</code> class obtains the number of meetings in the next +day as follows:</p> + +<pre> +/* Asynchronous task to load the meetings from the content provider and + * report the number of meetings back using onMeetingsLoaded() */ +private class LoadMeetingsTask extends AsyncTask<Void, Void, Integer> { + @Override + protected Integer doInBackground(Void... voids) { + long begin = System.currentTimeMillis(); + Uri.Builder builder = + WearableCalendarContract.Instances.CONTENT_URI.buildUpon(); + ContentUris.appendId(builder, begin); + ContentUris.appendId(builder, begin + DateUtils.DAY_IN_MILLIS); + final Cursor cursor = getContentResolver() .query(builder.build(), + null, null, null, null); + int numMeetings = cursor.getCount(); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "Num meetings: " + numMeetings); + } + return numMeetings; + } + + @Override + protected void onPostExecute(Integer result) { + /* get the number of meetings and set the next timer tick */ + onMeetingsLoaded(result); + } +} +</pre> + +<p>The <code>WearableCalendarContract</code> class from the Wearable Support Library provides +direct access to the user's calendar events from the companion device.</p> + +<p>When the task finishes retrieving data, your code invokes a callback method. The following +sections describe how to implement the callback method in detail.</p> + +<p>For more information about obtaining data from the calendar, see the <a +href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a> API +guide.</p> + +<h3 id="Timer">Create a custom timer</h3> + +<p>You can implement a custom timer that ticks periodically to update your data. +The <code>CalendarWatchFaceService</code> class uses a {@link android.os.Handler} instance +that sends and processes delayed messages using the thread's message queue:</p> + +<pre> +private class Engine extends CanvasWatchFaceService.Engine { + ... + int mNumMeetings; + private AsyncTask<Void, Void, Integer> mLoadMeetingsTask; + + /* Handler to load the meetings once a minute in interactive mode. */ + final Handler mLoadMeetingsHandler = new Handler() { + @Override + public void handleMessage(Message message) { + switch (message.what) { + case MSG_LOAD_MEETINGS: + cancelLoadMeetingTask(); + mLoadMeetingsTask = new LoadMeetingsTask(); + mLoadMeetingsTask.execute(); + break; + } + } + }; + ... +} +</pre> + +<p>This method initializes the timer when the watch face becomes visible:</p> + +<pre> +@Override +public void onVisibilityChanged(boolean visible) { + super.onVisibilityChanged(visible); + if (visible) { + mLoadMeetingsHandler.sendEmptyMessage(MSG_LOAD_MEETINGS); + } else { + mLoadMeetingsHandler.removeMessages(MSG_LOAD_MEETINGS); + cancelLoadMeetingTask(); + } +} +</pre> + +<p>The next timer tick is set in the <code>onMeetingsLoaded()</code> method, as shown in the next +section.</p> + +<h3 id="Redraw">Redraw your watch face with the updated data</h3> + +<p>When the task that retrieves your data finishes, call the <code>invalidate()</code> method +so the system redraws your watch face. Store your data inside member variables of the +<code>Engine</code> class so you can access it inside the <code>onDraw()</code> method.</p> + +<p>The <code>CalendarWatchFaceService</code> class provides a callback method for the task to +invoke when it finishes retrieving calendar data:</p> + +<pre> +private void onMeetingsLoaded(Integer result) { + if (result != null) { + mNumMeetings = result; + invalidate(); + } + if (isVisible()) { + mLoadMeetingsHandler.sendEmptyMessageDelayed( + MSG_LOAD_MEETINGS, LOAD_MEETINGS_DELAY_MS); + } +} +</pre> + +<p>The callback method stores the result in a member variable, invalidates the view, and +schedules the next timer tick to run the task again.</p> diff --git a/docs/html/training/wearables/watch-faces/issues.jd b/docs/html/training/wearables/watch-faces/issues.jd new file mode 100644 index 0000000..47c5e8c --- /dev/null +++ b/docs/html/training/wearables/watch-faces/issues.jd @@ -0,0 +1,125 @@ +page.title=Addressing Common Issues + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#ScreenShape">Detect the Shape of the Screen</a></li> + <li><a href="#PeekCards">Accomodate Peek Cards</a></li> + <li><a href="#RelativeMeasurements">Use Relative Measurements</a></li> +</ol> +<h2>You should also read</h2> +<ul> + <li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li> +</ul> +</div> +</div> + +<p>Creating a custom watch face for Android Wear is substantially different from creating +notifications and wearable-specific activities. This class shows you how to resolve some +issues that you may encounter as you implement your first few watch faces.</p> + + + +<h2 id="ScreenShape">Detect the Shape of the Screen</h2> + +<p>Some Android Wear devices have square screens, while others have round screens. Devices with +round screens can contain an inset (or "chin") at the bottom of the screen. Your watch face +should adapt to and take advantage of the particular shape of the screen, as described in the +<a href="{@docRoot}design/wear/watchfaces.html">design guidelines</a>.</p> + +<p>Android Wear lets your watch face determine the screen shape at runtime. To detect whether +the screen is square or round, override the <code>onApplyWindowInsets()</code> method in the +<code>CanvasWatchFaceService.Engine</code> class as follows:</p> + +<pre> +private class Engine extends CanvasWatchFaceService.Engine { + boolean mIsRound; + int mChinSize; + + @Override + public void onApplyWindowInsets(WindowInsets insets) { + super.onApplyWindowInsets(insets); + mIsRound = insets.isRound(); + mChinSize = insets.getSystemWindowInsetBottom(); + } + ... +} +</pre> + +<p>To adapt your design when you draw your watch face, check the value of the +<code>mIsRound</code> and <code>mChinSize</code> member variables.</p> + + + +<h2 id="PeekCards">Accomodate Peek Cards</h2> + +<div style="float:right;margin-left:30px;width:340px"> +<img src="{@docRoot}training/wearables/watch-faces/images/AnalogNoCard.png" alt="" + width="160" height="145" style="margin-right:7px"/> +<img src="{@docRoot}training/wearables/watch-faces/images/AnalogWithCard.png" alt="" + width="160" height="145"/> +<p class="img-caption"><strong>Figure 1.</strong> Some analog watch faces require adjustments +when notification cards appear.</p> +</div> + +<p>When users receive a notification, the notification card may cover a significant portion of the +screen, depending on the +<a href="{@docRoot}training/wearables/watch-faces/drawing.html#SystemUI">system UI style</a>. Your +watch face should adapt to these situations by ensuring that users can still tell the time while +the notification card is present.</p> + +<p>Analog watch faces can make adjustments when a notification card is present, like scaling +down the watch face to fit inside the portion of the screen not covered by the peek card. Digital +watch faces that display the time in the area of the screen not covered by peek cards do not +usually require adjustments. To determine the free space above the peek card so you can adapt +your watch face, use the <code>WatchFaceService.getPeekCardPosition()</code> method.</p> + +<p>In ambient mode, peek cards have a transparent background. If your watch face contains details +near the card in ambient mode, consider drawing a black rectangle over them to ensure that users +can read the contents of the card.</p> + + + +<h2 id="SystemIndicators">Configure the System Indicators</h2> + +<div style="width:200px;float:right;margin-left:10px"> +<img src="{@docRoot}training/wearables/watch-faces/images/Indicators_Cropped.png" alt="" + width="200" height="195"/> +<p class="img-caption" style="margin-left:25px;margin-top:-25px"> +<strong>Figure 2.</strong> The status bar.</p> +</div> + +<p>To ensure that the system indicators remain visible, you can configure their position on the +screen and whether they need background protection when you create a <code>WatchFaceStyle</code> +instance:</p> + +<ul> +<li>To set the position of the status bar, use the <code>setStatusBarGravity()</code> method.</li> +<li>To set the position of the hotword, use the <code>setHotwordIndicatorGravity()</code> +method.</li> +<li>To protect the status bar and hotword with a semi-transparent gray background, use the +<code>setViewProtection()</code> method. This is usually necessary if your watch face has a +light background, since the system indicators are white.</li> +</ul> + +<p>For more information about the system indicators, see <a +href="{@docRoot}training/wearables/watch-faces/drawing.html#SystemUI">Configure the System UI</a> +and read the <a href="{@docRoot}design/wear/watchfaces.html">design guidelines</a>.</p> + + + +<h2 id="RelativeMeasurements">Use Relative Measurements</h2> + +<p>Android Wear devices from different manufacturers feature screens with a variety of sizes and +resolutions. Your watch face should adapt to these variations by using relative measurements +instead of absolute pixel values.</p> + +<p>When you draw your watch face, obtain the size of the canvas with the {@link +android.graphics.Canvas#getWidth Canvas.getWidth()} and {@link +android.graphics.Canvas#getHeight Canvas.getHeight()} methods and set the positions of your +graphic elements using values that are some fraction of the detected screen size. If you resize +the elements of your watch face in response to a peek card, use values that are some fraction +of the remaining space above the card to redraw your watch face.</p> diff --git a/docs/html/training/wearables/watch-faces/performance.jd b/docs/html/training/wearables/watch-faces/performance.jd new file mode 100644 index 0000000..68438fe --- /dev/null +++ b/docs/html/training/wearables/watch-faces/performance.jd @@ -0,0 +1,160 @@ +page.title=Optimizing Performance and Battery Life + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#ReduceSize">Reduce the Size of Your Bitmap Assets</a></li> + <li><a href="#CombineBitmaps">Combine Bitmap Assets</a></li> + <li><a href="#AntiAlias">Disable Anti-Aliasing when Drawing Scaled Bitmaps</a></li> + <li><a href="#OutDrawing">Move Expensive Operations Outside the Drawing Method</a></li> + <li><a href="#SavePower">Follow Best Practices to Save Power</a></li> +</ol> +<h2>You should also read</h2> +<ul> + <li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li> +</ul> +</div> +</div> + +<p>In addition to accommodating notification cards and system indicators, you need to ensure that +the animations in your watch face run smoothly and that your service does not perform unnecessary +computations. Watch faces in Android Wear run continuously on the device, so it is critical +that your watch face uses power efficiently.</p> + +<p>This lesson provides some tips to speed up your animations and to measure and conserve +power on the device.</p> + + + +<h2 id="ReduceSize">Reduce the Size of Your Bitmap Assets</h2> + +<p>Many watch faces consist of a background image and other graphic assets that are transformed +and overlapped on top of the background image, such as clock hands and other elements of the design +that move over time. Typically these graphic elements are rotated (and sometimes scaled) inside the +<code>Engine.onDraw()</code> method every time the system redraws the watch face, as described in +<a href="{@docRoot}training/wearables/watch-faces/drawing.html#Drawing">Draw Your Watch +Face</a>.</p> + +<p>The larger these graphic assets are, the more computationally expensive it is to transform them. +Transforming large graphic assets in the <code>Engine.onDraw()</code> method drastically reduces +the frame rate at which the system can run your animations.</p> + +<div id="fig1" style="float:right;width:250px;margin-left:25px"> +<img src="{@docRoot}training/wearables/watch-faces/images/ClockHandFull.png" alt="" + width="180" height="180"/> +<img src="{@docRoot}training/wearables/watch-faces/images/ClockHandCropped.png" alt="" + width="15" height="65" style="margin-left:25px"/> +<p class="img-caption"> +<strong>Figure 1.</strong> Clock hands can be cropped to remove extra pixels.</p> +</div> + +<p>To improve the performance of your watch face:</p> + +<ul> +<li>Do not use graphic elements that are larger than you need.</li> +<li>Remove extra transparent pixels around the edges.</li> +</ul> + +<p>The example clock hand on the left side of <a href="#fig1">Figure 1</a> can be reduced in size +by 97%.</p> + +<p>Reducing the size of your bitmap assets as described in this section not only improves +the performance of your animations, but it also saves power.</p> + + + +<h2 id="CombineBitmaps">Combine Bitmap Assets</h2> + +<p>If you have bitmaps that are often drawn together, consider combining them into the same +graphic asset. You can often combine the background image in interactive mode with the tick +marks to avoid drawing two full-screen bitmaps every time the system redraws the watch face.</p> + + + +<h2 id="AntiAlias">Disable Anti-Aliasing when Drawing Scaled Bitmaps</h2> + +<p>When you draw a scaled bitmap on the {@link android.graphics.Canvas} object using the {@link +android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint) +Canvas.drawBitmap()} method, you can provide a {@link android.graphics.Paint} instance to configure +several options. To improve performance, disable anti-aliasing using the {@link +android.graphics.Paint#setAntiAlias setAntiAlias()} method, since this option does not have any +effect on bitmaps.</p> + +<div id="fig2" style="float:right;width:250px;margin-left:40px;margin-top:12px"> +<img src="{@docRoot}training/wearables/watch-faces/images/BitmapFilterDisabled.png" alt="" + width="70" height="70" style="margin-left:20px"/> +<img src="{@docRoot}training/wearables/watch-faces/images/BitmapFilterEnabled.png" alt="" + width="70" height="70" style="margin-left:20px"/> +<p class="img-caption"><strong>Figure 2.</strong> Example of bitmap filtering disabled (left) and +enabled (right).</p> +</div> + +<h3 id="BitmapFiltering">Use bitmap filtering</h3> + +<p>For bitmap assets that you draw on top of other elements, enable bitmap filtering on the same +{@link android.graphics.Paint} instance using the {@link android.graphics.Paint#setFilterBitmap +setFilterBitmap()} method. <a href="#fig2">Figure 2</a> shows a magnified view of a clock hand with +and without bitmap filtering.</p> + + + +<h2 id="OutDrawing">Move Expensive Operations Outside the Drawing Method</h2> + +<p>The system calls the <code>Engine.onDraw()</code> method every time it redraws your watch +face, so you should only include operations that are strictly required to update the watch +face inside this method to improve performance.<p> + +<p>When possible, avoid performing these operations inside the <code>onDraw()</code> method:</p> + +<ul> +<li>Loading images and other resources.</li> +<li>Resizing images.</li> +<li>Allocating objects.</li> +<li>Performing computations whose result does not change between frames.</li> +</ul> + +<p>You can usually perform these operations in the <code>Engine.onCreate()</code> method instead. +You can resize images ahead of time in the {@link +android.service.wallpaper.WallpaperService.Engine#onSurfaceChanged(android.view.SurfaceHolder, int, int, int) +Engine.onSurfaceChanged()} method, which provides you with the size of the canvas.</p> + +<p>To analyze the performance of your watch face, use the Android Device Monitor. In particular, +ensure that the execution time for your <code>Engine.onDraw()</code> implementation is short and +consistent across invocations. For more information, see +<a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a>.</p> + + + +<h2 id="SavePower">Follow Best Practices to Save Power</h2> + +<p>In addition to the techniques described in the previous sections, follow the best +practices in this section to reduce the power consumption of your watch face.</p> + +<h3>Reduce the frame rate of animations</h3> + +<p>Animations are often computationally expensive and consume a significant amount of power. Most +animations look fluid at 30 frames per second, so you should avoid running your animations +at a higher frame rate.</p> + +<h3>Let the CPU sleep</h3> + +<p>Animations and small changes to the contents of the watch face wake up the CPU. Your watch +face should let the CPU sleep in between animations. For example, you can use short bursts of +animation every second in interactive mode and then let the CPU sleep until the next second. +Letting the CPU sleep often, even briefly, can significantly reduce power consumption.</p> + +<p>To maximize battery life, use animations sparingly. Even a blinking colon wakes up the CPU with +every blink and hurts battery life.</p> + +<h3>Monitor power consumption</h3> + +<p>The <a href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app&hl=en"> +Android Wear companion app</a> lets developers and users see how much battery different processes +on the wearable device are consuming under <strong>Settings</strong> > <strong>Watch +battery</strong>.</p> + +<p>For more information about new features in Android 5.0 that help you improve battery life, +see <a href="{@docRoot}about/versions/android-5.0.html#Power">Project Volta</a>.</p> diff --git a/docs/html/training/wearables/watch-faces/service.jd b/docs/html/training/wearables/watch-faces/service.jd new file mode 100644 index 0000000..0cb628c --- /dev/null +++ b/docs/html/training/wearables/watch-faces/service.jd @@ -0,0 +1,280 @@ +page.title=Building a Watch Face Service + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#CreateProject">Create and Configure Your Project</a></li> + <li><a href="#CallbackMethods">Implement the Service Callback Methods</a></li> + <li><a href="#RegisterService">Register the Service Implementation</a></li> +</ol> +<h2>You should also read</h2> +<ul> + <li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li> +</ul> +</div> +</div> + +<p>Watch faces in Android Wear are implemented as <a +href="{@docRoot}guide/components/services.html">services</a> and packaged inside a <a +href="{@docRoot}training/wearables/apps/index.html">wearable app</a>. When users install a +handheld app that contains a wearable app with watch faces, these watch faces become available +in the <a +href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app&hl=en">Android +Wear companion app</a> on the handheld device and in the watch face picker on the wearable. When +users select one of the available watch faces, the wearable device shows the watch face and +invokes its service callback methods as required.</p> + +<p>This lesson shows you how to configure an Android project to include watch faces and how +to implement the watch face service.</p> + + + +<h2 id="CreateProject">Create and Configure Your Project</h2> + +<p>To create an Android project for your watch face in Android Studio:</p> + +<ol> +<li>Start Android Studio.</li> +<li>Create a new project: + <ul> + <li>If you don't have a project opened, in the <strong>Welcome</strong> screen, click + <strong>New Project</strong>.</li> + <li>If you have a project opened, from the <strong>File</strong> menu, select <strong>New + Project</strong>.</li> + </ul> +</li> +<li>Provide an application name and click <strong>Next</strong>.</li> +<li>Select the <strong>Phone and Tablet</strong> form factor.</li> +<li>Under <strong>Minimum SDK</strong>, choose API 18.</li> +<li>Select the <strong>Wear</strong> form factor.</li> +<li>Under <strong>Minimum SDK</strong>, choose API 21 and click <strong>Next</strong>.</li> +<li>Select <strong>Add No Activity</strong> and click <strong>Next</strong> in the two following + screens.</li> +<li>Click <strong>Finish</strong>.</li> +<li>Click <strong>View</strong> > <strong>Tool Windows</strong> > <strong>Project</strong> in the + IDE window.</li> +</ol> + +<p>Android Studio creates a project with the <code>wear</code> and <code>mobile</code> modules. +For more information, see <a href="{@docRoot}sdk/installing/create-project.html">Creating a +Project</a>.</p> + +<h3 id="Dependencies">Dependencies</h3> + +<p>For the handheld app, edit the <code>build.gradle</code> file in the <code>mobile</code> module +to add these dependencies:</p> + +<pre> +apply plugin: 'com.android.application' + +android { ... } + +dependencies { + ... + wearApp project(':wear') + compile 'com.google.android.gms:play-services:6.1.+' +} +</pre> + +<p>For the wearable app, edit the <code>build.gradle</code> file in the <code>wear</code> module +to add these dependencies:</p> + +<pre> +apply plugin: 'com.android.application' + +android { ... } + +dependencies { + ... + compile 'com.google.android.support:wearable:1.1.+' + compile 'com.google.android.gms:play-services-wearable:6.1.+' +} +</pre> + +<p>The Wearable Support Library provides the necessary classes that you extend to create watch +face implementations. The Google Play services client libraries (<code>play-services</code> and +<code>play-services-wearable</code>) are required to sync data items between the companion device +and the wearable with the <a href="{@docRoot}training/wearables/data-layer/index.html">Wearable +Data Layer API</a>.</p> + +<h3 id="Reference">Wearable Support Library API Reference</h3> + +<p>The reference documentation provides detailed information about the classes you use to +implement watch faces. Download the +<a href="{@docRoot}shareables/training/wearable-support-docs.zip">API reference +documentation</a> for the Wearable Support Library.</p> + +<h3 id="LibEclipse">Download the Wearable Support Library for Eclipse ADT</h3> + +<p>If you are using the ADT plugin for Eclipse, download the +<a href="{@docRoot}shareables/training/wearable-support-lib.zip">Wearable Support Library</a> and +include it as a dependency in your project.</p> + +<h3 id="Permissions">Declare Permissions</h3> + +<p>Watch faces require the <code>PROVIDE_BACKGROUND</code> and <code>WAKE_LOCK</code> permissions. +Add the following permissions to the manifest files of both the wearable app and the mobile +app under the <code>manifest</code> element:</p> + +<pre> +<manifest ...> + <uses-permission + android:name="com.google.android.permission.PROVIDE_BACKGROUND" /> + <uses-permission + android:name="android.permission.WAKE_LOCK" /> + ... +</manifest> +</pre> + +<p class="caution"><strong>Caution:</strong> The handheld app must include all the permissions +declared in the wearable app.</p> + + + +<h2 id="CallbackMethods">Implement the Service and Callback Methods</h2> + +<p>Watch faces in Android Wear are implemented as +<a href="{@docRoot}guide/components/services.html">services</a>. +When a watch face is active, the system invokes the methods in its service when the time changes +or when an important event occurs (like switching to ambient mode or receiving a new +notification). The service implementation then draws the watch face on the screen using the +updated time and any other relevant data.</p> + +<p>To implement a watch face, you extend the <code>CanvasWatchFaceService</code> +and <code>CanvasWatchFaceService.Engine</code> classes, and then you override the callback methods +in the <code>CanvasWatchFaceService.Engine</code> class. These classes are included in the +Wearable Support Library.</p> + +<p>The following snippet outlines the key methods you need to implement:</p> + +<pre> +public class AnalogWatchFaceService extends CanvasWatchFaceService { + + @Override + public Engine onCreateEngine() { + /* provide your watch face implementation */ + return new Engine(); + } + + /* implement service callback methods */ + private class Engine extends CanvasWatchFaceService.Engine { + + @Override + public void onCreate(SurfaceHolder holder) { + /* initialize your watch face */ + } + + @Override + public void onPropertiesChanged(Bundle properties) { + /* get device features (burn-in, low-bit ambient) */ + } + + @Override + public void onTimeTick() { + /* the time changed */ + } + + @Override + public void onAmbientModeChanged(boolean inAmbientMode) { + /* the wearable switched between modes */ + } + + @Override + public void onDraw(Canvas canvas) { + /* draw your watch face */ + } + + @Override + public void onVisibilityChanged(boolean visible) { + /* the watch face became visible or invisible */ + } + } +} +</pre> + +<p class="note"><strong>Note:</strong> The <em>WatchFace</em> sample in the Android SDK +demonstrates how to implement analog and digital watch faces extending the +<code>CanvasWatchFaceService</code> class. This sample is located in the +<code>android-sdk/samples/android-21/wearable/WatchFace</code> directory.</p> + +<p>The <code>CanvasWatchFaceService</code> class provides an invalidate mechanism similar to +the {@link android.view.View#invalidate View.invalidate()} method. You can call the +<code>invalidate()</code> method throughout your implementation when you want the system to +redraw the watch face. You can only use the <code>invalidate()</code> method in the main UI +thread. To invalidate the canvas from another thread, call the <code>postInvalidate()</code> +method.</p> + +<p>For more information about implementing the methods in the +<code>CanvasWatchFaceService.Engine</code> class, see <a +href="{@docRoot}training/wearables/watch-faces/drawing.html">Drawing Watch Faces</a>.</p> + + + +<h2 id="RegisterService">Register the Watch Face Service</h2> + +<p>After you implement the watch face service, you register the implementation in the manifest +file of the wearable app. When users install this app, the system uses the information about +the service to make the watch face available in the <a +href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app&hl=en">Android +Wear companion app</a> and in the watch face picker on the wearable device.</p> + +</p>The following snippet shows how to register a watch face implementation +under the <a href="{@docRoot}guide/topics/manifest/application-element.html"> +<code>application</code></a> element:</p> + +<pre> +<service + android:name=".AnalogWatchFaceService" + android:label="@string/analog_name" + android:allowEmbedded="true" + android:taskAffinity="" + android:permission="android.permission.BIND_WALLPAPER" > + <meta-data + android:name="android.service.wallpaper" + android:resource="@xml/watch_face" /> + <meta-data + android:name="com.google.android.wearable.watchface.preview" + android:resource="@drawable/preview_analog" /> + <meta-data + android:name="com.google.android.wearable.watchface.preview_circular" + android:resource="@drawable/preview_analog_circular" /> + <intent-filter> + <action android:name="android.service.wallpaper.WallpaperService" /> + <category + android:name= + "com.google.android.wearable.watchface.category.WATCH_FACE" /> + </intent-filter> +</service> +</pre> + +<p>The <a +href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app&hl=en">Android +Wear companion app</a> and the watch face picker on the wearable device use the preview image +defined by the <code>com.google.android.wearable.watchface.preview</code> metadata entry when +presenting users with all the watch faces installed on the device. To obtain this drawable, +run the watch face on your Android Wear device or in an emulator instance and <a +href="{@docRoot}sdk/installing/studio-debug.html#screenCap">take a screenshot</a>. On Android Wear +devices with hdpi screens, the preview image is typically 320x320 pixels in size.</p> + +<p>Watch faces that look substantially different on round devices can provide both round and +square preview images. To specify a round preview image, use the +<code>com.google.android.wearable.watchface.preview_circular</code> metadata entry. If a watch +face includes both preview images, the companion app and the watch face picker on the wearable +show the appropriate one, depending on the shape of the watch. If a round preview image is not +included, the square preview image is used for both square and round devices. For round devices, +a square preview image is cropped using a circular shape.</p> + +<p>The <code>android.service.wallpaper</code> metadata entry specifies the +<code>watch_face.xml</code> resource file, which contains a <code>wallpaper</code> +element:</p> + +<pre> +<?xml version="1.0" encoding="UTF-8"?> +<wallpaper xmlns:android="http://schemas.android.com/apk/res/android" /> +</pre> + +<p>Your wearable app can contain more than one watch face. You must add a service entry to the +manifest file of the wearable app for each of your watch face implementations.</p> diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java index 9eb0251..74ff1b0 100644 --- a/graphics/java/android/graphics/drawable/AnimationDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java @@ -375,7 +375,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An mOneShot = orig.mOneShot; } else { mDurations = new int[getCapacity()]; - mOneShot = true; + mOneShot = false; } } diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index 79ac651..9be296a 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -48,6 +48,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.util.Collection; /** * A Drawable that wraps a bitmap and can be tiled, stretched, or aligned. You can create a @@ -913,8 +914,11 @@ public class BitmapDrawable extends Drawable { } @Override - public Bitmap getBitmap() { - return mBitmap; + public int addAtlasableBitmaps(Collection<Bitmap> atlasList) { + if (isAtlasable(mBitmap) && atlasList.add(mBitmap)) { + return mBitmap.getWidth() * mBitmap.getHeight(); + } + return 0; } @Override diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 1fac5b6..0e38cc0 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -51,6 +51,7 @@ import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.util.Arrays; +import java.util.Collection; /** * A Drawable is a general abstraction for "something that can be drawn." Most @@ -1244,10 +1245,16 @@ public abstract class Drawable { public abstract int getChangingConfigurations(); /** + * @return Total pixel count * @hide */ - public Bitmap getBitmap() { - return null; + public int addAtlasableBitmaps(Collection<Bitmap> atlasList) { + return 0; + } + + /** @hide */ + protected final boolean isAtlasable(Bitmap bitmap) { + return bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888; } /** diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 2748030..1e360d3 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; +import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Insets; @@ -31,6 +32,8 @@ import android.os.SystemClock; import android.util.LayoutDirection; import android.util.SparseArray; +import java.util.Collection; + /** * A helper class that contains several {@link Drawable}s and selects which one to use. * @@ -1062,6 +1065,20 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return true; } + /** @hide */ + @Override + public int addAtlasableBitmaps(Collection<Bitmap> atlasList) { + final int N = mNumChildren; + int pixelCount = 0; + for (int i = 0; i < N; i++) { + final ConstantState state = getChild(i).getConstantState(); + if (state != null) { + pixelCount += state.addAtlasableBitmaps(atlasList); + } + } + return pixelCount; + } + /** * Class capable of cloning a Drawable from another Drawable's * ConstantState. diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java index acfd427..8b70a08 100644 --- a/graphics/java/android/graphics/drawable/InsetDrawable.java +++ b/graphics/java/android/graphics/drawable/InsetDrawable.java @@ -19,6 +19,7 @@ package android.graphics.drawable; import com.android.internal.R; import android.annotation.NonNull; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -26,16 +27,19 @@ import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.Resources.Theme; +import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Insets; import android.graphics.Outline; import android.graphics.PixelFormat; import android.graphics.PorterDuff.Mode; +import android.graphics.drawable.Drawable.ConstantState; import android.graphics.Rect; import android.util.AttributeSet; import java.io.IOException; +import java.util.Collection; /** * A Drawable that insets another Drawable by a specified distance. @@ -472,6 +476,15 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { return mCanConstantState; } + + @Override + public int addAtlasableBitmaps(Collection<Bitmap> atlasList) { + final ConstantState state = mDrawable.getConstantState(); + if (state != null) { + return state.addAtlasableBitmaps(atlasList); + } + return 0; + } } private InsetDrawable(InsetState state, Resources res) { diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 689d225..4aa5f59 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -21,6 +21,7 @@ import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; +import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Outline; @@ -36,6 +37,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.util.Collection; /** * A Drawable that manages an array of other Drawables. These are drawn in array @@ -1105,6 +1107,20 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mHaveOpacity = false; mHaveIsStateful = false; } + + @Override + public int addAtlasableBitmaps(Collection<Bitmap> atlasList) { + final ChildDrawable[] array = mChildren; + final int N = mNum; + int pixelCount = 0; + for (int i = 0; i < N; i++) { + final ConstantState state = array[i].mDrawable.getConstantState(); + if (state != null) { + pixelCount += state.addAtlasableBitmaps(atlasList); + } + } + return pixelCount; + } } } diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index d821224..b87ae92 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -48,6 +48,7 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.InputStream; +import java.util.Collection; /** * @@ -289,7 +290,7 @@ public class NinePatchDrawable extends Drawable { if (bounds.isEmpty()) return; if (mNinePatchState != null) { - NinePatch.InsetStruct insets = mNinePatchState.getBitmap().getNinePatchInsets(); + NinePatch.InsetStruct insets = mNinePatchState.mNinePatch.getBitmap().getNinePatchInsets(); if (insets != null) { final Rect outlineInsets = insets.outlineRect; outline.setRoundRect(bounds.left + outlineInsets.left, @@ -648,8 +649,12 @@ public class NinePatchDrawable extends Drawable { } @Override - public Bitmap getBitmap() { - return mNinePatch.getBitmap(); + public int addAtlasableBitmaps(Collection<Bitmap> atlasList) { + final Bitmap bitmap = mNinePatch.getBitmap(); + if (isAtlasable(bitmap) && atlasList.add(bitmap)) { + return bitmap.getWidth() * bitmap.getHeight(); + } + return 0; } @Override diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 13e3d54..9809606 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -556,11 +556,13 @@ public class RippleDrawable extends LayerDrawable { if (mRipple != null) { mRipple.cancel(); mRipple = null; + mRippleActive = false; } if (mBackground != null) { mBackground.cancel(); mBackground = null; + mBackgroundActive = false; } cancelExitingRipples(); diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index d6d4cb8..da722f3 100644 --- a/graphics/java/android/graphics/drawable/ScaleDrawable.java +++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java @@ -31,6 +31,7 @@ import android.view.Gravity; import android.util.AttributeSet; import java.io.IOException; +import java.util.Collection; /** * A Drawable that changes the size of another Drawable based on its current @@ -413,6 +414,15 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { return mCanConstantState; } + + @Override + public int addAtlasableBitmaps(Collection<Bitmap> atlasList) { + final ConstantState state = mDrawable.getConstantState(); + if (state != null) { + return state.addAtlasableBitmaps(atlasList); + } + return 0; + } } private ScaleDrawable(ScaleState state, Resources res) { diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp index 21c869b..b2dba00 100644 --- a/libs/hwui/AmbientShadow.cpp +++ b/libs/hwui/AmbientShadow.cpp @@ -325,6 +325,7 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque, // At the end, update the real index and vertex buffer size. shadowVertexBuffer.updateVertexCount(vertexBufferIndex); shadowVertexBuffer.updateIndexCount(indexBufferIndex); + shadowVertexBuffer.computeBounds<AlphaVertex>(); ShadowTessellator::checkOverflow(vertexBufferIndex, totalVertexCount, "Ambient Vertex Buffer"); ShadowTessellator::checkOverflow(indexBufferIndex, totalIndexCount, "Ambient Index Buffer"); diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index cb8a8d1..7a43a2a 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -77,18 +77,14 @@ public: OpenGLRenderer& mRenderer; const int mReplayFlags; - // Allocator with the lifetime of a single frame. - // replay uses an Allocator owned by the struct, while defer shares the DeferredDisplayList's Allocator + // Allocator with the lifetime of a single frame. replay uses an Allocator owned by the struct, + // while defer shares the DeferredDisplayList's Allocator + // TODO: move this allocator to be owned by object with clear frame lifecycle LinearAllocator * const mAllocator; SkPath* allocPathForFrame() { - mTempPaths.push_back(); - return &mTempPaths.back(); + return mRenderer.allocPathForFrame(); } - -private: - // Paths kept alive for the duration of the frame - std::vector<SkPath> mTempPaths; }; class DeferStateStruct : public PlaybackStateStruct { diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index d78c1cb..96e76d0 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -720,7 +720,8 @@ public: } virtual void output(int level, uint32_t logFlags) const { - OP_LOG("Draw bitmap %p at %f %f", mBitmap, mLocalBounds.left, mLocalBounds.top); + OP_LOG("Draw bitmap %p at %f %f%s", mBitmap, mLocalBounds.left, mLocalBounds.top, + mEntry ? " using AssetAtlas" : ""); } virtual const char* name() { return "DrawBitmap"; } @@ -954,7 +955,8 @@ public: } virtual void output(int level, uint32_t logFlags) const { - OP_LOG("Draw patch " RECT_STRING, RECT_ARGS(mLocalBounds)); + OP_LOG("Draw patch " RECT_STRING "%s", RECT_ARGS(mLocalBounds), + mEntry ? " with AssetAtlas" : ""); } virtual const char* name() { return "DrawPatch"; } diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 075f2c5..96257e4 100755 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -311,6 +311,11 @@ void OpenGLRenderer::finish() { renderOverdraw(); endTiling(); + for (size_t i = 0; i < mTempPaths.size(); i++) { + delete mTempPaths[i]; + } + mTempPaths.clear(); + // When finish() is invoked on FBO 0 we've reached the end // of the current frame if (getTargetFbo() == 0) { diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index e1c3d10..5eee2e2 100755 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -342,6 +342,12 @@ public: uint8_t getAmbientShadowAlpha() const { return mAmbientShadowAlpha; } uint8_t getSpotShadowAlpha() const { return mSpotShadowAlpha; } + SkPath* allocPathForFrame() { + SkPath* path = new SkPath(); + mTempPaths.push_back(path); + return path; + } + protected: /** * Perform the setup specific to a frame. This method does not @@ -1014,6 +1020,9 @@ private: uint8_t mAmbientShadowAlpha; uint8_t mSpotShadowAlpha; + // Paths kept alive for the duration of the frame + std::vector<SkPath*> mTempPaths; + friend class Layer; friend class TextSetupFunctor; friend class DrawBitmapOp; diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp index 717ce9a..31bd637 100644 --- a/libs/hwui/ResourceCache.cpp +++ b/libs/hwui/ResourceCache.cpp @@ -68,8 +68,6 @@ void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) } void ResourceCache::incrementRefcount(const SkBitmap* bitmapResource) { - bitmapResource->pixelRef()->globalRef(); - SkSafeRef(bitmapResource->getColorTable()); incrementRefcount((void*) bitmapResource, kBitmap); } @@ -92,8 +90,6 @@ void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourc } void ResourceCache::incrementRefcountLocked(const SkBitmap* bitmapResource) { - bitmapResource->pixelRef()->globalRef(); - SkSafeRef(bitmapResource->getColorTable()); incrementRefcountLocked((void*) bitmapResource, kBitmap); } @@ -111,8 +107,6 @@ void ResourceCache::decrementRefcount(void* resource) { } void ResourceCache::decrementRefcount(const SkBitmap* bitmapResource) { - bitmapResource->pixelRef()->globalUnref(); - SkSafeUnref(bitmapResource->getColorTable()); decrementRefcount((void*) bitmapResource); } @@ -138,8 +132,6 @@ void ResourceCache::decrementRefcountLocked(void* resource) { } void ResourceCache::decrementRefcountLocked(const SkBitmap* bitmapResource) { - bitmapResource->pixelRef()->globalUnref(); - SkSafeUnref(bitmapResource->getColorTable()); decrementRefcountLocked((void*) bitmapResource); } diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 03ecad2..ea9e703 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -3110,11 +3110,12 @@ public class AudioService extends IAudioService.Stub { break; } if ((direction == AudioManager.ADJUST_LOWER)) { - if (VOLUME_SETS_RINGER_MODE_SILENT - && mPrevVolDirection != AudioManager.ADJUST_LOWER) { - ringerMode = RINGER_MODE_SILENT; - } else { - result |= AudioManager.FLAG_SHOW_VIBRATE_HINT; + if (mPrevVolDirection != AudioManager.ADJUST_LOWER) { + if (VOLUME_SETS_RINGER_MODE_SILENT) { + ringerMode = RINGER_MODE_SILENT; + } else { + result |= AudioManager.FLAG_SHOW_VIBRATE_HINT; + } } } else if (direction == AudioManager.ADJUST_RAISE) { ringerMode = RINGER_MODE_NORMAL; @@ -4298,6 +4299,13 @@ public class AudioService extends IAudioService.Stub { } } } + + synchronized (mAudioPolicies) { + for(AudioPolicyProxy policy : mAudioPolicies.values()) { + policy.connectMixes(); + } + } + // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); break; @@ -5938,7 +5946,7 @@ public class AudioService extends IAudioService.Stub { if (mHasFocusListener) { mMediaFocusControl.addFocusFollower(mPolicyToken); } - updateMixes(AudioSystem.DEVICE_STATE_AVAILABLE); + connectMixes(); } public void binderDied() { @@ -5960,23 +5968,11 @@ public class AudioService extends IAudioService.Stub { if (mHasFocusListener) { mMediaFocusControl.removeFocusFollower(mPolicyToken); } - updateMixes(AudioSystem.DEVICE_STATE_UNAVAILABLE); + AudioSystem.registerPolicyMixes(mMixes, false); } - void updateMixes(int connectionState) { - for (AudioMix mix : mMixes) { - // TODO implement sending the mix attribute matching info to native audio policy - if (DEBUG_AP) { - Log.v(TAG, "AudioPolicyProxy mix new connection state=" + connectionState - + " addr=" + mix.getRegistration()); - } - AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_REMOTE_SUBMIX, - connectionState, - mix.getRegistration()); - AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, - connectionState, - mix.getRegistration()); - } + void connectMixes() { + AudioSystem.registerPolicyMixes(mMixes, true); } }; diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index e795fa7..46ab7e0 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -16,6 +16,7 @@ package android.media; +import android.media.audiopolicy.AudioMix; import java.util.ArrayList; /* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET @@ -566,5 +567,7 @@ public class AudioSystem public static final int AUDIO_HW_SYNC_INVALID = 0; public static native int getAudioHwSyncForSession(int sessionId); + + public static native int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register); } diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java index 400c082..8d6a588 100644 --- a/media/java/android/media/ImageReader.java +++ b/media/java/android/media/ImageReader.java @@ -578,7 +578,11 @@ public class ImageReader implements AutoCloseable { @Override public int getWidth() { if (mIsImageValid) { - return ImageReader.this.mWidth; + if (mWidth == -1) { + mWidth = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getWidth() : + nativeGetWidth(); + } + return mWidth; } else { throw new IllegalStateException("Image is already released"); } @@ -587,7 +591,11 @@ public class ImageReader implements AutoCloseable { @Override public int getHeight() { if (mIsImageValid) { - return ImageReader.this.mHeight; + if (mHeight == -1) { + mHeight = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getHeight() : + nativeGetHeight(); + } + return mHeight; } else { throw new IllegalStateException("Image is already released"); } @@ -721,9 +729,13 @@ public class ImageReader implements AutoCloseable { private SurfacePlane[] mPlanes; private boolean mIsImageValid; + private int mHeight = -1; + private int mWidth = -1; private synchronized native ByteBuffer nativeImageGetBuffer(int idx, int readerFormat); private synchronized native SurfacePlane nativeCreatePlane(int idx, int readerFormat); + private synchronized native int nativeGetWidth(); + private synchronized native int nativeGetHeight(); } private synchronized native void nativeInit(Object weakSelf, int w, int h, diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index acf1b43..615dac2 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -61,6 +61,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -979,6 +980,9 @@ public class MediaPlayer implements SubtitleController.Listener // Redirect ringtones to go directly to underlying provider uri = RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.getDefaultType(uri)); + if (uri == null) { + throw new FileNotFoundException("Failed to resolve default ringtone"); + } } AssetFileDescriptor fd = null; diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java index 7d075ba..8441541 100644 --- a/media/java/android/media/Ringtone.java +++ b/media/java/android/media/Ringtone.java @@ -51,6 +51,12 @@ public class Ringtone { private final Context mContext; private final AudioManager mAudioManager; + + /** + * Flag indicating if we're allowed to fall back to remote playback using + * {@link #mRemotePlayer}. Typically this is false when we're the remote + * player and there is nobody else to delegate to. + */ private final boolean mAllowRemote; private final IRingtonePlayer mRemotePlayer; private final Binder mRemoteToken; @@ -211,12 +217,7 @@ public class Ringtone { mLocalPlayer.setAudioAttributes(mAudioAttributes); mLocalPlayer.prepare(); - } catch (SecurityException e) { - destroyLocalPlayer(); - if (!mAllowRemote) { - Log.w(TAG, "Remote playback not allowed: " + e); - } - } catch (IOException e) { + } catch (SecurityException | IOException e) { destroyLocalPlayer(); if (!mAllowRemote) { Log.w(TAG, "Remote playback not allowed: " + e); diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index e13f008..df4bc78 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -412,7 +412,9 @@ public final class MediaSession { * @param metadata The new metadata */ public void setMetadata(@Nullable MediaMetadata metadata) { - metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build(); + if (metadata != null ) { + metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build(); + } try { mBinder.setMetadata(metadata); } catch (RemoteException e) { diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 7830c80..3f4736d 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -615,6 +615,24 @@ static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buff return rowStride; } +static int Image_getBufferWidth(CpuConsumer::LockedBuffer* buffer) { + if (buffer == NULL) return -1; + + if (!buffer->crop.isEmpty()) { + return buffer->crop.getWidth(); + } + return buffer->width; +} + +static int Image_getBufferHeight(CpuConsumer::LockedBuffer* buffer) { + if (buffer == NULL) return -1; + + if (!buffer->crop.isEmpty()) { + return buffer->crop.getHeight(); + } + return buffer->height; +} + // ---------------------------------------------------------------------------- static void ImageReader_classInit(JNIEnv* env, jclass clazz) @@ -795,33 +813,16 @@ static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, } // Check if the producer buffer configurations match what ImageReader configured. - // We want to fail for the very first image because this case is too bad. - int outputWidth = buffer->width; - int outputHeight = buffer->height; - - // Correct width/height when crop is set. - if (!buffer->crop.isEmpty()) { - outputWidth = buffer->crop.getWidth(); - outputHeight = buffer->crop.getHeight(); - } + int outputWidth = Image_getBufferWidth(buffer); + int outputHeight = Image_getBufferHeight(buffer); int imgReaderFmt = ctx->getBufferFormat(); int imageReaderWidth = ctx->getBufferWidth(); int imageReaderHeight = ctx->getBufferHeight(); if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) && (imgReaderFmt != 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; + (imageReaderWidth != outputWidth || imageReaderHeight != outputHeight)) { + ALOGV("%s: Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d", + __FUNCTION__, outputWidth, outputHeight, imageReaderWidth, imageReaderHeight); } int bufFmt = buffer->format; @@ -934,6 +935,19 @@ static jobject Image_getByteBuffer(JNIEnv* env, jobject thiz, int idx, int reade return byteBuffer; } +static jint Image_getWidth(JNIEnv* env, jobject thiz) +{ + CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz); + return Image_getBufferWidth(buffer); +} + +static jint Image_getHeight(JNIEnv* env, jobject thiz) +{ + CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz); + return Image_getBufferHeight(buffer); +} + + } // extern "C" // ---------------------------------------------------------------------------- @@ -943,14 +957,16 @@ static JNINativeMethod gImageReaderMethods[] = { {"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;)I", (void*)ImageReader_imageSetup }, + {"nativeImageSetup", "(Landroid/media/Image;)I", (void*)ImageReader_imageSetup }, {"nativeGetSurface", "()Landroid/view/Surface;", (void*)ImageReader_getSurface }, }; static JNINativeMethod gImageMethods[] = { {"nativeImageGetBuffer", "(II)Ljava/nio/ByteBuffer;", (void*)Image_getByteBuffer }, {"nativeCreatePlane", "(II)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;", - (void*)Image_createSurfacePlane }, + (void*)Image_createSurfacePlane }, + {"nativeGetWidth", "()I", (void*)Image_getWidth }, + {"nativeGetHeight", "()I", (void*)Image_getHeight }, }; int register_android_media_ImageReader(JNIEnv *env) { diff --git a/packages/Keyguard/res/values-af/strings.xml b/packages/Keyguard/res/values-af/strings.xml index 7444c63..4bfd98e 100644 --- a/packages/Keyguard/res/values-af/strings.xml +++ b/packages/Keyguard/res/values-af/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Wagwoord ontsluit."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Patroonarea."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Sleep-area."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN-area"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM-PIN-area"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM-PUK-area"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Vorigesnit-knoppie"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Volgendesnit-knoppie"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Laatwag-knoppie"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou tablet te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Verwyder"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Verkeerde SIM PIN-kode, jy sal nou jou diensverskaffer moet kontak om jou toestel te ontsluit."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-am/strings.xml b/packages/Keyguard/res/values-am/strings.xml index e84134e..714a3eb 100644 --- a/packages/Keyguard/res/values-am/strings.xml +++ b/packages/Keyguard/res/values-am/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"የፒን አካባቢ"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"የሲም ፒን አካባቢ"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"የሲም PUK አካባቢ"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ልክ ያልሆነ የሲም ኮድ። አሁን መሳሪያዎን ለማስከፈት ድምጸ ተያያዥ ሞደምዎን ማግኘት አለብዎ።"</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-ar/strings.xml b/packages/Keyguard/res/values-ar/strings.xml index cd926f4..5a8d2bd 100644 --- a/packages/Keyguard/res/values-ar/strings.xml +++ b/packages/Keyguard/res/values-ar/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"منطقة رقم التعريف الشخصي"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"منطقة رقم التعريف الشخصي لبطاقة SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"منطقة PUK لبطاقة SIM"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> من المرات. ستتم إزالة الملف الشخصي للعمل والتي بدورها تحذف جميع بياناته."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"رمز \"رقم التعريف الشخصي\" لبطاقة SIM غير صحيح، ويلزمك الاتصال الآن بمشغّل شبكة الجوّال لإلغاء قفل الجهاز."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-bg/strings.xml b/packages/Keyguard/res/values-bg/strings.xml index 5f963d8..bdfbdff 100644 --- a/packages/Keyguard/res/values-bg/strings.xml +++ b/packages/Keyguard/res/values-bg/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"Област за ПИН кода"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Област за ПИН кода на SIM картата"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Област за PUK кода на SIM картата"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Неправилно опитахте да отключите телефона <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Неправилен ПИН код за SIM картата – сега трябва да се свържете с оператора си, за да отключите устройството."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-bn-rBD/strings.xml b/packages/Keyguard/res/values-bn-rBD/strings.xml index 5af9631..77acaf8 100644 --- a/packages/Keyguard/res/values-bn-rBD/strings.xml +++ b/packages/Keyguard/res/values-bn-rBD/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN অঞ্চল"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN অঞ্চল"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK অঞ্চল"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুল করে ফোনটি আনলক করার চেষ্টা করেছেন৷ কাজের প্রোফাইল সরানো হবে যা সমস্ত প্রোফাইল ডেটা মুছে ফেলবে৷"</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ভুল সিম PIN কোড, আপনার ডিভাইসটি আনলক করতে এখন আপনাকে অবশ্যই আপনার ক্যারিয়ারের সাথে যোগাযোগ করতে হবে৷"</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-ca/strings.xml b/packages/Keyguard/res/values-ca/strings.xml index 82023d2..ac745f1 100644 --- a/packages/Keyguard/res/values-ca/strings.xml +++ b/packages/Keyguard/res/values-ca/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueig mitjançant contrasenya"</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Àrea de patró"</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Àrea per lliscar el dit"</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Zona del PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Zona del PIN de la SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Zona del PUK de la SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botó de pista anterior"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botó de pista següent"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botó de pausa"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER">%d</xliff:g> vegades. El perfil professional se suprimirà, juntament amb totes les dades que contingui."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Elimina"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"El codi PIN de la SIM no és correcte. Has de contactar amb l\'operador de telefonia mòbil per desbloquejar el dispositiu."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-cs/strings.xml b/packages/Keyguard/res/values-cs/strings.xml index 01e3a01..141fe41 100644 --- a/packages/Keyguard/res/values-cs/strings.xml +++ b/packages/Keyguard/res/values-cs/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Odemknutí heslem."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Oblast pro zadání bezpečnostního gesta."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Oblast pro přejetí prstem."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Oblast kódu PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Oblast kódu PIN SIM karty"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Oblast kódu PUK SIM karty"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Tlačítko Předchozí stopa"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Tlačítko Další stopa"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Tlačítko Pozastavit"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odebrat"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Zadali jste nesprávný kód PIN SIM karty. Nyní musíte za účelem odemknutí zařízení kontaktovat svého operátora."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml index 89f0d0c..93b5756 100644 --- a/packages/Keyguard/res/values-da/strings.xml +++ b/packages/Keyguard/res/values-da/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Lås op med adgangskode."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Mønsterområde."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Strygeområde."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Område for pinkoden"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Område for pinkoden til simkortet"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Område for PUK-koden til simkortet"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Knap til forrige nummer"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Knap til næste nummer"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pause-knap"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket vil slette alle profildata."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg vil du blive bedt om at låse din tablet op ved hjælp af en e-mailkonto\n\n Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en e-mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Forkert pinkode til SIM-kort. Du skal nu kontakte dit mobilselskab for at låse din enhed op."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-de/strings.xml b/packages/Keyguard/res/values-de/strings.xml index ea05822..f6545a1 100644 --- a/packages/Keyguard/res/values-de/strings.xml +++ b/packages/Keyguard/res/values-de/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Entsperrung mit Passwort"</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Bereich für Muster"</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Bereich für Fingerbewegung"</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN-Bereich"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM-PIN-Bereich"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM-PUK-Bereich"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Schaltfläche für vorherigen Titel"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Schaltfläche für nächsten Titel"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Schaltfläche für Pause"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Entfernen"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Falscher PIN-Code der SIM-Karte. Bitte wenden Sie sich an Ihren Mobilfunkanbieter, damit er Ihr Gerät entsperrt."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-el/strings.xml b/packages/Keyguard/res/values-el/strings.xml index 8e03595..9dbe709 100644 --- a/packages/Keyguard/res/values-el/strings.xml +++ b/packages/Keyguard/res/values-el/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"Περιοχή PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Περιοχή PIN SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Περιοχή PUK SIM"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα προφίλ."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το tablet σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Εσφαλμένος κωδικός PIN κάρτας SIM. Θα πρέπει να επικοινωνήσετε με τον πάροχο κινητής τηλεφωνίας σας για να ξεκλειδώσετε τη συσκευή σας."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-en-rGB/strings.xml b/packages/Keyguard/res/values-en-rGB/strings.xml index cb1f0a8..6ac27be 100644 --- a/packages/Keyguard/res/values-en-rGB/strings.xml +++ b/packages/Keyguard/res/values-en-rGB/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN area"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN area"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK 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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-en-rIN/strings.xml b/packages/Keyguard/res/values-en-rIN/strings.xml index cb1f0a8..6ac27be 100644 --- a/packages/Keyguard/res/values-en-rIN/strings.xml +++ b/packages/Keyguard/res/values-en-rIN/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN area"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN area"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK 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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-es-rUS/strings.xml b/packages/Keyguard/res/values-es-rUS/strings.xml index 12b85c0..80058ba 100644 --- a/packages/Keyguard/res/values-es-rUS/strings.xml +++ b/packages/Keyguard/res/values-es-rUS/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueo por contraseña"</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Área de patrón"</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Área de deslizamiento"</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Área de PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Área de PIN de SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Área de PUK de SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botón de pista anterior"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botón de pista siguiente"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botón de pausa"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se eliminará el perfil de trabajo y se perderán todos los datos de perfil."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tablet mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminar"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"El código PIN de la tarjeta SIM es incorrecto. Debes comunicarte con el proveedor para desbloquear el dispositivo."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-es/strings.xml b/packages/Keyguard/res/values-es/strings.xml index 63d644e..9d6cdc4 100644 --- a/packages/Keyguard/res/values-es/strings.xml +++ b/packages/Keyguard/res/values-es/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueo por contraseña"</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Área de patrón"</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Área para deslizar"</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Área de PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Área de PIN de SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Área de PUK de SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botón de canción anterior"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botón de siguiente canción"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botón de pausa"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. El perfil de trabajo se eliminará, lo que borrará todos sus datos."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el tablet.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminar"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Código PIN de la tarjeta SIM incorrecto. Debes ponerte en contacto con tu operador para desbloquear el dispositivo."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-et-rEE/strings.xml b/packages/Keyguard/res/values-et-rEE/strings.xml index 5a5954a..ab953e1 100644 --- a/packages/Keyguard/res/values-et-rEE/strings.xml +++ b/packages/Keyguard/res/values-et-rEE/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN-koodi ala"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM-kaardi PIN-koodi ala"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM-kaardi PUK-koodi ala"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda valesti telefoni avada. Tööprofiil eemaldatakse ja kõik profiili andmed kustutatakse."</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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Vale SIM-i PIN-kood, seadme avamiseks peate nüüd ühendust võtma oma operaatoriga."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-eu-rES/strings.xml b/packages/Keyguard/res/values-eu-rES/strings.xml index 6f6f7f9..ba2c931 100644 --- a/packages/Keyguard/res/values-eu-rES/strings.xml +++ b/packages/Keyguard/res/values-eu-rES/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Pasahitzaren bidez desblokeatzea."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Eredua marrazteko eremua."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Hatza lerratzeko eremua."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN kodearen eremua"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM txartelaren PIN kodearen eremua"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM txartelaren PUK kodearen eremua"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Aurreko pistara joateko botoia"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Hurrengo pistara joateko botoia"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pausatzeko botoia"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz oker marrazten baduzu, tableta posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%d</xliff:g> segundo barru."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz oker marrazten baduzu, telefonoa posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%d</xliff:g> segundo barru."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Kendu"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM txartelaren PIN kodea okerra da. Gailua desblokeatzeko, jarri operadorearekin harremanetan."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-fa/strings.xml b/packages/Keyguard/res/values-fa/strings.xml index 785c80e..fea1f59 100644 --- a/packages/Keyguard/res/values-fa/strings.xml +++ b/packages/Keyguard/res/values-fa/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"قسمت پین"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"قسمت پین سیمکارت"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"قسمت PUK سیمکارت"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. نمایه کار حذف میشود که با آن همه اطلاعات نمایه حذف میشود."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"کد پین سیم کارت اشتباه است، اکنون برای گشودن قفل دستگاهتان باید با شرکت مخابراتی تماس بگیرید."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-fi/strings.xml b/packages/Keyguard/res/values-fi/strings.xml index d54460d..6cbc029 100644 --- a/packages/Keyguard/res/values-fi/strings.xml +++ b/packages/Keyguard/res/values-fi/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Lukituksen poisto salasanalla."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Kuvioalue."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Liu\'utusalue."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN-koodin alue"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM-kortin PIN-koodin alue"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM-kortin PUK-koodin alue"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Edellinen kappale -painike"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Seuraava kappale -painike"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Tauko-painike"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen tiedot poistetaan."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan tablet-laitteesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Poista"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Virheellinen SIM-kortin PIN-koodi. Sinun on nyt otettava yhteys operaattoriin laitteen lukituksen avaamiseksi."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-fr-rCA/strings.xml b/packages/Keyguard/res/values-fr-rCA/strings.xml index c59d1f3..d5b62ee 100644 --- a/packages/Keyguard/res/values-fr-rCA/strings.xml +++ b/packages/Keyguard/res/values-fr-rCA/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"Zone du NIP"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Zone du NIP de la carte SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Zone du code PUK de la carte SIM"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"NIP de carte SIM incorrect. Vous devez maintenant communiquer avec votre fournisseur de services pour déverrouiller votre appareil."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-fr/strings.xml b/packages/Keyguard/res/values-fr/strings.xml index c58e220..5a62057 100644 --- a/packages/Keyguard/res/values-fr/strings.xml +++ b/packages/Keyguard/res/values-fr/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"Champ du code PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Champ du code PIN de la carte SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Champ du code PUK de la carte SIM"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Code PIN de la carte SIM incorrect. Vous devez désormais contacter votre opérateur pour déverrouiller votre appareil."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-gl-rES/strings.xml b/packages/Keyguard/res/values-gl-rES/strings.xml index a55cbb8..4cd8ae0 100644 --- a/packages/Keyguard/res/values-gl-rES/strings.xml +++ b/packages/Keyguard/res/values-gl-rES/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueo mediante contrasinal"</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Zona do padrón"</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Zona para pasar o dedo"</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Área do PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Área do PIN da tarxeta SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Área do PUK da tarxeta SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botón de pista anterior"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botón de pista seguinte"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botón de pausa"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Eliminarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, terás que desbloquear o tablet a través dunha unha conta de correo electrónico.\n\n Téntao de novo dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, terás que desbloquear o teléfono a través dunha conta de correo electrónico.\n\n Téntao de novo dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminar"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"O código PIN da SIM non é correcto. Agora debes contactar co teu operador para desbloquear o dispositivo."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml index ba21954..c2e3b7e 100644 --- a/packages/Keyguard/res/values-hi/strings.xml +++ b/packages/Keyguard/res/values-hi/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"पिन क्षेत्र"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"सिम पिन क्षेत्र"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"सिम PUK क्षेत्र"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास किया है. कार्य प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"गलत सिम PIN कोड अपने डिवाइस को अनलॉक करने के लिए अब आपको अपने वाहक से संपर्क करना होगा."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-hr/strings.xml b/packages/Keyguard/res/values-hr/strings.xml index b718b03..56c4bb1 100644 --- a/packages/Keyguard/res/values-hr/strings.xml +++ b/packages/Keyguard/res/values-hr/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Otključavanje zaporkom."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Područje uzorka."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Područje klizanja."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Područje PIN-a"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Područje PIN-a za SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Područje PUK-a za SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Gumb Prethodni zapis"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Gumb Sljedeći zapis"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Gumb Pauza"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati tabletno računalo pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ukloni"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Netočan PIN kôd SIM kartice; sada morate kontaktirati svog mobilnog operatera da bi otključao vaš uređaj."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-hu/strings.xml b/packages/Keyguard/res/values-hu/strings.xml index d4ae4c3..74a63bb 100644 --- a/packages/Keyguard/res/values-hu/strings.xml +++ b/packages/Keyguard/res/values-hu/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Feloldás jelszóval"</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Mintaterület"</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Csúsztatási terület"</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN kód területe"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN kód területe"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK kód területe"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Előző szám gomb"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Következő szám gomb"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Szünet gomb"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer eltávolítja munkahelyi profilját, és összes profiladata törlődik."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a táblagépét.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a telefonját.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eltávolítás"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Helytelen PIN kód a SIM kártyához; vegye fel a kapcsolatot szolgáltatójával az eszköz feloldásához."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-hy-rAM/strings.xml b/packages/Keyguard/res/values-hy-rAM/strings.xml index 4d2f728..e233d12 100644 --- a/packages/Keyguard/res/values-hy-rAM/strings.xml +++ b/packages/Keyguard/res/values-hy-rAM/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN կոդի տարածք"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM քարտի PIN կոդի տարածք"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM քարտի PUK կոդի տարածք"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Դուք սխալ եք հավաքել ձեր ապակողպման սխեման <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Սխալ SIM PIN կոդի պատճառով պետք է դիմեք ձեր օպերատորին՝ սարքն արգելաբացելու համար:"</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-in/strings.xml b/packages/Keyguard/res/values-in/strings.xml index 7f5a03b..d637208 100644 --- a/packages/Keyguard/res/values-in/strings.xml +++ b/packages/Keyguard/res/values-in/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Buka kunci dengan sandi."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Area pola."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Area geser."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Bidang PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Bidang PIN SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Bidang PUK SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Tombol lagu sebelumnya"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Tombol lagu berikutnya"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Tombol jeda"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Profil kerja akan dihapus, sehingga menghapus semua data profil."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Hapus"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Kode PIN SIM salah. Hubungi operator untuk membuka kunci perangkat."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-is-rIS/strings.xml b/packages/Keyguard/res/values-is-rIS/strings.xml index 3f594b7..d1d8dc2 100644 --- a/packages/Keyguard/res/values-is-rIS/strings.xml +++ b/packages/Keyguard/res/values-is-rIS/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Opnun með aðgangsorði."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Svæði mynsturs."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Stroksvæði."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN-svæði"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"PIN-svæði SIM-korts"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"PUK-svæði SIM-korts"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Hnappur fyrir fyrra lag"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Hnappur fyrir næsta lag"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Hnappur til að gera hlé"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna spjaldtölvuna með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%d</xliff:g> sekúndur."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna símann með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%d</xliff:g> sekúndur."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjarlægja"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Rangt PIN-númer SIM-korts. Þú þarft núna að hafa samband við símafyrirtækið þitt til að taka tækið úr lás."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-it/strings.xml b/packages/Keyguard/res/values-it/strings.xml index 3c6d13f..ac7de84 100644 --- a/packages/Keyguard/res/values-it/strings.xml +++ b/packages/Keyguard/res/values-it/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Sblocco con password."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Area sequenza."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Area di scorrimento."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Area PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Area PIN SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Area PUK SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Pulsante traccia precedente"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Pulsante traccia successiva"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pulsante Pausa"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Rimuovi"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Codice PIN della SIM errato. Devi contattare l\'operatore per sbloccare il dispositivo."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-iw/strings.xml b/packages/Keyguard/res/values-iw/strings.xml index 66d206f..2d8f1bf 100644 --- a/packages/Keyguard/res/values-iw/strings.xml +++ b/packages/Keyguard/res/values-iw/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"אזור עבור קוד PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"אזור עבור קוד PIN של SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"אזור עבור קוד PUK של SIM"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים באופן שגוי. פרופיל העבודה יוסר וכתוצאה מכך כל נתוני הפרופיל יימחקו."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"מספר PIN שגוי של כרטיס ה-SIM. עליך ליצור כעת קשר עם הספק על מנת לבטל את נעילת המכשיר."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-ja/strings.xml b/packages/Keyguard/res/values-ja/strings.xml index cfc501d..39dc52e 100644 --- a/packages/Keyguard/res/values-ja/strings.xml +++ b/packages/Keyguard/res/values-ja/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PINエリア"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PINエリア"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUKエリア"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"携帯電話のロック解除に<xliff:g id="NUMBER">%d</xliff:g>回失敗しました。ワークプロフィールが削除され、プロフィールのデータがすべて削除されます。"</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PINコードが無効です。お使いの端末をロック解除するには携帯通信会社にお問い合わせいただく必要があります。"</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-ka-rGE/strings.xml b/packages/Keyguard/res/values-ka-rGE/strings.xml index 47f107c..ccd6bea 100644 --- a/packages/Keyguard/res/values-ka-rGE/strings.xml +++ b/packages/Keyguard/res/values-ka-rGE/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN-ის არე"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM-ის PIN-ის არე"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM-ის PUK-ის არე"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g> ჯერ. სამუშაო პროფილი ამოიშლება, რაც წაშლის პროფილის მთლიან მონაცემს."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM-ის არასწორი PIN კოდი. თქვენ ახლა მოგიწევთ მოწყობილობის განსაბლოკად მიმართოთ ოპერატორს."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-kk-rKZ/strings.xml b/packages/Keyguard/res/values-kk-rKZ/strings.xml index d0bee1a..1663ca0 100644 --- a/packages/Keyguard/res/values-kk-rKZ/strings.xml +++ b/packages/Keyguard/res/values-kk-rKZ/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN аумағы"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN аумағы"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK аумағы"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Телефон бекітпесін ашуға <xliff:g id="NUMBER">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Жұмыс профилі жойылып, бүкіл профиль деректері жойылады."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%d</xliff:g> рет қате сыздыңыз. After <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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PIN коды дұрыс емес, құрылғыны ашу үшін қызмет жабдықтаушыға хабарласаңыз."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-km-rKH/strings.xml b/packages/Keyguard/res/values-km-rKH/strings.xml index 858c001..f4a73a8 100644 --- a/packages/Keyguard/res/values-km-rKH/strings.xml +++ b/packages/Keyguard/res/values-km-rKH/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"ប្រអប់លេខសម្ងាត់"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"ប្រអប់លេខសម្ងាត់ស៊ីម"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"ប្រអប់ PUK ស៊ីម"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើទូរស័ព្ទរបស់អ្នក <xliff:g id="NUMBER">%d</xliff:g> ដង។ ប្រវត្តិរូបការងាររបស់អ្នកនឹងត្រូវបានដកចេញ ដែលវានឹងលុបទិន្នន័យប្រវត្តិរូបទាំងអស់របស់អ្នក។"</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"អ្នកបានគូរលំនាំដោះសោមិនត្រឹមត្រូវ <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"លេខកូដ PIN ស៊ីមមិនត្រឹមត្រូវ អ្នកត្រូវទាក់ទងក្រុមហ៊ុនបញ្ជូនរបស់អ្នកឥឡូវនេះ ដើម្បីដោះសោឧបករណ៍របស់អ្នក។"</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-kn-rIN/strings.xml b/packages/Keyguard/res/values-kn-rIN/strings.xml index d76a21a..6e2b4d0 100644 --- a/packages/Keyguard/res/values-kn-rIN/strings.xml +++ b/packages/Keyguard/res/values-kn-rIN/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"ಪಿನ್ ಪ್ರದೇಶ"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"ಸಿಮ್ ಪಿನ್ ಪ್ರದೇಶ"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"ಸಿಮ್ PUK ಪ್ರದೇಶ"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ಸಿಮ್ ಪಿನ್ ಕೋಡ್ ತಪ್ಪಾಗಿದೆ, ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು ಈ ಕೂಡಲೇ ನಿಮ್ಮ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಬೇಕು."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-ko/strings.xml b/packages/Keyguard/res/values-ko/strings.xml index afeb0d1..b60b159 100644 --- a/packages/Keyguard/res/values-ko/strings.xml +++ b/packages/Keyguard/res/values-ko/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN 영역"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN 영역"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK 영역"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필이 삭제되며 모든 프로필 데이터가 삭제됩니다."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PIN 코드가 잘못되었습니다. 이동통신사에 문의하여 기기를 잠금 해제해야 합니다."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-ky-rKG/strings.xml b/packages/Keyguard/res/values-ky-rKG/strings.xml index cad3581..f90acb4 100644 --- a/packages/Keyguard/res/values-ky-rKG/strings.xml +++ b/packages/Keyguard/res/values-ky-rKG/strings.xml @@ -67,6 +67,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN аймагы"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN аймагы"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK аймагы"</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> @@ -148,7 +151,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Телефондун кулпусун ачууда <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Жумуш профили чыгарылып салынып, андагы бардык дайындар жок болот."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Сиз бөгөттөн чыгаруу үлгүсүн <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM-карта PIN-коду туура эмес. Эми түзмөктү бөгөттөн чыгарыш үчүн операторуңузга кайрылышыңыз керек."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-lo-rLA/strings.xml b/packages/Keyguard/res/values-lo-rLA/strings.xml index 2a8eb6a..40f1893 100644 --- a/packages/Keyguard/res/values-lo-rLA/strings.xml +++ b/packages/Keyguard/res/values-lo-rLA/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"ພື້ນທີ່ PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"ພື້ນທີ່ PIN ຂອງ SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"ພື້ນທີ່ PUK ຂອງ SIM"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນໂປຣໄຟລ໌."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ລະຫັດ PIN ຂອງ SIM ບໍ່ຖືກຕ້ອງທ່ານຕ້ອງຕິດຕໍ່ຫາຜູ່ໃຫ້ບໍລິການ ເພື່ອປົດລັອກອຸປະກອນຂອງທ່ານ."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-lt/strings.xml b/packages/Keyguard/res/values-lt/strings.xml index ae24992..eb9c910 100644 --- a/packages/Keyguard/res/values-lt/strings.xml +++ b/packages/Keyguard/res/values-lt/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Atrakinimas įvedus slaptažodį."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Atrakinimo pagal piešinį sritis."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Slydimo sritis."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN kodo sritis"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM kortelės PIN kodo sritis"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM kortelės PUK kodo sritis"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Ankstesnio takelio mygtukas"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Kito takelio mygtukas"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pristabdymo mygtukas"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Pašalinti"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Netinkamas SIM kortelės PIN kodas. Reikės susisiekti su operatoriumi, kad atrakintų įrenginį."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-lv/strings.xml b/packages/Keyguard/res/values-lv/strings.xml index 17492a1..920a141 100644 --- a/packages/Keyguard/res/values-lv/strings.xml +++ b/packages/Keyguard/res/values-lv/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Autorizācija ar paroli."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Kombinācijas ievades apgabals."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Apgabals, kur vilkt ar pirkstu."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN apgabals"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN apgabals"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK apgabals"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Iepriekšējā ieraksta poga"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Nākamā ieraksta poga"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pārtraukšanas poga"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem planšetdators būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Noņemt"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Nepareizs SIM kartes PIN kods. Lai atbloķētu ierīci, sazinieties ar mobilo sakaru operatoru."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-mk-rMK/strings.xml b/packages/Keyguard/res/values-mk-rMK/strings.xml index a7a782c..a94503b 100644 --- a/packages/Keyguard/res/values-mk-rMK/strings.xml +++ b/packages/Keyguard/res/values-mk-rMK/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"Поле за ПИН"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Поле за ПИН на СИМ"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Поле за ПУК на СИМ"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ПИН кодот за СИМ картичката е неточен. Контактирате со вашиот оператор да го отклучи уредот."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-ml-rIN/strings.xml b/packages/Keyguard/res/values-ml-rIN/strings.xml index 1a8edca..20c73a3 100644 --- a/packages/Keyguard/res/values-ml-rIN/strings.xml +++ b/packages/Keyguard/res/values-ml-rIN/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN ഏരിയ"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN ഏരിയ"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK ഏരിയ"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"നിങ്ങളുടെ ഫോൺ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യുന്നതിനാൽ എല്ലാ പ്രൊഫൈൽ വിവരങ്ങളും ഇല്ലാതാക്കും."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"സിം പിൻ കോഡ് തെറ്റാണ്, നിങ്ങളുടെ ഉപകരണം അൺലോക്കുചെയ്യാൻ ഇപ്പോൾ നിങ്ങളുടെ കാരിയറുമായി ബന്ധപ്പെടണം."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-mn-rMN/strings.xml b/packages/Keyguard/res/values-mn-rMN/strings.xml index 708d8ea..f2d6f8c 100644 --- a/packages/Keyguard/res/values-mn-rMN/strings.xml +++ b/packages/Keyguard/res/values-mn-rMN/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN талбар"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN талбар"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK талбар"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу оруулсан байна. Ажлын профайл устгагдаж, улмаар профайлын бүх мэдээлэл устах болно."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Та тайлах хээг <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"СИМ ПИН код буруу, та төхөөрөмжийн түгжээг тайлахын тулд оператор компанитай холбоо барих шаардлагатай."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-mr-rIN/strings.xml b/packages/Keyguard/res/values-mr-rIN/strings.xml index f6f15c5..47b6ebb 100644 --- a/packages/Keyguard/res/values-mr-rIN/strings.xml +++ b/packages/Keyguard/res/values-mr-rIN/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"पिन क्षेत्र"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"सिम पिन क्षेत्र"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"सिम PUK क्षेत्र"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"आपण फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाईल काढले जाईल, जे सर्व प्रोफाईल डेटा हटवेल."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपण आपला अनलॉक नमुना <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"सिम पिन कोड चुकीचा आहे आपण आता आपले डिव्हाइस अनलॉक करण्यासाठी आपल्या वाहकाशी संपर्क साधावा."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-ms-rMY/strings.xml b/packages/Keyguard/res/values-ms-rMY/strings.xml index c46c73c..8f46081 100644 --- a/packages/Keyguard/res/values-ms-rMY/strings.xml +++ b/packages/Keyguard/res/values-ms-rMY/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"Kawasan PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Kawasan PIN SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Kawasan PUK SIM"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadam semua data profil."</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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Kod PIN SIM tidak betul, jadi anda harus menghubungi pembawa anda untuk membuka kunci peranti."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-my-rMM/strings.xml b/packages/Keyguard/res/values-my-rMM/strings.xml index dd15517..a7ba0e5 100644 --- a/packages/Keyguard/res/values-my-rMM/strings.xml +++ b/packages/Keyguard/res/values-my-rMM/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN နေရာ"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN နေရာ"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK နေရာ"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ အလုပ်ပရိုဖိုင် ဖယ်ထုတ်ခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"သင် ပုံဖော်၍သော့ဖွင့်ခြင်းကို <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ဆင်းကဒ် လျှို့ဝှက် အမှတ် မှားယွင်းပါသည်, ဖုန်းလိုင်းဌာနကို ဆက်သွယ်ရမည် ဖြစ်ပါတယ်"</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-nb/strings.xml b/packages/Keyguard/res/values-nb/strings.xml index e300053..0f7fa66 100644 --- a/packages/Keyguard/res/values-nb/strings.xml +++ b/packages/Keyguard/res/values-nb/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Passordopplåsning."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Mønsterområde."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Dra-felt."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN-området"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"PIN-området for SIM-kortet"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"PUK-området for SIM-kortet"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Forrige spor-knapp"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Neste spor-knapp"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pause-knapp"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Arbeidsprofilen blir fjernet, og alle profildata blir slettet."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp nettbrettet via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Feil PIN-kode for SIM-kortet. Du må nå kontakte operatøren din for å låse opp enheten."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-ne-rNP/strings.xml b/packages/Keyguard/res/values-ne-rNP/strings.xml index e16d1fb..00b9ece 100644 --- a/packages/Keyguard/res/values-ne-rNP/strings.xml +++ b/packages/Keyguard/res/values-ne-rNP/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"पीन क्षेत्र"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM पिन क्षेत्र"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM पुक क्षेत्र"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER">%d</xliff:g> पटक। काम प्रोफाइल हटाइनेछ जसले सम्पूर्ण प्रोफाइल डेटा मेट्नेछ।"</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"तपाईंले गलत तरिकाले आफ्नो अनलक ढाँचा <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PIN कोड गलत छ। अब तपाईंले अाफ्नो उपकरण खोल्नलाई तपाईंको वाहकसँग सम्पर्क गर्नै पर्दर।"</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-nl/strings.xml b/packages/Keyguard/res/values-nl/strings.xml index 75ed684..518a1e1 100644 --- a/packages/Keyguard/res/values-nl/strings.xml +++ b/packages/Keyguard/res/values-nl/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Ontgrendeling via wachtwoord."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Tekengebied voor patroon."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Schuifgebied."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Gebied voor pincode"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Gebied voor sim-pincode"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Gebied voor sim-pukcode"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Knop voor vorig nummer"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Knop voor volgend nummer"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Knop voor onderbreken"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"U heeft <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Verwijderen"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Onjuiste pincode voor simkaart. U moet nu contact opnemen met uw provider om uw apparaat te ontgrendelen."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-pl/strings.xml b/packages/Keyguard/res/values-pl/strings.xml index c5721b4..623c8ca 100644 --- a/packages/Keyguard/res/values-pl/strings.xml +++ b/packages/Keyguard/res/values-pl/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Odblokowanie hasłem."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Obszar wzoru."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Obszar przesuwania."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Miejsce na PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Miejsce na PIN do karty SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Miejsce na PUK do karty SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Przycisk poprzedniego utworu"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Przycisk następnego utworu"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Przycisk wstrzymania"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować telefon. Profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Usuń"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Nieprawidłowy kod PIN karty SIM. Musisz teraz skontaktować się z operatorem, by odblokował Twoje urządzenie."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-pt-rPT/strings.xml b/packages/Keyguard/res/values-pt-rPT/strings.xml index c3c4a9a..0556812 100644 --- a/packages/Keyguard/res/values-pt-rPT/strings.xml +++ b/packages/Keyguard/res/values-pt-rPT/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueio através de palavra-passe."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Área da sequência."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Área de deslize."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Área do PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Área do PIN do SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Área do PUK do SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botão Faixa anterior"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botão Faixa seguinte"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botão Pausa"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do perfil."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" - "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remover"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Código PIN do cartão SIM incorreto. Tem de contactar o seu operador para desbloquear o dispositivo."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-pt/strings.xml b/packages/Keyguard/res/values-pt/strings.xml index c3cd2eb..154eaa7 100644 --- a/packages/Keyguard/res/values-pt/strings.xml +++ b/packages/Keyguard/res/values-pt/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueio com senha."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Área do padrão."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Área de deslize."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Área do PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Área do PIN SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Área do PUK SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botão \"Faixa anterior\""</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botão \"Próxima faixa\""</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botão \"Pausar\""</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remover"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Código PIN do SIM incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-ro/strings.xml b/packages/Keyguard/res/values-ro/strings.xml index 4c8fe6f..dd3fe2f 100644 --- a/packages/Keyguard/res/values-ro/strings.xml +++ b/packages/Keyguard/res/values-ro/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Deblocare cu parolă."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Zonă model."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Zonă glisare."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Zona codului PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Zona codului PIN al cardului SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Zona codului PUK al cardului SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Butonul Melodia anterioară"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Butonul Melodia următoare"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Butonul Întrerupeți"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul unui cont de e-mail.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul unui cont de e-mail.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminaţi"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Codul PIN pentru cardul SIM este incorect. Contactați operatorul pentru a vă debloca dispozitivul."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-ru/strings.xml b/packages/Keyguard/res/values-ru/strings.xml index 91e3eb3..1edfba5 100644 --- a/packages/Keyguard/res/values-ru/strings.xml +++ b/packages/Keyguard/res/values-ru/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN-код"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"PIN-код SIM-карты"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"PUK-код SIM-карты"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Достигнуто максимальное количество неудачных попыток разблокировать телефон (<xliff:g id="NUMBER">%d</xliff:g>). Рабочий профиль и все его данные будут удалены."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы <xliff:g id="NUMBER_0">%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="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> неверных попыток для разблокировки телефона потребуется войти в аккаунт Google.\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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Неверный PIN-код. Обратитесь к оператору связи, чтобы разблокировать SIM-карту."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-si-rLK/strings.xml b/packages/Keyguard/res/values-si-rLK/strings.xml index 95ad701..6527874 100644 --- a/packages/Keyguard/res/values-si-rLK/strings.xml +++ b/packages/Keyguard/res/values-si-rLK/strings.xml @@ -68,6 +68,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN කොටස"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN කොටස"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK කොටස"</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> @@ -146,7 +149,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. සියලුම පැතිකඩ දත්ත මකා දමමින්, කාර්යාල පැතිකඩ මකා දැමෙනු ඇත."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ඔබ අගුළු ඇරිමේ රටාව <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"වැරදී SIM PIN කේතයකි, ඔබගේ දුරකතනයේ අඟුල හැරීමට ඔබගේ වාහකයා ඔබ දැන් සම්බන්ධ කරගත යුතුය."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-sk/strings.xml b/packages/Keyguard/res/values-sk/strings.xml index bd925db..c8c05f2 100644 --- a/packages/Keyguard/res/values-sk/strings.xml +++ b/packages/Keyguard/res/values-sk/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Odomknutie heslom."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Oblasť na zadanie bezpečnostného vzoru."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Oblasť na prejdenie prstom."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Oblasť kódu PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Oblasť kódu PIN SIM karty"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Oblasť kódu PUK SIM karty"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Tlačidlo Predchádzajúca stopa"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Tlačidlo Ďalšia stopa"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Tlačidlo Pozastaviť"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších <xliff:g id="NUMBER_1">%d</xliff:g> neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odstrániť"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Nesprávny kód PIN karty SIM. Teraz musíte kontaktovať svojho operátora, aby vám odomkol zariadenie."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-sl/strings.xml b/packages/Keyguard/res/values-sl/strings.xml index 0de2893..81acafb 100644 --- a/packages/Keyguard/res/values-sl/strings.xml +++ b/packages/Keyguard/res/values-sl/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Odklepanje z geslom."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Območje vzorca."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Območje podrsanja."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Območje za kodo PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Območje za kodo PIN za SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Območje za kodo PUK za SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Gumb za prejšnjo skladbo"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Gumb za naslednjo skladbo"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Gumb za začasno ustavitev"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen, zaradi česar bodo izbrisani vsi podatki profila."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odstrani"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Napačna koda PIN kartice SIM. Zdaj se boste morali za odklenitev naprave obrniti na operaterja."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml index a049432..d7ae794 100644 --- a/packages/Keyguard/res/values-sr/strings.xml +++ b/packages/Keyguard/res/values-sr/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"Област за PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Област за PIN за SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Област за PUK за SIM"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пут(а). Пословни профил ће бити уклоњен и сви подаци са њега ће бити избрисани."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Нетачан SIM PIN кôд. Сада морате да контактирате мобилног оператера да бисте откључали уређај."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-sv/strings.xml b/packages/Keyguard/res/values-sv/strings.xml index 064eee0..a86b489 100644 --- a/packages/Keyguard/res/values-sv/strings.xml +++ b/packages/Keyguard/res/values-sv/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Lås upp med lösenord."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Fält för grafiskt lösenord."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Fält med dragreglage."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Pinkodsområde"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Pinkodsområde för SIM-kort"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"PUK-kodsområde för SIM-kort"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Knapp för föregående spår"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Knapp för nästa spår"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pausknappen"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp surfplattan med ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp mobilen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ta bort"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Du angav fel pinkod för SIM-kortet och måste nu kontakta operatören för att låsa upp enheten."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-sw/strings.xml b/packages/Keyguard/res/values-sw/strings.xml index 3f4002e..2e67ff7 100644 --- a/packages/Keyguard/res/values-sw/strings.xml +++ b/packages/Keyguard/res/values-sw/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Kufungua kwa nenosiri."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Eneo la ruwaza."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Eneo la slaidi."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Eneo la PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Eneo la PIN ya SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Eneo la PUK ya SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Kitufe cha wimbo uliotangulia"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Kitufe cha wimbo unaofuata"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Kitufe cha kusitisha"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g>. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> bila kufaulu, utaombwa kufungua kompyuta yako ndogo kwa kutumia akaunti yako ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> yasiyofaulu, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <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">"Ondoa"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Msimbo wa PIN ya SIM usiosahihi sasa lazima uwasiliane na mtoa huduma wako ili ufungue kifaa chako."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-ta-rIN/strings.xml b/packages/Keyguard/res/values-ta-rIN/strings.xml index cd24dfc..19a02b9 100644 --- a/packages/Keyguard/res/values-ta-rIN/strings.xml +++ b/packages/Keyguard/res/values-ta-rIN/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN பகுதி"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"சிம் PIN பகுதி"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"சிம் PUK பகுதி"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"மொபைலைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். பணி சுயவிவரம் அகற்றப்படும், அத்துடன் சுயவிவரத்தின் எல்லா தரவும் நீக்கப்படும்."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"சிம் பின் குறியீடு தவறானது, உங்கள் சாதனத்தின் தடையை நீக்க, உங்கள் மொபைல் நிறுவனத்தைத் தொடர்புகொள்ள வேண்டும்."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-te-rIN/strings.xml b/packages/Keyguard/res/values-te-rIN/strings.xml index 5e65cb1..30173b0 100644 --- a/packages/Keyguard/res/values-te-rIN/strings.xml +++ b/packages/Keyguard/res/values-te-rIN/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN ప్రాంతం"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN ప్రాంతం"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK ప్రాంతం"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, ఇందువల్ల మొత్తం ప్రొఫైల్ డేటా తొలగించబడుతుంది."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"సిమ్ పిన్ కోడ్ చెల్లదు, మీరు ఇప్పుడు మీ పరికరాన్ని అన్లాక్ చేయడానికి తప్పనిసరిగా మీ క్యారియర్ను సంప్రదించండి."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-th/strings.xml b/packages/Keyguard/res/values-th/strings.xml index f83503f..1d7bc66 100644 --- a/packages/Keyguard/res/values-th/strings.xml +++ b/packages/Keyguard/res/values-th/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"พื้นที่ PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"พื้นที่ PIN ของซิม"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"พื้นที่ PUK ของซิม"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"รหัส PIN ของซิมไม่ถูกต้อง ตอนนี้คุณต้องติดต่อผู้ให้บริการเพื่อปลดล็อกอุปกรณ์ของคุณ"</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-tl/strings.xml b/packages/Keyguard/res/values-tl/strings.xml index 7f90ba0..fb03d07 100644 --- a/packages/Keyguard/res/values-tl/strings.xml +++ b/packages/Keyguard/res/values-tl/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Pag-unlock ng password."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Bahagi ng pattern."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Bahagi ng slide."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Lugar ng PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Lugar ng PIN ng SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Lugar ng PUK ng SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Button na Nakaraang track"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Button na Susunod na track"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Button na I-pause"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alisin"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Maling PIN code ng SIM, dapat ka nang makipag-ugnay sa iyong carrier upang i-unlock ang iyong device."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-tr/strings.xml b/packages/Keyguard/res/values-tr/strings.xml index e2c5bfa..3bc4860 100644 --- a/packages/Keyguard/res/values-tr/strings.xml +++ b/packages/Keyguard/res/values-tr/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Şifreyle kilit açma."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Desen alanı."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Kaydırma alanı."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN alanı"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN alanı"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK alanı"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Önceki parça düğmesi"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Sonraki parça düğmesi"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Duraklat düğmesi"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra, tabletinizi bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Kaldır"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Yanlış SIM PIN kodu. Cihazınızın kilidini açmak için artık operatörünüzle bağlantı kurmanız gerekiyor."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-uk/strings.xml b/packages/Keyguard/res/values-uk/strings.xml index f6ac5cc..b46ad1a 100644 --- a/packages/Keyguard/res/values-uk/strings.xml +++ b/packages/Keyguard/res/values-uk/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"Область PIN-коду"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Область PIN-коду SIM-карти"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Область PUK-коду SIM-карти"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Неправильний PIN-код SIM-карти. Зв’яжіться зі своїм оператором, щоб розблокувати пристрій."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-ur-rPK/strings.xml b/packages/Keyguard/res/values-ur-rPK/strings.xml index e9925b3..f4e4eeb 100644 --- a/packages/Keyguard/res/values-ur-rPK/strings.xml +++ b/packages/Keyguard/res/values-ur-rPK/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN کا علاقہ"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN کا علاقہ"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK کا علاقہ"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"غلط SIM PIN کوڈ اب آپ کو اپنا آلہ غیر مقفل کرنے کیلئے لازمی طور پر اپنے کیریئر سے رابطہ کرنا چاہئے۔"</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-uz-rUZ/strings.xml b/packages/Keyguard/res/values-uz-rUZ/strings.xml index 11b98a0..cc891b2 100644 --- a/packages/Keyguard/res/values-uz-rUZ/strings.xml +++ b/packages/Keyguard/res/values-uz-rUZ/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Parolli qulfni ochish."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Chizmali qulf maydoni."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Maydonni silang"</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN kod maydoni"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM karta PIN kodi maydoni"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM karta PUK kodi maydoni"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Avvalgi qo‘shiq tugmasi"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Keyingi qo‘shiq tugmasi"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pauza tugmasi"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ishchi profil o‘chirib tashlanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Chizmali parolni <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri chizdingiz. <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, planshet qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Chizmali parolni <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri chizdingiz. <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"O‘chirish"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM karta PIN kodi noto‘g‘ri. Qurilma qulfini ochish uchun aloqa operatoringiz bilan bog‘laning."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-vi/strings.xml b/packages/Keyguard/res/values-vi/strings.xml index ec8ff16..0190f1c 100644 --- a/packages/Keyguard/res/values-vi/strings.xml +++ b/packages/Keyguard/res/values-vi/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Mở khóa bằng mật khẩu."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Khu vực hình."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Khu vực trượt."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Khu vực mã PIN"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Khu vực mã PIN của SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Khu vực PUK của SIM"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Nút bản nhạc trước"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Nút bản nhạc tiếp theo"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Nút tạm dừng"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Xóa"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Mã PIN của SIM không chính xác, bây giờ bạn phải liên hệ với nhà cung cấp dịch vụ để mở khóa thiết bị của bạn."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml index a8c0857..449cc1e 100644 --- a/packages/Keyguard/res/values-zh-rCN/strings.xml +++ b/packages/Keyguard/res/values-zh-rCN/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN 码区域"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM 卡 PIN 码区域"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM 卡 PUK 码区域"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"您已经 <xliff:g id="NUMBER">%d</xliff:g> 次错误地尝试解锁手机。系统将移除此工作资料,这会删除所有的工作资料数据。"</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已经 <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM卡PIN码不正确,您现在必须联系运营商为您解锁设备。"</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-zh-rHK/strings.xml b/packages/Keyguard/res/values-zh-rHK/strings.xml index 9051a7b..be19441 100644 --- a/packages/Keyguard/res/values-zh-rHK/strings.xml +++ b/packages/Keyguard/res/values-zh-rHK/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN 區域"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN 區域"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK 區域"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"您已 <xliff:g id="NUMBER">%d</xliff:g> 次錯誤解鎖手機。該工作設定檔將被移除,所有設定檔資料將因此被刪除。"</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PIN 碼不正確,您現在必須聯絡流動網絡供應商為您的裝置解鎖。"</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-zh-rTW/strings.xml b/packages/Keyguard/res/values-zh-rTW/strings.xml index cff24c9..82ef9d1 100644 --- a/packages/Keyguard/res/values-zh-rTW/strings.xml +++ b/packages/Keyguard/res/values-zh-rTW/strings.xml @@ -66,6 +66,9 @@ <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_pin_area" msgid="7903959476607833485">"PIN 區"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM 卡 PIN 區"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM 卡 PUK 區"</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> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。您的 Work 設定檔將遭到移除,所有設定檔資料也會一併遭到刪除。"</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="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM 卡的 PIN 碼輸入錯誤,您現在必須請行動通訊業者為裝置解鎖。"</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/res/values-zu/strings.xml b/packages/Keyguard/res/values-zu/strings.xml index c0f4e39..f8c8f53 100644 --- a/packages/Keyguard/res/values-zu/strings.xml +++ b/packages/Keyguard/res/values-zu/strings.xml @@ -66,6 +66,9 @@ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Ukuvula ngephasiwedi."</string> <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Indawo yephethini."</string> <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Indawo yokushelelisa."</string> + <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Indawo yephinikhodi"</string> + <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Indawo yephinikhodi ye-SIM"</string> + <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Indawo ye-SIM PUK"</string> <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Inkinombo yethrekhi yangaphambilini"</string> <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Inkinobho yethrekhi elandelayo"</string> <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Inkinobho yokumiswa isikhashana"</string> @@ -144,7 +147,6 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Udwebe ngokungalungile iphathini yakho yokuvula izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Emva <xliff:g id="NUMBER_1">%d</xliff:g> kweminye imizamo engaphumelelanga, uzocelwa ukuvula ithebhulethi yakho usebenzisa ukungena ngemvume kwi-Google.\n\n Sicela uzame futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_2">%d</xliff:g>"</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%d</xliff:g> amasekhondi."</string> - <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Susa"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Ikhodi yephinikhodi ye-SIM engalungile manje kumele uxhumane nenkampini yenethiwekhi yakho ukuvula idivayisi yakho."</string> <plurals name="kg_password_wrong_pin_code"> diff --git a/packages/Keyguard/src/com/android/keyguard/CarrierText.java b/packages/Keyguard/src/com/android/keyguard/CarrierText.java index 7f4ce59..d8b0c71 100644 --- a/packages/Keyguard/src/com/android/keyguard/CarrierText.java +++ b/packages/Keyguard/src/com/android/keyguard/CarrierText.java @@ -21,6 +21,7 @@ import java.util.Locale; import android.content.Context; import android.content.res.TypedArray; +import android.net.ConnectivityManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.text.TextUtils; @@ -140,14 +141,23 @@ public class CarrierText extends TextView { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); - mKeyguardUpdateMonitor.registerCallback(mCallback); + if (ConnectivityManager.from(mContext).isNetworkSupported( + ConnectivityManager.TYPE_MOBILE)) { + mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); + mKeyguardUpdateMonitor.registerCallback(mCallback); + } else { + // Don't listen and clear out the text when the device isn't a phone. + mKeyguardUpdateMonitor = null; + setText(""); + } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - mKeyguardUpdateMonitor.removeCallback(mCallback); + if (mKeyguardUpdateMonitor != null) { + mKeyguardUpdateMonitor.removeCallback(mCallback); + } } /** diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java index bca0305..7c56e84 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -17,7 +17,11 @@ package com.android.keyguard; import android.content.Context; +import android.database.ContentObserver; import android.graphics.Rect; +import android.os.Handler; +import android.os.UserHandle; +import android.provider.Settings; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.View; @@ -28,19 +32,39 @@ import android.view.View; public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView implements View.OnKeyListener { + private final android.database.ContentObserver mSpeakPasswordObserver + = new ContentObserver(new Handler()) { + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + // Ensure that it's not called too early + if (mButton0 != null) { + mButton0.updateContentDescription(); + mButton1.updateContentDescription(); + mButton2.updateContentDescription(); + mButton3.updateContentDescription(); + mButton4.updateContentDescription(); + mButton5.updateContentDescription(); + mButton6.updateContentDescription(); + mButton7.updateContentDescription(); + mButton8.updateContentDescription(); + mButton9.updateContentDescription(); + } + } + }; protected PasswordTextView mPasswordEntry; private View mOkButton; private View mDeleteButton; - private View mButton0; - private View mButton1; - private View mButton2; - private View mButton3; - private View mButton4; - private View mButton5; - private View mButton6; - private View mButton7; - private View mButton8; - private View mButton9; + private NumPadKey mButton0; + private NumPadKey mButton1; + private NumPadKey mButton2; + private NumPadKey mButton3; + private NumPadKey mButton4; + private NumPadKey mButton5; + private NumPadKey mButton6; + private NumPadKey mButton7; + private NumPadKey mButton8; + private NumPadKey mButton9; public KeyguardPinBasedInputView(Context context) { this(context, null); @@ -48,6 +72,9 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView public KeyguardPinBasedInputView(Context context, AttributeSet attrs) { super(context, attrs); + context.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD), true, + mSpeakPasswordObserver, UserHandle.USER_ALL); } @Override @@ -188,16 +215,16 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView } }); - mButton0 = findViewById(R.id.key0); - mButton1 = findViewById(R.id.key1); - mButton2 = findViewById(R.id.key2); - mButton3 = findViewById(R.id.key3); - mButton4 = findViewById(R.id.key4); - mButton5 = findViewById(R.id.key5); - mButton6 = findViewById(R.id.key6); - mButton7 = findViewById(R.id.key7); - mButton8 = findViewById(R.id.key8); - mButton9 = findViewById(R.id.key9); + mButton0 = (NumPadKey) findViewById(R.id.key0); + mButton1 = (NumPadKey) findViewById(R.id.key1); + mButton2 = (NumPadKey) findViewById(R.id.key2); + mButton3 = (NumPadKey) findViewById(R.id.key3); + mButton4 = (NumPadKey) findViewById(R.id.key4); + mButton5 = (NumPadKey) findViewById(R.id.key5); + mButton6 = (NumPadKey) findViewById(R.id.key6); + mButton7 = (NumPadKey) findViewById(R.id.key7); + mButton8 = (NumPadKey) findViewById(R.id.key8); + mButton9 = (NumPadKey) findViewById(R.id.key9); mPasswordEntry.requestFocus(); super.onFinishInflate(); diff --git a/packages/Keyguard/src/com/android/keyguard/NumPadKey.java b/packages/Keyguard/src/com/android/keyguard/NumPadKey.java index d539856..70a4108 100644 --- a/packages/Keyguard/src/com/android/keyguard/NumPadKey.java +++ b/packages/Keyguard/src/com/android/keyguard/NumPadKey.java @@ -22,6 +22,8 @@ import android.graphics.drawable.Drawable; import android.os.Debug; import android.os.PowerManager; import android.os.SystemClock; +import android.os.UserHandle; +import android.provider.Settings; import android.util.AttributeSet; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; @@ -118,7 +120,17 @@ public class NumPadKey extends ViewGroup { } setBackground(mContext.getDrawable(R.drawable.ripple_drawable)); - setContentDescription(mDigitText.getText().toString() + mKlondikeText.getText().toString()); + updateContentDescription(); + } + + public void updateContentDescription() { + if (shouldSpeakPasswordsForAccessibility()) { + setContentDescription( + mDigitText.getText().toString() + mKlondikeText.getText().toString()); + } else { + setContentDescription(getContext().getString( + com.android.internal.R.string.keyboard_password_character_no_headset)); + } } @Override @@ -152,6 +164,15 @@ public class NumPadKey extends ViewGroup { mKlondikeText.layout(left, top, left + mKlondikeText.getMeasuredWidth(), bottom); } + /** + * @return true if the user has explicitly allowed accessibility services + * to speak passwords. + */ + private boolean shouldSpeakPasswordsForAccessibility() { + return (Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0, UserHandle.USER_CURRENT) == 1); + } + @Override public boolean hasOverlappingRendering() { return false; diff --git a/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml b/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml new file mode 100644 index 0000000..2ac223b --- /dev/null +++ b/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="72.0" + android:viewportHeight="72.0"> + <group + android:translateX="52.0" + android:translateY="42.0" > + <path + android:fillColor="#FFFFFFFF" + android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.76 -2.24,-5.0 -5.0,-5.0S7.0,3.24 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.0 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-6.0,9.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0 2.0,0.9 2.0,2.0 -0.9,2.0 -2.0,2.0zm3.1,-9.0L8.9,8.0L8.9,6.0c0.0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0.0 3.1,1.39 3.1,3.1l0.0,2.0z"/> + </group> +</vector> diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index ca07c87..4cf4f52d 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -29,6 +29,7 @@ android:layout_height="wrap_content" android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom" android:layout_gravity="bottom|center_horizontal" + android:gravity="center_horizontal" android:textStyle="italic" android:textColor="#ffffff" android:textAppearance="?android:attr/textAppearanceSmall" /> diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml index 922f90d..27353ff 100644 --- a/packages/SystemUI/res/layout/zen_mode_panel.xml +++ b/packages/SystemUI/res/layout/zen_mode_panel.xml @@ -23,6 +23,7 @@ android:orientation="vertical" > <FrameLayout + android:id="@+id/zen_buttons_container" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="8dp" diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 1153369..4a05367 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -318,7 +318,7 @@ <string name="guest_wipe_session_message" msgid="8476238178270112811">"¿Quieres continuar con la sesión?"</string> <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"Volver a empezar"</string> <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"Sí, continuar"</string> - <string name="user_add_user_title" msgid="4553596395824132638">"¿Añadir usuario nuevo?"</string> + <string name="user_add_user_title" msgid="4553596395824132638">"¿Añadir nuevo usuario?"</string> <string name="user_add_user_message_short" msgid="2161624834066214559">"Al añadir un usuario nuevo, este debe configurar su espacio.\n\nCualquier usuario puede actualizar las aplicaciones del resto de usuarios."</string> <string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string> <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y el envío de datos en segundo plano"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 9bfb405..fb8b0d78 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -109,11 +109,11 @@ <string name="accessibility_data_three_bars" msgid="9167670452395038520">"Datasignaali - kolme palkkia"</string> <string name="accessibility_data_signal_full" msgid="2708384608124519369">"Vahva kuuluvuus."</string> <string name="accessibility_wifi_off" msgid="3177380296697933627">"Wi-Fi pois käytöstä."</string> - <string name="accessibility_no_wifi" msgid="1425476551827924474">"Ei wifi-yhteyttä."</string> + <string name="accessibility_no_wifi" msgid="1425476551827924474">"Ei Wi-Fi-yhteyttä."</string> <string name="accessibility_wifi_one_bar" msgid="7735893178010724377">"Wi-Fi-signaali – yksi palkki."</string> <string name="accessibility_wifi_two_bars" msgid="4994274250497262434">"Wi-Fi-signaali – kaksi palkkia."</string> <string name="accessibility_wifi_three_bars" msgid="3495755044276588384">"Wi-Fi-signaali – kolme palkkia."</string> - <string name="accessibility_wifi_signal_full" msgid="6853561303586480376">"Vahva wifi-signaali."</string> + <string name="accessibility_wifi_signal_full" msgid="6853561303586480376">"Vahva Wi-Fi-signaali."</string> <string name="accessibility_wifi_name" msgid="7202151365171148501">"Yhteys: <xliff:g id="WIFI">%s</xliff:g>."</string> <string name="accessibility_bluetooth_name" msgid="8441517146585531676">"Yhteys: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> <string name="accessibility_no_wimax" msgid="4329180129727630368">"Ei WiMAX-yhteyttä."</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 90b62bf..d581e73 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -318,8 +318,8 @@ <string name="guest_exit_guest_dialog_remove" msgid="7402231963862520531">"削除"</string> <string name="guest_wipe_session_title" msgid="6419439912885956132">"おかえりなさい、ゲストさん"</string> <string name="guest_wipe_session_message" msgid="8476238178270112811">"セッションを続行しますか?"</string> - <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"最初から再生"</string> - <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"次へ進む"</string> + <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"最初から開始"</string> + <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"続行"</string> <string name="user_add_user_title" msgid="4553596395824132638">"新しいユーザーを追加しますか?"</string> <string name="user_add_user_message_short" msgid="2161624834066214559">"新しいユーザーを追加したら、そのユーザーは自分のスペースをセットアップする必要があります。\n\nすべてのユーザーは他のユーザーに代わってアプリを更新できます。"</string> <string name="battery_saver_notification_title" msgid="237918726750955859">"バッテリーセーバーがON"</string> diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml index f17a524..9808830 100644 --- a/packages/SystemUI/res/values-lo-rLA/strings.xml +++ b/packages/SystemUI/res/values-lo-rLA/strings.xml @@ -355,8 +355,8 @@ <string name="hidden_notifications_setup" msgid="41079514801976810">"ຕັ້ງຄ່າ"</string> <string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"ປັກໝຸດໜ້າຈໍແລ້ວ"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"ມັນຈະຮັກສາໜ້າຈໍໄວ້ໃນມຸມມອງຂອງທ່ານຈົນກວ່າທ່ານຈະຖອດໝຸດ. ສຳຜັດປຸ່ມ ກັບຄືນ ແລະ ພາບຮວມ ຄ້າງໄວ້ພ້ອມກັນເພື່ອຖອດໝຸດ."</string> - <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ມັນຈະຮັກສາໜ້າຈໍໄວ້ໃນມຸມມອງຂອງທ່ານຈົນກວ່າທ່ານຈະຖອດໝຸດ. ສຳຜັດປຸ່ມ ພາບຮວມ ຄ້າງໄວ້ເພື່ອຖອດໝຸດ."</string> + <string name="screen_pinning_description" msgid="1346522416878235405">"ມັນຈະຮັກສາໜ້າຈໍໄວ້ໃນມຸມມອງຂອງທ່ານຈົນກວ່າທ່ານຈະຖອດໝຸດ. ແຕະປຸ່ມ ກັບຄືນ ແລະ ພາບຮວມ ຄ້າງໄວ້ພ້ອມກັນເພື່ອຖອດໝຸດ."</string> + <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ມັນຈະຮັກສາໜ້າຈໍໄວ້ໃນມຸມມອງຂອງທ່ານຈົນກວ່າທ່ານຈະຖອດໝຸດ. ແຕະປຸ່ມ ພາບຮວມ ຄ້າງໄວ້ເພື່ອຖອດໝຸດ."</string> <string name="screen_pinning_positive" msgid="3783985798366751226">"ເຂົ້າໃຈແລ້ວ"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"ບໍ່, ຂອບໃຈ"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ເຊື່ອງ <xliff:g id="TILE_LABEL">%1$s</xliff:g> ຫຼືບໍ່?"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 4e19700..060b1c5 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -319,7 +319,7 @@ <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"Opnieuw starten"</string> <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"Ja, doorgaan"</string> <string name="user_add_user_title" msgid="4553596395824132638">"Nieuwe gebruiker toevoegen?"</string> - <string name="user_add_user_message_short" msgid="2161624834066214559">"Wanneer u een nieuwe gebruiker toevoegt, moet die persoon zijn eigen profiel instellen.\n\n1Elke gebruiker kan apps bijwerken voor alle andere gebruikers."</string> + <string name="user_add_user_message_short" msgid="2161624834066214559">"Wanneer u een nieuwe gebruiker toevoegt, moet die persoon zijn eigen profiel instellen.\n\n1Elke gebruiker kan apps updaten voor alle andere gebruikers."</string> <string name="battery_saver_notification_title" msgid="237918726750955859">"Accubesparing is ingeschakeld"</string> <string name="battery_saver_notification_text" msgid="820318788126672692">"Vermindert de prestaties en achtergrondgegevens"</string> <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Accubesparing uitschakelen"</string> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 98f03b5..4d76f38 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -287,8 +287,8 @@ <!-- Number of times to show the strong alarm warning text in the volume dialog --> <integer name="zen_mode_alarm_warning_threshold">5</integer> - <!-- Maximum number of optional conditions to display in the zen mode selection panel --> - <integer name="zen_mode_max_conditions">3</integer> + <!-- Maximum number of total conditions to display in the zen mode selection panel --> + <integer name="zen_mode_max_conditions">5</integer> <!-- Enable the default volume dialog --> <bool name="enable_volume_ui">true</bool> diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java index ce0d5f4..a311d6e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java @@ -18,13 +18,13 @@ package com.android.systemui.qs; import android.content.Context; import android.content.res.Configuration; +import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; -import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -162,6 +162,12 @@ public class QSDetailItems extends FrameLayout { view.setVisibility(mItemsVisible ? VISIBLE : INVISIBLE); final ImageView iv = (ImageView) view.findViewById(android.R.id.icon); iv.setImageResource(item.icon); + iv.getOverlay().clear(); + if (item.overlay != null) { + item.overlay.setBounds(0, 0, item.overlay.getIntrinsicWidth(), + item.overlay.getIntrinsicHeight()); + iv.getOverlay().add(item.overlay); + } final TextView title = (TextView) view.findViewById(android.R.id.title); title.setText(item.line1); final TextView summary = (TextView) view.findViewById(android.R.id.summary); @@ -213,6 +219,7 @@ public class QSDetailItems extends FrameLayout { public static class Item { public int icon; + public Drawable overlay; public String line1; public String line2; public Object tag; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 699240c..a920624 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -326,7 +326,12 @@ public class WifiTile extends QSTile<QSTile.SignalState> { item.line2 = mContext.getString(ap.isConfigured ? R.string.quick_settings_connected : R.string.quick_settings_connected_via_wfa); + } else if (ap.networkId >= 0) { + // TODO: Set line 2 to wifi saved string here. } + item.overlay = ap.hasSecurity + ? mContext.getDrawable(R.drawable.qs_ic_wifi_lock) + : null; items[i] = item; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java index 4f0700e..f1bf66d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java @@ -61,15 +61,8 @@ import java.util.concurrent.atomic.AtomicBoolean; /** A proxy implementation for the recents component */ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationStartedListener { - final public static String EXTRA_FROM_HOME = "recents.triggeredOverHome"; - final public static String EXTRA_FROM_SEARCH_HOME = "recents.triggeredOverSearchHome"; - final public static String EXTRA_FROM_APP_THUMBNAIL = "recents.animatingWithThumbnail"; - final public static String EXTRA_FROM_TASK_ID = "recents.activeTaskId"; final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "recents.triggeredFromAltTab"; final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "recents.triggeredFromHomeKey"; - final public static String EXTRA_REUSE_TASK_STACK_VIEWS = "recents.reuseTaskStackViews"; - final public static String EXTRA_NUM_VISIBLE_TASKS = "recents.numVisibleTasks"; - final public static String EXTRA_NUM_VISIBLE_THUMBNAILS = "recents.numVisibleThumbnails"; final public static String ACTION_START_ENTER_ANIMATION = "action_start_enter_animation"; final public static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity"; @@ -550,7 +543,8 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack, mDummyStackView); if (opts != null) { - startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_APP_THUMBNAIL, stackVr); + startAlternateRecentsActivity(topTask, opts, false /* fromHome */, + false /* fromSearchHome */, true /* fromThumbnail */, stackVr); } else { // Fall through below to the non-thumbnail transition useThumbnailTransition = false; @@ -583,12 +577,13 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome); - startAlternateRecentsActivity(topTask, opts, - fromSearchHome ? EXTRA_FROM_SEARCH_HOME : EXTRA_FROM_HOME, stackVr); + startAlternateRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome, + false /* fromThumbnail */, stackVr); } else { // Otherwise we do the normal fade from an unknown source ActivityOptions opts = getUnknownTransitionActivityOptions(); - startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_HOME, stackVr); + startAlternateRecentsActivity(topTask, opts, true /* fromHome */, + false /* fromSearchHome */, false /* fromThumbnail */, stackVr); } } mLastToggleTime = SystemClock.elapsedRealtime(); @@ -596,21 +591,24 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta /** Starts the recents activity */ void startAlternateRecentsActivity(ActivityManager.RunningTaskInfo topTask, - ActivityOptions opts, String extraFlag, + ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail, TaskStackViewLayoutAlgorithm.VisibilityReport vr) { + // Update the configuration based on the launch options + mConfig.launchedFromHome = fromSearchHome || fromHome; + mConfig.launchedFromSearchHome = fromSearchHome; + mConfig.launchedFromAppWithThumbnail = fromThumbnail; + mConfig.launchedToTaskId = (topTask != null) ? topTask.id : -1; + mConfig.launchedWithAltTab = mTriggeredFromAltTab; + mConfig.launchedReuseTaskStackViews = mCanReuseTaskStackViews; + mConfig.launchedNumVisibleTasks = vr.numVisibleTasks; + mConfig.launchedNumVisibleThumbnails = vr.numVisibleThumbnails; + mConfig.launchedHasConfigurationChanged = false; + Intent intent = new Intent(sToggleRecentsAction); intent.setClassName(sRecentsPackage, sRecentsActivity); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_TASK_ON_HOME); - if (extraFlag != null) { - intent.putExtra(extraFlag, true); - } - intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, mTriggeredFromAltTab); - intent.putExtra(EXTRA_FROM_TASK_ID, (topTask != null) ? topTask.id : -1); - intent.putExtra(EXTRA_REUSE_TASK_STACK_VIEWS, mCanReuseTaskStackViews); - intent.putExtra(EXTRA_NUM_VISIBLE_TASKS, vr.numVisibleTasks); - intent.putExtra(EXTRA_NUM_VISIBLE_THUMBNAILS, vr.numVisibleThumbnails); if (opts != null) { mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT); } else { diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index a37bc54..6baff96 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -108,8 +108,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView @Override public void run() { - // Mark Recents as no longer visible - onRecentsActivityVisibilityChanged(false); // Finish Recents if (mLaunchIntent != null) { if (mLaunchOpts != null) { @@ -133,8 +131,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY)) { - // Mark Recents as no longer visible - AlternateRecentsComponent.notifyVisibilityChanged(false); if (intent.getBooleanExtra(AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false)) { // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app dismissRecentsToFocusedTaskOrHome(false); @@ -186,24 +182,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView /** Updates the set of recent tasks */ void updateRecentsTasks(Intent launchIntent) { - // Update the configuration based on the launch intent - boolean fromSearchHome = launchIntent.getBooleanExtra( - AlternateRecentsComponent.EXTRA_FROM_SEARCH_HOME, false); - int numVisibleTasks = launchIntent.getIntExtra( - AlternateRecentsComponent.EXTRA_NUM_VISIBLE_TASKS, 0); - int numVisibleThumbnails = launchIntent.getIntExtra( - AlternateRecentsComponent.EXTRA_NUM_VISIBLE_THUMBNAILS, 0); - mConfig.launchedFromHome = fromSearchHome || launchIntent.getBooleanExtra( - AlternateRecentsComponent.EXTRA_FROM_HOME, false); - mConfig.launchedFromAppWithThumbnail = launchIntent.getBooleanExtra( - AlternateRecentsComponent.EXTRA_FROM_APP_THUMBNAIL, false); - mConfig.launchedToTaskId = launchIntent.getIntExtra( - AlternateRecentsComponent.EXTRA_FROM_TASK_ID, -1); - mConfig.launchedWithAltTab = launchIntent.getBooleanExtra( - AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false); - mConfig.launchedReuseTaskStackViews = launchIntent.getBooleanExtra( - AlternateRecentsComponent.EXTRA_REUSE_TASK_STACK_VIEWS, false); - // If AlternateRecentsComponent has preloaded a load plan, then use that to prevent // reconstructing the task stack RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); @@ -218,8 +196,8 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options(); loadOpts.runningTaskId = mConfig.launchedToTaskId; - loadOpts.numVisibleTasks = numVisibleTasks; - loadOpts.numVisibleTaskThumbnails = numVisibleThumbnails; + loadOpts.numVisibleTasks = mConfig.launchedNumVisibleTasks; + loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails; loader.loadTasks(this, plan, loadOpts); SpaceNode root = plan.getSpaceNode(); @@ -237,9 +215,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent, ActivityOptions.makeCustomAnimation(this, - fromSearchHome ? R.anim.recents_to_search_launcher_enter : + mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter : R.anim.recents_to_launcher_enter, - fromSearchHome ? R.anim.recents_to_search_launcher_exit : + mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit : R.anim.recents_to_launcher_exit)); // Mark the task that is the launch target @@ -403,12 +381,12 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub); mDebugOverlayStub = (ViewStub) findViewById(R.id.debug_overlay_stub); mScrimViews = new SystemBarScrimViews(this, mConfig); + mStatusBar = ((SystemUIApplication) getApplication()) + .getComponent(PhoneStatusBar.class); inflateDebugOverlay(); // Bind the search app widget when we first start up bindSearchBarAppWidget(); - // Update the recent tasks - updateRecentsTasks(getIntent()); // Register the broadcast receiver to handle messages when the screen is turned off IntentFilter filter = new IntentFilter(); @@ -424,17 +402,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } catch (InvocationTargetException e) { e.printStackTrace(); } - - // Update if we are getting a configuration change - if (savedInstanceState != null) { - // Update RecentsConfiguration - mConfig.updateOnConfigurationChange(); - // Trigger the enter animation - onEnterAnimationTriggered(); - } - - mStatusBar = ((SystemUIApplication) getApplication()) - .getComponent(PhoneStatusBar.class); } /** Inflates the debug overlay if debug mode is enabled. */ @@ -449,14 +416,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } } - /** Handles changes to the activity visibility. */ - void onRecentsActivityVisibilityChanged(boolean visible) { - if (!visible) { - AlternateRecentsComponent.notifyVisibilityChanged(visible); - } - mVisible = visible; - } - @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); @@ -469,14 +428,13 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView if (mDebugOverlay != null) { mDebugOverlay.clear(); } - - // Update the recent tasks - updateRecentsTasks(intent); } @Override protected void onStart() { super.onStart(); + mVisible = true; + AlternateRecentsComponent.notifyVisibilityChanged(true); // Register the broadcast receiver to handle messages from our service IntentFilter filter = new IntentFilter(); @@ -487,19 +445,16 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Register any broadcast receivers for the task loader RecentsTaskLoader.getInstance().registerReceivers(this, mRecentsView); - } - - @Override - protected void onResume() { - super.onResume(); - // Mark Recents as visible - onRecentsActivityVisibilityChanged(true); + // Update the recent tasks + updateRecentsTasks(getIntent()); } @Override protected void onStop() { super.onStop(); + mVisible = false; + AlternateRecentsComponent.notifyVisibilityChanged(false); // Notify the views that we are no longer visible mRecentsView.onRecentsHidden(); @@ -641,8 +596,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView @Override public void onTaskViewClicked() { - // Mark recents as no longer visible - onRecentsActivityVisibilityChanged(false); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index 2b33d14..52e7e7f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -124,8 +124,12 @@ public class RecentsConfiguration { public boolean launchedWithNoRecentTasks; public boolean launchedFromAppWithThumbnail; public boolean launchedFromHome; + public boolean launchedFromSearchHome; public boolean launchedReuseTaskStackViews; + public boolean launchedHasConfigurationChanged; public int launchedToTaskId; + public int launchedNumVisibleTasks; + public int launchedNumVisibleThumbnails; /** Misc **/ public boolean useHardwareLayers; @@ -308,12 +312,10 @@ public class RecentsConfiguration { /** Called when the configuration has changed, and we want to reset any configuration specific * members. */ public void updateOnConfigurationChange() { - launchedWithAltTab = false; - launchedWithNoRecentTasks = false; - launchedFromAppWithThumbnail = false; - launchedFromHome = false; + // Reset this flag on configuration change to ensure that we recreate new task views launchedReuseTaskStackViews = false; - launchedToTaskId = -1; + // Set this flag to indicate that the configuration has changed since Recents last launched + launchedHasConfigurationChanged = true; } /** Returns whether the search bar app widget exists. */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 33a36f6..169683f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -715,14 +715,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mStartEnterAnimationContext = null; } - // When Alt-Tabbing, we scroll to and focus the previous task + // When Alt-Tabbing, focus the previous task (but leave the animation until we finish the + // enter animation). if (mConfig.launchedWithAltTab) { - if (mConfig.launchedFromHome) { - focusTask(Math.max(0, mStack.getTaskCount() - 1), false, true); + if (mConfig.launchedFromAppWithThumbnail) { + focusTask(Math.max(0, mStack.getTaskCount() - 2), false, + mConfig.launchedHasConfigurationChanged); } else { - focusTask(Math.max(0, mStack.getTaskCount() - 2), false, true); + focusTask(Math.max(0, mStack.getTaskCount() - 1), false, + mConfig.launchedHasConfigurationChanged); } } + + // Start dozing + mUIDozeTrigger.startDozing(); } /** Requests this task stacks to start it's enter-recents animation */ @@ -767,16 +773,27 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @Override public void run() { mStartEnterAnimationCompleted = true; - // Start dozing - mUIDozeTrigger.startDozing(); - // Focus the first view if accessibility is enabled + // Poke the dozer to restart the trigger after the animation completes + mUIDozeTrigger.poke(); + RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); SystemServicesProxy ssp = loader.getSystemServicesProxy(); int childCount = getChildCount(); - if (childCount > 0 && ssp.isTouchExplorationEnabled()) { - TaskView tv = ((TaskView) getChildAt(childCount - 1)); - tv.requestAccessibilityFocus(); - mPrevAccessibilityFocusedIndex = mStack.indexOfTask(tv.getTask()); + if (childCount > 0) { + // Focus the first view if accessibility is enabled + if (ssp.isTouchExplorationEnabled()) { + TaskView tv = ((TaskView) getChildAt(childCount - 1)); + tv.requestAccessibilityFocus(); + mPrevAccessibilityFocusedIndex = mStack.indexOfTask(tv.getTask()); + } + } + + // Start the focus animation when alt-tabbing + if (mConfig.launchedWithAltTab && !mConfig.launchedHasConfigurationChanged) { + View tv = getChildAt(mFocusedTaskIndex); + if (tv != null) { + ((TaskView) tv).setFocusedTask(true); + } } } }); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java index 26fbbf4..49b9129 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java @@ -135,7 +135,6 @@ public class TaskStackViewLayoutAlgorithm { // Update the task offsets float pAtBackMostCardTop = 0.5f; float pAtFrontMostCardTop = pAtBackMostCardTop; - float pAtSecondFrontMostCardTop = pAtBackMostCardTop; int taskCount = tasks.size(); for (int i = 0; i < taskCount; i++) { Task task = tasks.get(i); @@ -145,25 +144,19 @@ public class TaskStackViewLayoutAlgorithm { // Increment the peek height float pPeek = task.group.isFrontMostTask(task) ? pBetweenAffiliateOffset : pWithinAffiliateOffset; - pAtSecondFrontMostCardTop = pAtFrontMostCardTop; pAtFrontMostCardTop += pPeek; } } mMaxScrollP = pAtFrontMostCardTop - ((1f - pTaskHeightOffset - pNavBarOffset)); mMinScrollP = tasks.size() == 1 ? Math.max(mMaxScrollP, 0f) : 0f; - if (launchedWithAltTab) { - if (launchedFromHome) { - // Center the top most task, since that will be focused first - mInitialScrollP = pAtSecondFrontMostCardTop - 0.5f; - } else { - // Center the second top most task, since that will be focused first - mInitialScrollP = pAtSecondFrontMostCardTop - 0.5f; - } + if (launchedWithAltTab && launchedFromHome) { + // Center the top most task, since that will be focused first + mInitialScrollP = mMaxScrollP; } else { mInitialScrollP = pAtFrontMostCardTop - 0.825f; } - mInitialScrollP = Math.max(0, mInitialScrollP); + mInitialScrollP = Math.min(mMaxScrollP, Math.max(0, mInitialScrollP)); } /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index de5974f..faa728d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -235,7 +235,9 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask, boolean occludesLaunchTarget, int offscreenY) { int initialDim = getDim(); - if (mConfig.launchedFromAppWithThumbnail) { + if (mConfig.launchedHasConfigurationChanged) { + // Just load the views as-is + } else if (mConfig.launchedFromAppWithThumbnail) { if (isTaskViewLaunchTargetTask) { // Set the dim to 0 so we can animate it in initialDim = 0; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java index 464d007..05f6f40 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -237,15 +237,17 @@ public class TaskViewHeader extends FrameLayout { /** Animates this task bar if the user does not interact with the stack after a certain time. */ void startNoUserInteractionAnimation() { - mDismissButton.setVisibility(View.VISIBLE); - mDismissButton.setAlpha(0f); - mDismissButton.animate() - .alpha(1f) - .setStartDelay(0) - .setInterpolator(mConfig.fastOutLinearInInterpolator) - .setDuration(mConfig.taskViewEnterFromAppDuration) - .withLayer() - .start(); + if (mDismissButton.getVisibility() != View.VISIBLE) { + mDismissButton.setVisibility(View.VISIBLE); + mDismissButton.setAlpha(0f); + mDismissButton.animate() + .alpha(1f) + .setStartDelay(0) + .setInterpolator(mConfig.fastOutLinearInInterpolator) + .setDuration(mConfig.taskViewEnterFromAppDuration) + .withLayer() + .start(); + } } /** Mark this task view that the user does has not interacted with the stack after a certain time. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index 0faad21..914b3d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -124,6 +124,7 @@ public class NotificationContentView extends FrameLayout { mContractedChild = child; mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child); selectLayout(false /* animate */, true /* force */); + mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */); } public void setExpandedChild(View child) { @@ -245,6 +246,7 @@ public class NotificationContentView extends FrameLayout { public void notifyContentUpdated() { selectLayout(false /* animate */, true /* force */); if (mContractedChild != null) { + mContractedWrapper.notifyContentUpdated(); mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java index 5b6e1cd..fbcba0b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java @@ -26,6 +26,7 @@ import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; import android.view.View; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; @@ -40,17 +41,18 @@ import com.android.systemui.statusbar.phone.NotificationPanelView; */ public class NotificationTemplateViewWrapper extends NotificationViewWrapper { - private final ViewInvertHelper mInvertHelper; - private final ImageView mIcon; - protected final ImageView mPicture; private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix(); private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter( 0, PorterDuff.Mode.SRC_ATOP); private final int mIconDarkAlpha; - private final int mIconBackgroundColor; private final int mIconBackgroundDarkColor; private final Interpolator mLinearOutSlowInInterpolator; + private int mIconBackgroundColor; + private ViewInvertHelper mInvertHelper; + private ImageView mIcon; + protected ImageView mPicture; + protected NotificationTemplateViewWrapper(Context ctx, View view) { super(view); mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha); @@ -58,12 +60,16 @@ public class NotificationTemplateViewWrapper extends NotificationViewWrapper { ctx.getResources().getColor(R.color.doze_small_icon_background_color); mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in); - View mainColumn = view.findViewById(com.android.internal.R.id.notification_main_column); + resolveViews(); + } + + private void resolveViews() { + View mainColumn = mView.findViewById(com.android.internal.R.id.notification_main_column); mInvertHelper = mainColumn != null ? new ViewInvertHelper(mainColumn, NotificationPanelView.DOZE_ANIMATION_DURATION) : null; - ImageView largeIcon = (ImageView) view.findViewById(com.android.internal.R.id.icon); - ImageView rightIcon = (ImageView) view.findViewById(com.android.internal.R.id.right_icon); + ImageView largeIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon); + ImageView rightIcon = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon); mIcon = resolveIcon(largeIcon, rightIcon); mPicture = resolvePicture(largeIcon); mIconBackgroundColor = resolveBackgroundColor(mIcon); @@ -92,6 +98,14 @@ public class NotificationTemplateViewWrapper extends NotificationViewWrapper { } @Override + public void notifyContentUpdated() { + super.notifyContentUpdated(); + + // Reinspect the notification. + resolveViews(); + } + + @Override public void setDark(boolean dark, boolean fade, long delay) { if (mInvertHelper != null) { if (fade) { @@ -180,7 +194,13 @@ public class NotificationTemplateViewWrapper extends NotificationViewWrapper { private void updateIconColorFilter(ImageView target, float intensity) { int color = interpolateColor(mIconBackgroundColor, mIconBackgroundDarkColor, intensity); mIconColorFilter.setColor(color); - target.getBackground().mutate().setColorFilter(mIconColorFilter); + Drawable background = target.getBackground(); + + // The notification might have been modified during the animation, so background might be + // null here. + if (background != null) { + background.mutate().setColorFilter(mIconColorFilter); + } } private void updateIconAlpha(ImageView target, boolean dark) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java index 0a02573..78b9739 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java @@ -53,4 +53,9 @@ public abstract class NotificationViewWrapper { * @param delay if fading, the delay of the animation */ public abstract void setDark(boolean dark, boolean fade, long delay); + + /** + * Notifies this wrapper that the content of the view might have changed. + */ + public void notifyContentUpdated() {} } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index 8e50abe..8e35ee9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -277,9 +277,13 @@ public class SignalClusterView mWifiStrengthId)); boolean anyMobileVisible = false; + int firstMobileTypeId = 0; for (PhoneState state : mPhoneStates) { if (state.apply(anyMobileVisible)) { - anyMobileVisible = true; + if (!anyMobileVisible) { + firstMobileTypeId = state.mMobileTypeId; + anyMobileVisible = true; + } } } @@ -298,7 +302,7 @@ public class SignalClusterView mWifiAirplaneSpacer.setVisibility(View.GONE); } - if ((anyMobileVisible || mNoSimsVisible) && mWifiVisible) { + if (((anyMobileVisible && firstMobileTypeId != 0) || mNoSimsVisible) && mWifiVisible) { mWifiSignalSpacer.setVisibility(View.VISIBLE); } else { mWifiSignalSpacer.setVisibility(View.GONE); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 08844f3..d2dc425 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -1629,6 +1629,7 @@ public class NotificationPanelView extends PanelView implements } else { mSecureCameraLaunchManager.startSecureCameraLaunch(); } + mStatusBar.startLaunchTransitionTimeout(); mBlockTouches = true; } 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 ec2d30c..8b328aa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -203,8 +203,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000; private static final int MSG_CLOSE_PANELS = 1001; private static final int MSG_OPEN_SETTINGS_PANEL = 1002; + private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003; // 1020-1040 reserved for BaseStatusBar + // Time after we abort the launch transition. + private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000; + private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true; private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService @@ -2196,6 +2200,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, escalateHeadsUp(); setHeadsUpVisibility(false); break; + case MSG_LAUNCH_TRANSITION_TIMEOUT: + onLaunchTransitionTimeout(); + break; } } } @@ -3528,12 +3535,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mLaunchTransitionFadingAway) { mNotificationPanel.animate().cancel(); mNotificationPanel.setAlpha(1f); - if (mLaunchTransitionEndRunnable != null) { - mLaunchTransitionEndRunnable.run(); - } - mLaunchTransitionEndRunnable = null; + runLaunchTransitionEndRunnable(); mLaunchTransitionFadingAway = false; } + mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); setBarState(StatusBarState.KEYGUARD); updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */); if (!mScreenOnFromKeyguard) { @@ -3574,6 +3579,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, */ public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading, Runnable endRunnable) { + mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); mLaunchTransitionEndRunnable = endRunnable; Runnable hideRunnable = new Runnable() { @Override @@ -3592,10 +3598,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, @Override public void run() { mNotificationPanel.setAlpha(1); - if (mLaunchTransitionEndRunnable != null) { - mLaunchTransitionEndRunnable.run(); - } - mLaunchTransitionEndRunnable = null; + runLaunchTransitionEndRunnable(); mLaunchTransitionFadingAway = false; } }); @@ -3609,6 +3612,32 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } /** + * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that + * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen + * because the launched app crashed or something else went wrong. + */ + public void startLaunchTransitionTimeout() { + mHandler.sendEmptyMessageDelayed(MSG_LAUNCH_TRANSITION_TIMEOUT, + LAUNCH_TRANSITION_TIMEOUT_MS); + } + + private void onLaunchTransitionTimeout() { + Log.w(TAG, "Launch transition: Timeout!"); + mNotificationPanel.resetViews(); + } + + private void runLaunchTransitionEndRunnable() { + if (mLaunchTransitionEndRunnable != null) { + Runnable r = mLaunchTransitionEndRunnable; + + // mLaunchTransitionEndRunnable might call showKeyguard, which would execute it again, + // which would lead to infinite recursion. Protect against it. + mLaunchTransitionEndRunnable = null; + r.run(); + } + } + + /** * @return true if we would like to stay in the shade, false if it should go away entirely */ public boolean hideKeyguard() { @@ -3631,6 +3660,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mQSPanel != null) { mQSPanel.refreshAllTiles(); } + mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); return staying; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 77da70a..f4edab5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -199,7 +199,7 @@ public class StatusBarKeyguardViewManager { new Runnable() { @Override public void run() { - mStatusBarWindowManager.setKeyguardOccluded(true); + mStatusBarWindowManager.setKeyguardOccluded(mOccluded); reset(); } }); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java index 80fec5b..076cfe2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java @@ -19,15 +19,21 @@ package com.android.systemui.statusbar.policy; import static android.bluetooth.BluetoothAdapter.ERROR; import static com.android.systemui.statusbar.policy.BluetoothUtil.connectionStateToString; import static com.android.systemui.statusbar.policy.BluetoothUtil.deviceToString; -import static com.android.systemui.statusbar.policy.BluetoothUtil.profileStateToString; import static com.android.systemui.statusbar.policy.BluetoothUtil.profileToString; import static com.android.systemui.statusbar.policy.BluetoothUtil.uuidToProfile; import static com.android.systemui.statusbar.policy.BluetoothUtil.uuidToString; import static com.android.systemui.statusbar.policy.BluetoothUtil.uuidsToString; +import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothA2dpSink; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHeadset; +import android.bluetooth.BluetoothHeadsetClient; +import android.bluetooth.BluetoothInputDevice; import android.bluetooth.BluetoothManager; +import android.bluetooth.BluetoothMap; +import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile.ServiceListener; import android.content.BroadcastReceiver; @@ -38,24 +44,37 @@ import android.os.ParcelUuid; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; -import android.util.SparseBooleanArray; +import android.util.SparseArray; import com.android.systemui.statusbar.policy.BluetoothUtil.Profile; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.List; import java.util.Set; public class BluetoothControllerImpl implements BluetoothController { private static final String TAG = "BluetoothController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + // This controls the order in which we check the states. Since a device can only have + // one state on screen, but can have multiple profiles, the later states override the + // value of earlier states. So if a device has a profile in CONNECTING and one in + // CONNECTED, it will show as CONNECTED, theoretically this shouldn't really happen often, + // but seemed worth noting. + private static final int[] CONNECTION_STATES = { + BluetoothProfile.STATE_DISCONNECTED, + BluetoothProfile.STATE_DISCONNECTING, + BluetoothProfile.STATE_CONNECTING, + BluetoothProfile.STATE_CONNECTED, + }; private final Context mContext; private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); private final BluetoothAdapter mAdapter; private final Receiver mReceiver = new Receiver(); private final ArrayMap<BluetoothDevice, DeviceInfo> mDeviceInfo = new ArrayMap<>(); + private final SparseArray<BluetoothProfile> mProfiles = new SparseArray<>(); private boolean mEnabled; private boolean mConnecting; @@ -73,7 +92,8 @@ public class BluetoothControllerImpl implements BluetoothController { mReceiver.register(); setAdapterState(mAdapter.getState()); - updateBondedBluetoothDevices(); + updateBluetoothDevices(); + bindAllProfiles(); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { @@ -83,6 +103,7 @@ public class BluetoothControllerImpl implements BluetoothController { pw.print(" mConnecting="); pw.println(mConnecting); pw.print(" mLastDevice="); pw.println(mLastDevice); pw.print(" mCallbacks.size="); pw.println(mCallbacks.size()); + pw.print(" mProfiles="); pw.println(profilesToString(mProfiles)); pw.print(" mDeviceInfo.size="); pw.println(mDeviceInfo.size()); for (int i = 0; i < mDeviceInfo.size(); i++) { final BluetoothDevice device = mDeviceInfo.keyAt(i); @@ -95,7 +116,22 @@ public class BluetoothControllerImpl implements BluetoothController { private static String infoToString(DeviceInfo info) { return info == null ? null : ("connectionState=" + - connectionStateToString(info.connectionState) + ",bonded=" + info.bonded); + connectionStateToString(info.connectionState) + ",bonded=" + info.bonded + + ",profiles=" + profilesToString(info.connectedProfiles)); + } + + private static String profilesToString(SparseArray<?> profiles) { + final int N = profiles.size(); + final StringBuffer buffer = new StringBuffer(); + buffer.append('['); + for (int i = 0; i < N; i++) { + if (i != 0) { + buffer.append(','); + } + buffer.append(BluetoothUtil.profileToString(profiles.keyAt(i))); + } + buffer.append(']'); + return buffer.toString(); } public void addStateChangedCallback(Callback cb) { @@ -178,6 +214,7 @@ public class BluetoothControllerImpl implements BluetoothController { private void connect(PairedDevice pd, final boolean connect) { if (mAdapter == null || pd == null || pd.tag == null) return; final BluetoothDevice device = (BluetoothDevice) pd.tag; + final DeviceInfo info = mDeviceInfo.get(device); final String action = connect ? "connect" : "disconnect"; if (DEBUG) Log.d(TAG, action + " " + deviceToString(device)); final ParcelUuid[] uuids = device.getUuids(); @@ -185,43 +222,35 @@ public class BluetoothControllerImpl implements BluetoothController { Log.w(TAG, "No uuids returned, aborting " + action + " for " + deviceToString(device)); return; } - final SparseBooleanArray profiles = new SparseBooleanArray(); - for (ParcelUuid uuid : uuids) { - final int profile = uuidToProfile(uuid); - if (profile == 0) { - Log.w(TAG, "Device " + deviceToString(device) + " has an unsupported uuid: " - + uuidToString(uuid)); - continue; - } - final int profileState = mAdapter.getProfileConnectionState(profile); - if (DEBUG && !profiles.get(profile)) Log.d(TAG, "Profile " + profileToString(profile) - + " state = " + profileStateToString(profileState)); - final boolean connected = profileState == BluetoothProfile.STATE_CONNECTED; - if (connect != connected) { - profiles.put(profile, true); + SparseArray<Boolean> profiles = new SparseArray<>(); + if (connect) { + // When connecting add every profile we can recognize by uuid. + for (ParcelUuid uuid : uuids) { + final int profile = uuidToProfile(uuid); + if (profile == 0) { + Log.w(TAG, "Device " + deviceToString(device) + " has an unsupported uuid: " + + uuidToString(uuid)); + continue; + } + final boolean connected = info.connectedProfiles.get(profile, false); + if (!connected) { + profiles.put(profile, true); + } } + } else { + // When disconnecting, just add every profile we know they are connected to. + profiles = info.connectedProfiles; } for (int i = 0; i < profiles.size(); i++) { final int profile = profiles.keyAt(i); - mAdapter.getProfileProxy(mContext, new ServiceListener() { - @Override - public void onServiceConnected(int profile, BluetoothProfile proxy) { - if (DEBUG) Log.d(TAG, "onServiceConnected " + profileToString(profile)); - final Profile p = BluetoothUtil.getProfile(proxy); - if (p == null) { - Log.w(TAG, "Unable get get Profile for " + profileToString(profile)); - } else { - final boolean ok = connect ? p.connect(device) : p.disconnect(device); - if (DEBUG) Log.d(TAG, action + " " + profileToString(profile) + " " - + (ok ? "succeeded" : "failed")); - } - } - - @Override - public void onServiceDisconnected(int profile) { - if (DEBUG) Log.d(TAG, "onServiceDisconnected " + profileToString(profile)); - } - }, profile); + if (mProfiles.indexOfKey(profile) >= 0) { + final Profile p = BluetoothUtil.getProfile(mProfiles.get(profile)); + final boolean ok = connect ? p.connect(device) : p.disconnect(device); + if (DEBUG) Log.d(TAG, action + " " + profileToString(profile) + " " + + (ok ? "succeeded" : "failed")); + } else { + Log.w(TAG, "Unable get get Profile for " + profileToString(profile)); + } } } @@ -230,11 +259,13 @@ public class BluetoothControllerImpl implements BluetoothController { return mLastDevice != null ? mLastDevice.getAliasName() : null; } - private void updateBondedBluetoothDevices() { + private void updateBluetoothDevices() { if (mAdapter == null) return; final Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices(); for (DeviceInfo info : mDeviceInfo.values()) { info.bonded = false; + info.connectionState = ERROR; + info.connectedProfiles.clear(); } int bondedCount = 0; BluetoothDevice lastBonded = null; @@ -248,12 +279,62 @@ public class BluetoothControllerImpl implements BluetoothController { } } } + final int N = mProfiles.size(); + final int[] connectionType = new int[1]; + for (int i = 0; i < CONNECTION_STATES.length; i++) { + connectionType[0] = CONNECTION_STATES[i]; + for (int j = 0; j < N; j++) { + int profile = mProfiles.keyAt(j); + List<BluetoothDevice> devices = mProfiles.get(profile) + .getDevicesMatchingConnectionStates(connectionType); + for (int k = 0; k < devices.size(); k++) { + DeviceInfo info = mDeviceInfo.get(devices.get(k)); + info.connectionState = CONNECTION_STATES[i]; + if (CONNECTION_STATES[i] == BluetoothProfile.STATE_CONNECTED) { + info.connectedProfiles.put(profile, true); + } + } + } + } if (mLastDevice == null && bondedCount == 1) { mLastDevice = lastBonded; } + // If we are no longer connected to the current device, see if we are connected to + // something else, so we don't display a name we aren't connected to. + if (mLastDevice != null && + mDeviceInfo.get(mLastDevice).connectionState != BluetoothProfile.STATE_CONNECTED) { + // Make sure we don't keep this device while it isn't connected. + mLastDevice = null; + // Look for anything else connected. + final int size = mDeviceInfo.size(); + for (int i = 0; i < size; i++) { + BluetoothDevice device = mDeviceInfo.keyAt(i); + DeviceInfo info = mDeviceInfo.valueAt(i); + if (info.connectionState == BluetoothProfile.STATE_CONNECTED) { + mLastDevice = device; + break; + } + } + } firePairedDevicesChanged(); } + private void bindAllProfiles() { + // Note: This needs to contain all of the types that can be returned by BluetoothUtil + // otherwise we can't find the profiles we need when we connect/disconnect. + mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP); + mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP_SINK); + mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.AVRCP_CONTROLLER); + mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET); + mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET_CLIENT); + mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.INPUT_DEVICE); + mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.MAP); + mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.PAN); + // Note Health is not in this list because health devices aren't 'connected'. + // If profiles are expanded to use more than just connection state and connect/disconnect + // then it should be added. + } + private void firePairedDevicesChanged() { for (Callback cb : mCallbacks) { cb.onBluetoothPairedDevicesChanged(); @@ -283,6 +364,20 @@ public class BluetoothControllerImpl implements BluetoothController { cb.onBluetoothStateChange(mEnabled, mConnecting); } + private final ServiceListener mProfileListener = new ServiceListener() { + @Override + public void onServiceDisconnected(int profile) { + mProfiles.remove(profile); + updateBluetoothDevices(); + } + + @Override + public void onServiceConnected(int profile, BluetoothProfile proxy) { + mProfiles.put(profile, proxy); + updateBluetoothDevices(); + } + }; + private final class Receiver extends BroadcastReceiver { public void register() { final IntentFilter filter = new IntentFilter(); @@ -290,6 +385,15 @@ public class BluetoothControllerImpl implements BluetoothController { filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); filter.addAction(BluetoothDevice.ACTION_ALIAS_CHANGED); + filter.addAction(BluetoothDevice.ACTION_CLASS_CHANGED); + filter.addAction(BluetoothDevice.ACTION_UUID); + filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); + filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); + filter.addAction(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED); + filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED); + filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED); + filter.addAction(BluetoothMap.ACTION_CONNECTION_STATE_CHANGED); + filter.addAction(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED); mContext.registerReceiver(this, filter); } @@ -301,16 +405,13 @@ public class BluetoothControllerImpl implements BluetoothController { setAdapterState(intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, ERROR)); if (DEBUG) Log.d(TAG, "ACTION_STATE_CHANGED " + mEnabled); } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) { - final DeviceInfo info = updateInfo(device); + updateInfo(device); final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, ERROR); - if (state != ERROR) { - info.connectionState = state; - } mLastDevice = device; if (DEBUG) Log.d(TAG, "ACTION_CONNECTION_STATE_CHANGED " + connectionStateToString(state) + " " + deviceToString(device)); - setConnecting(info.connectionState == BluetoothAdapter.STATE_CONNECTING); + setConnecting(state == BluetoothAdapter.STATE_CONNECTING); } else if (action.equals(BluetoothDevice.ACTION_ALIAS_CHANGED)) { updateInfo(device); mLastDevice = device; @@ -318,7 +419,8 @@ public class BluetoothControllerImpl implements BluetoothController { if (DEBUG) Log.d(TAG, "ACTION_BOND_STATE_CHANGED " + device); // we'll update all bonded devices below } - updateBondedBluetoothDevices(); + // Always update bluetooth devices state. + updateBluetoothDevices(); } } @@ -332,5 +434,6 @@ public class BluetoothControllerImpl implements BluetoothController { private static class DeviceInfo { int connectionState = BluetoothAdapter.STATE_DISCONNECTED; boolean bonded; // per getBondedDevices + SparseArray<Boolean> connectedProfiles = new SparseArray<>(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothUtil.java index 1b4be85..ed8ac2c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothUtil.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothUtil.java @@ -36,7 +36,10 @@ public class BluetoothUtil { if (profile == BluetoothProfile.HEADSET) return "HEADSET"; if (profile == BluetoothProfile.A2DP) return "A2DP"; if (profile == BluetoothProfile.AVRCP_CONTROLLER) return "AVRCP_CONTROLLER"; - return "UNKNOWN"; + if (profile == BluetoothProfile.PAN) return "PAN"; + if (profile == BluetoothProfile.INPUT_DEVICE) return "INPUT_DEVICE"; + if (profile == BluetoothProfile.MAP) return "MAP"; + return "UNKNOWN(" + profile + ")"; } public static String profileStateToString(int state) { @@ -106,6 +109,11 @@ public class BluetoothUtil { if (BluetoothUuid.AvrcpController.equals(uuid)) return BluetoothProfile.AVRCP_CONTROLLER; + if (BluetoothUuid.Hid.equals(uuid)) return BluetoothProfile.INPUT_DEVICE; + if (BluetoothUuid.Hogp.equals(uuid)) return BluetoothProfile.INPUT_DEVICE; + + if (BluetoothUuid.NAP.equals(uuid)) return BluetoothProfile.PAN; + return 0; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java index 30da9cb..af51266 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java @@ -196,6 +196,7 @@ public class MobileDataControllerImpl implements NetworkController.MobileDataCon } public void setMobileDataEnabled(boolean enabled) { + Log.d(TAG, "setMobileDataEnabled: enabled=" + enabled); mTelephonyManager.setDataEnabled(enabled); if (mCallback != null) { mCallback.onMobileDataEnabled(enabled); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 6431ab5..3397a38 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -272,7 +272,7 @@ public class NetworkControllerImpl extends BroadcastReceiver if (mMobileSignalControllers.containsKey(dataSubId)) { return mMobileSignalControllers.get(dataSubId); } - Log.e(TAG, "Cannot find controller for data sub: " + dataSubId); + if (DEBUG) Log.e(TAG, "Cannot find controller for data sub: " + dataSubId); return mDefaultSignalController; } @@ -293,7 +293,7 @@ public class NetworkControllerImpl extends BroadcastReceiver if (mMobileSignalControllers.containsKey(voiceSubId)) { return mMobileSignalControllers.get(voiceSubId).isEmergencyOnly(); } - Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId); + if (DEBUG) Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId); // Something is wrong, better assume we can't make calls... return true; } @@ -483,6 +483,10 @@ public class NetworkControllerImpl extends BroadcastReceiver cachedControllers.get(key).unregisterListener(); } } + // There may be new MobileSignalControllers around, make sure they get the current + // inet condition and airplane mode. + pushConnectivityToSignals(); + updateAirplaneMode(true /* force */); } private boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) { @@ -577,6 +581,13 @@ public class NetworkControllerImpl extends BroadcastReceiver mBluetoothTethered = mConnectedTransports.get(TRANSPORT_BLUETOOTH); mEthernetConnected = mConnectedTransports.get(TRANSPORT_ETHERNET); + pushConnectivityToSignals(); + } + + /** + * Pushes the current connectivity state to all SignalControllers. + */ + private void pushConnectivityToSignals() { // We want to update all the icons, all at once, for any condition change for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) { mobileSignalController.setInetCondition( diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java index d3a8fc0..acdcfc1 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java @@ -124,8 +124,7 @@ public class VolumePanel extends Handler implements DemoMode { private static final int MSG_ZEN_MODE_AVAILABLE_CHANGED = 13; private static final int MSG_USER_ACTIVITY = 14; private static final int MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED = 15; - private static final int MSG_ZEN_MODE_CHANGED = 16; - private static final int MSG_INTERNAL_RINGER_MODE_CHANGED = 17; + private static final int MSG_INTERNAL_RINGER_MODE_CHANGED = 16; // Pseudo stream type for master volume private static final int STREAM_MASTER = -100; @@ -511,6 +510,9 @@ public class VolumePanel extends Handler implements DemoMode { pw.println(); } } + if (mZenPanel != null) { + mZenPanel.dump(fd, pw, args); + } } private void initZenModePanel() { @@ -723,7 +725,7 @@ public class VolumePanel extends Handler implements DemoMode { mSliderPanel.addView(active.group); mActiveStreamType = activeStreamType; active.group.setVisibility(View.VISIBLE); - updateSlider(active); + updateSlider(active, true /*forceReloadIcon*/); updateTimeoutDelay(); updateZenPanelVisible(); } @@ -799,11 +801,12 @@ public class VolumePanel extends Handler implements DemoMode { } /** Update the mute and progress state of a slider */ - private void updateSlider(StreamControl sc) { + private void updateSlider(StreamControl sc, boolean forceReloadIcon) { updateSliderProgress(sc, -1); final boolean muted = isMuted(sc.streamType); - // Force reloading the image resource - sc.icon.setImageDrawable(null); + if (forceReloadIcon) { + sc.icon.setImageDrawable(null); + } updateSliderIcon(sc, muted); updateSliderEnabled(sc, muted, false); updateSliderSuppressor(sc); @@ -907,11 +910,18 @@ public class VolumePanel extends Handler implements DemoMode { } } - public void updateStates() { + private void updateStates() { final int count = mSliderPanel.getChildCount(); for (int i = 0; i < count; i++) { StreamControl sc = (StreamControl) mSliderPanel.getChildAt(i).getTag(); - updateSlider(sc); + updateSlider(sc, true /*forceReloadIcon*/); + } + } + + private void updateActiveSlider() { + final StreamControl active = mStreamControls.get(mActiveStreamType); + if (active != null) { + updateSlider(active, false /*forceReloadIcon*/); } } @@ -1449,12 +1459,11 @@ public class VolumePanel extends Handler implements DemoMode { break; } - case MSG_ZEN_MODE_CHANGED: case MSG_RINGER_MODE_CHANGED: case MSG_INTERNAL_RINGER_MODE_CHANGED: case MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED: { if (isShowing()) { - updateStates(); + updateActiveSlider(); } break; } @@ -1563,10 +1572,6 @@ public class VolumePanel extends Handler implements DemoMode { mNotificationEffectsSuppressor = mZenController.getEffectsSuppressor(); sendEmptyMessage(MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED); } - - public void onZenChanged(int zen) { - sendEmptyMessage(MSG_ZEN_MODE_CHANGED); - } }; private final MediaController.Callback mMediaControllerCb = new MediaController.Callback() { @@ -1591,6 +1596,7 @@ public class VolumePanel extends Handler implements DemoMode { public void start(StreamControl sc) { if (sc == null) throw new IllegalArgumentException(); + if (LOGD) Log.d(mTag, "Secondary icon animation start"); if (mTarget != null) { cancel(); } @@ -1643,6 +1649,7 @@ public class VolumePanel extends Handler implements DemoMode { @Override public void run() { if (mTarget == null) return; + if (LOGD) Log.d(mTag, "Secondary icon animation complete, show notification slider"); mAudioManager.forceVolumeControlStream(StreamResources.NotificationStream.streamType); mAudioManager.adjustStreamVolume(StreamResources.NotificationStream.streamType, AudioManager.ADJUST_SAME, AudioManager.FLAG_SHOW_UI); diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java index 6ed24e0..e250ec7 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java @@ -17,13 +17,16 @@ package com.android.systemui.volume; import android.animation.LayoutTransition; +import android.animation.LayoutTransition.TransitionListener; import android.app.ActivityManager; +import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.res.Resources; import android.net.Uri; +import android.os.AsyncTask; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -32,6 +35,7 @@ import android.provider.Settings.Global; import android.service.notification.Condition; import android.service.notification.ZenModeConfig; import android.text.TextUtils; +import android.util.ArraySet; import android.util.AttributeSet; import android.util.Log; import android.util.MathUtils; @@ -50,6 +54,8 @@ import android.widget.TextView; import com.android.systemui.R; import com.android.systemui.statusbar.policy.ZenModeController; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.Arrays; import java.util.Objects; @@ -67,8 +73,7 @@ public class ZenModePanel extends LinearLayout { private static final int MAX_BUCKET_MINUTES = MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1]; private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60); private static final int FOREVER_CONDITION_INDEX = 0; - private static final int TIME_CONDITION_INDEX = 1; - private static final int FIRST_CONDITION_INDEX = 2; + private static final int COUNTDOWN_CONDITION_INDEX = 1; public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS); @@ -81,6 +86,10 @@ public class ZenModePanel extends LinearLayout { private final int mSubheadColor; private final Interpolator mInterpolator; private final int mMaxConditions; + private final int mMaxOptionalConditions; + private final boolean mCountdownConditionSupported; + private final int mFirstConditionIndex; + private final TransitionHelper mTransitionHelper = new TransitionHelper(); private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this)); @@ -98,7 +107,7 @@ public class ZenModePanel extends LinearLayout { private String mExitConditionText; private int mBucketIndex = -1; private boolean mExpanded; - private boolean mHidden = false; + private boolean mHidden; private int mSessionZen; private int mAttachedZen; private boolean mAttached; @@ -117,11 +126,30 @@ public class ZenModePanel extends LinearLayout { mSubheadColor = res.getColor(R.color.qs_subhead); mInterpolator = AnimationUtils.loadInterpolator(mContext, com.android.internal.R.interpolator.fast_out_slow_in); + mCountdownConditionSupported = NotificationManager.from(mContext) + .isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH); + final int countdownDelta = mCountdownConditionSupported ? 1 : 0; + mFirstConditionIndex = COUNTDOWN_CONDITION_INDEX + countdownDelta; + final int minConditions = 1 /*forever*/ + countdownDelta; mMaxConditions = MathUtils.constrain(res.getInteger(R.integer.zen_mode_max_conditions), - 1, 100); + minConditions, 100); + mMaxOptionalConditions = mMaxConditions - minConditions; if (DEBUG) Log.d(mTag, "new ZenModePanel"); } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("ZenModePanel state:"); + pw.print(" mCountdownConditionSupported="); pw.println(mCountdownConditionSupported); + pw.print(" mMaxConditions="); pw.println(mMaxConditions); + pw.print(" mRequestingConditions="); pw.println(mRequestingConditions); + pw.print(" mAttached="); pw.println(mAttached); + pw.print(" mHidden="); pw.println(mHidden); + pw.print(" mExpanded="); pw.println(mExpanded); + pw.print(" mSessionZen="); pw.println(mSessionZen); + pw.print(" mAttachedZen="); pw.println(mAttachedZen); + mTransitionHelper.dump(fd, pw, args); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -135,6 +163,9 @@ public class ZenModePanel extends LinearLayout { Global.ZEN_MODE_OFF); mZenButtons.setCallback(mZenButtonsCallback); + final ViewGroup zenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container); + zenButtonsContainer.setLayoutTransition(newLayoutTransition(null)); + mZenSubhead = findViewById(R.id.zen_subhead); mZenSubheadCollapsed = (TextView) findViewById(R.id.zen_subhead_collapsed); @@ -159,15 +190,22 @@ public class ZenModePanel extends LinearLayout { Interaction.register(mMoreSettings, mInteractionCallback); mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions); - setLayoutTransition(newLayoutTransition()); + for (int i = 0; i < mMaxConditions; i++) { + mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false)); + } + + setLayoutTransition(newLayoutTransition(mTransitionHelper)); } - private LayoutTransition newLayoutTransition() { + private LayoutTransition newLayoutTransition(TransitionListener listener) { final LayoutTransition transition = new LayoutTransition(); transition.disableTransitionType(LayoutTransition.DISAPPEARING); transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING); - transition.setInterpolator(LayoutTransition.APPEARING, mInterpolator); + transition.disableTransitionType(LayoutTransition.APPEARING); transition.setInterpolator(LayoutTransition.CHANGE_APPEARING, mInterpolator); + if (listener != null) { + transition.addTransitionListener(listener); + } return transition; } @@ -175,11 +213,11 @@ public class ZenModePanel extends LinearLayout { protected void onAttachedToWindow() { super.onAttachedToWindow(); if (DEBUG) Log.d(mTag, "onAttachedToWindow"); - ((ViewGroup) getParent()).setLayoutTransition(newLayoutTransition()); mAttached = true; mAttachedZen = getSelectedZen(-1); mSessionZen = mAttachedZen; - mSessionExitCondition = copy(mExitCondition); + mTransitionHelper.clear(); + setSessionExitCondition(copy(mExitCondition)); refreshExitConditionText(); updateWidgets(); setRequestingConditions(!mHidden); @@ -193,9 +231,16 @@ public class ZenModePanel extends LinearLayout { mAttached = false; mAttachedZen = -1; mSessionZen = -1; - mSessionExitCondition = null; + setSessionExitCondition(null); setExpanded(false); setRequestingConditions(false); + mTransitionHelper.clear(); + } + + private void setSessionExitCondition(Condition condition) { + if (Objects.equals(condition, mSessionExitCondition)) return; + if (DEBUG) Log.d(mTag, "mSessionExitCondition=" + getConditionId(condition)); + mSessionExitCondition = condition; } public void setHidden(boolean hidden) { @@ -228,12 +273,17 @@ public class ZenModePanel extends LinearLayout { } /** Start or stop requesting relevant zen mode exit conditions */ - private void setRequestingConditions(boolean requesting) { + private void setRequestingConditions(final boolean requesting) { if (mRequestingConditions == requesting) return; if (DEBUG) Log.d(mTag, "setRequestingConditions " + requesting); mRequestingConditions = requesting; if (mController != null) { - mController.requestConditions(mRequestingConditions); + AsyncTask.execute(new Runnable() { + @Override + public void run() { + mController.requestConditions(requesting); + } + }); } if (mRequestingConditions) { mTimeCondition = parseExistingTimeCondition(mExitCondition); @@ -248,7 +298,7 @@ public class ZenModePanel extends LinearLayout { mConditions = null; // reset conditions handleUpdateConditions(); } else { - mZenConditions.removeAllViews(); + hideAllConditions(); } } @@ -259,7 +309,7 @@ public class ZenModePanel extends LinearLayout { mSessionZen = getSelectedZen(-1); handleUpdateZen(mController.getZen()); if (DEBUG) Log.d(mTag, "init mExitCondition=" + mExitCondition); - mZenConditions.removeAllViews(); + hideAllConditions(); mController.addCallback(mZenCallback); } @@ -270,6 +320,7 @@ public class ZenModePanel extends LinearLayout { private void setExitCondition(Condition exitCondition) { if (Objects.equals(mExitCondition, exitCondition)) return; mExitCondition = exitCondition; + if (DEBUG) Log.d(mTag, "mExitCondition=" + getConditionId(mExitCondition)); refreshExitConditionText(); updateWidgets(); } @@ -290,7 +341,7 @@ public class ZenModePanel extends LinearLayout { final String forever = mContext.getString(com.android.internal.R.string.zen_mode_forever); if (mExitCondition == null) { mExitConditionText = forever; - } else if (ZenModeConfig.isValidCountdownConditionId(mExitCondition.id)) { + } else if (isCountdown(mExitCondition)) { final Condition condition = parseExistingTimeCondition(mExitCondition); mExitConditionText = condition != null ? condition.summary : forever; } else { @@ -316,6 +367,24 @@ public class ZenModePanel extends LinearLayout { } mZenButtons.setSelectedValue(zen); updateWidgets(); + handleUpdateConditions(); + if (mExpanded) { + final Condition selected = getSelectedCondition(); + if (!Objects.equals(mExitCondition, selected)) { + select(selected); + } + } + } + + private Condition getSelectedCondition() { + final int N = getVisibleConditions(); + for (int i = 0; i < N; i++) { + final ConditionTag tag = getConditionTagAt(i); + if (tag != null && tag.rb.isChecked()) { + return tag.condition; + } + } + return null; } private int getSelectedZen(int defValue) { @@ -324,6 +393,10 @@ public class ZenModePanel extends LinearLayout { } private void updateWidgets() { + if (mTransitionHelper.isTransitioning()) { + mTransitionHelper.pendingUpdateWidgets(); + return; + } final int zen = getSelectedZen(Global.ZEN_MODE_OFF); final boolean zenOff = zen == Global.ZEN_MODE_OFF; final boolean zenImportant = zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; @@ -371,7 +444,7 @@ public class ZenModePanel extends LinearLayout { } private Condition[] trimConditions(Condition[] conditions) { - if (conditions == null || conditions.length <= mMaxConditions) { + if (conditions == null || conditions.length <= mMaxOptionalConditions) { // no need to trim return conditions; } @@ -384,33 +457,34 @@ public class ZenModePanel extends LinearLayout { break; } } - final Condition[] rt = Arrays.copyOf(conditions, mMaxConditions); - if (found >= mMaxConditions) { + final Condition[] rt = Arrays.copyOf(conditions, mMaxOptionalConditions); + if (found >= mMaxOptionalConditions) { // found after the first N, promote to the end of the first N - rt[mMaxConditions - 1] = conditions[found]; + rt[mMaxOptionalConditions - 1] = conditions[found]; } return rt; } private void handleUpdateConditions() { + if (mTransitionHelper.isTransitioning()) { + mTransitionHelper.pendingUpdateConditions(); + return; + } final int conditionCount = mConditions == null ? 0 : mConditions.length; if (DEBUG) Log.d(mTag, "handleUpdateConditions conditionCount=" + conditionCount); - for (int i = mZenConditions.getChildCount() - 1; i >= FIRST_CONDITION_INDEX; i--) { - mZenConditions.removeViewAt(i); - } // forever bind(null, mZenConditions.getChildAt(FOREVER_CONDITION_INDEX)); // countdown - bind(mTimeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX)); + if (mCountdownConditionSupported) { + bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX)); + } // provider conditions - boolean foundDowntime = false; for (int i = 0; i < conditionCount; i++) { - bind(mConditions[i], mZenConditions.getChildAt(FIRST_CONDITION_INDEX + i)); - foundDowntime |= isDowntime(mConditions[i]); + bind(mConditions[i], mZenConditions.getChildAt(mFirstConditionIndex + i)); } - // ensure downtime exists, if active - if (isDowntime(mSessionExitCondition) && !foundDowntime) { - bind(mSessionExitCondition, null); + // hide the rest + for (int i = mZenConditions.getChildCount() - 1; i > mFirstConditionIndex + conditionCount; i--) { + mZenConditions.getChildAt(i).setVisibility(GONE); } // ensure something is selected if (mExpanded) { @@ -418,78 +492,101 @@ public class ZenModePanel extends LinearLayout { } } - private static boolean isDowntime(Condition c) { - return ZenModeConfig.isValidDowntimeConditionId(getConditionId(c)); - } - private ConditionTag getConditionTagAt(int index) { return (ConditionTag) mZenConditions.getChildAt(index).getTag(); } + private int getVisibleConditions() { + int rt = 0; + final int N = mZenConditions.getChildCount(); + for (int i = 0; i < N; i++) { + rt += mZenConditions.getChildAt(i).getVisibility() == VISIBLE ? 1 : 0; + } + return rt; + } + + private void hideAllConditions() { + final int N = mZenConditions.getChildCount(); + for (int i = 0; i < N; i++) { + mZenConditions.getChildAt(i).setVisibility(GONE); + } + } + private void ensureSelection() { // are we left without anything selected? if so, set a default - if (mZenConditions.getChildCount() == 0) return; - for (int i = 0; i < mZenConditions.getChildCount(); i++) { - if (getConditionTagAt(i).rb.isChecked()) { - if (DEBUG) Log.d(mTag, "Not selecting a default, checked=" - + getConditionTagAt(i).condition); + final int visibleConditions = getVisibleConditions(); + if (visibleConditions == 0) return; + for (int i = 0; i < visibleConditions; i++) { + final ConditionTag tag = getConditionTagAt(i); + if (tag != null && tag.rb.isChecked()) { + if (DEBUG) Log.d(mTag, "Not selecting a default, checked=" + tag.condition); return; } } + final ConditionTag foreverTag = getConditionTagAt(FOREVER_CONDITION_INDEX); + if (foreverTag == null) return; if (DEBUG) Log.d(mTag, "Selecting a default"); final int favoriteIndex = mPrefs.getMinuteIndex(); - if (favoriteIndex == -1) { - getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true); + if (favoriteIndex == -1 || !mCountdownConditionSupported) { + foreverTag.rb.setChecked(true); } else { mTimeCondition = ZenModeConfig.toTimeCondition(mContext, MINUTE_BUCKETS[favoriteIndex], ActivityManager.getCurrentUser()); mBucketIndex = favoriteIndex; - bind(mTimeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX)); - getConditionTagAt(TIME_CONDITION_INDEX).rb.setChecked(true); + bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX)); + getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb.setChecked(true); } } private void handleExitConditionChanged(Condition exitCondition) { setExitCondition(exitCondition); if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitCondition); - final int N = mZenConditions.getChildCount(); + final int N = getVisibleConditions(); for (int i = 0; i < N; i++) { final ConditionTag tag = getConditionTagAt(i); - tag.rb.setChecked(sameConditionId(tag.condition, mExitCondition)); + if (tag != null) { + if (sameConditionId(tag.condition, mExitCondition)) { + bind(exitCondition, mZenConditions.getChildAt(i)); + } + } } } - private void bind(final Condition condition, View convertView) { + private boolean isCountdown(Condition c) { + return c != null && ZenModeConfig.isValidCountdownConditionId(c.id); + } + + private void bind(final Condition condition, final View row) { final boolean enabled = condition == null || condition.state == Condition.STATE_TRUE; - final View row; - if (convertView == null) { - row = mInflater.inflate(R.layout.zen_mode_condition, this, false); - if (DEBUG) Log.d(mTag, "Adding new condition view for: " + condition); - mZenConditions.addView(row); - } else { - row = convertView; - } final ConditionTag tag = row.getTag() != null ? (ConditionTag) row.getTag() : new ConditionTag(); row.setTag(tag); + final boolean first = tag.rb == null; if (tag.rb == null) { tag.rb = (RadioButton) row.findViewById(android.R.id.checkbox); } tag.condition = condition; + final Uri conditionId = getConditionId(tag.condition); + if (DEBUG) Log.d(mTag, "bind i=" + mZenConditions.indexOfChild(row) + " first=" + first + + " condition=" + conditionId); tag.rb.setEnabled(enabled); - if ((mSessionExitCondition != null || mAttachedZen != Global.ZEN_MODE_OFF) - && sameConditionId(mSessionExitCondition, tag.condition)) { - tag.rb.setChecked(true); + final boolean checked = (mSessionExitCondition != null + || mAttachedZen != Global.ZEN_MODE_OFF) + && (sameConditionId(mSessionExitCondition, tag.condition) + || isCountdown(mSessionExitCondition) && isCountdown(tag.condition)); + if (checked != tag.rb.isChecked()) { + if (DEBUG) Log.d(mTag, "bind checked=" + checked + " condition=" + conditionId); + tag.rb.setChecked(checked); } tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (mExpanded && isChecked) { - if (DEBUG) Log.d(mTag, "onCheckedChanged " + tag.condition); - final int N = mZenConditions.getChildCount(); + if (DEBUG) Log.d(mTag, "onCheckedChanged " + conditionId); + final int N = getVisibleConditions(); for (int i = 0; i < N; i++) { - ConditionTag childTag = getConditionTagAt(i); - if (childTag == tag) continue; + final ConditionTag childTag = getConditionTagAt(i); + if (childTag == null || childTag == tag) continue; childTag.rb.setChecked(false); } select(tag.condition); @@ -547,8 +644,10 @@ public class ZenModePanel extends LinearLayout { } }); - final long time = ZenModeConfig.tryParseCountdownConditionId(getConditionId(tag.condition)); + final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId); if (time > 0) { + button1.setVisibility(VISIBLE); + button2.setVisibility(VISIBLE); if (mBucketIndex > -1) { button1.setEnabled(mBucketIndex > 0); button2.setEnabled(mBucketIndex < MINUTE_BUCKETS.length - 1); @@ -563,16 +662,17 @@ public class ZenModePanel extends LinearLayout { button1.setAlpha(button1.isEnabled() ? 1f : .5f); button2.setAlpha(button2.isEnabled() ? 1f : .5f); } else { - button1.setVisibility(View.GONE); - button2.setVisibility(View.GONE); + button1.setVisibility(GONE); + button2.setVisibility(GONE); } // wire up interaction callbacks for newly-added condition rows - if (convertView == null) { + if (first) { Interaction.register(tag.rb, mInteractionCallback); Interaction.register(tag.lines, mInteractionCallback); Interaction.register(button1, mInteractionCallback); Interaction.register(button2, mInteractionCallback); } + row.setVisibility(VISIBLE); } private void announceConditionSelection(ConditionTag tag) { @@ -629,18 +729,23 @@ public class ZenModePanel extends LinearLayout { announceConditionSelection(tag); } - private void select(Condition condition) { + private void select(final Condition condition) { if (DEBUG) Log.d(mTag, "select " + condition); if (mController != null) { - mController.setExitCondition(condition); + AsyncTask.execute(new Runnable() { + @Override + public void run() { + mController.setExitCondition(condition); + } + }); } setExitCondition(condition); if (condition == null) { mPrefs.setMinuteIndex(-1); - } else if (ZenModeConfig.isValidCountdownConditionId(condition.id) && mBucketIndex != -1) { + } else if (isCountdown(condition) && mBucketIndex != -1) { mPrefs.setMinuteIndex(mBucketIndex); } - mSessionExitCondition = copy(condition); + setSessionExitCondition(copy(condition)); } private void fireMoreSettings() { @@ -784,10 +889,15 @@ public class ZenModePanel extends LinearLayout { private final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() { @Override - public void onSelected(Object value) { + public void onSelected(final Object value) { if (value != null && mZenButtons.isShown()) { if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + value); - mController.setZen((Integer) value); + AsyncTask.execute(new Runnable() { + @Override + public void run() { + mController.setZen((Integer) value); + } + }); } } @@ -803,4 +913,79 @@ public class ZenModePanel extends LinearLayout { fireInteraction(); } }; + + private final class TransitionHelper implements TransitionListener, Runnable { + private final ArraySet<View> mTransitioningViews = new ArraySet<View>(); + + private boolean mTransitioning; + private boolean mPendingUpdateConditions; + private boolean mPendingUpdateWidgets; + + public void clear() { + mTransitioningViews.clear(); + mPendingUpdateConditions = mPendingUpdateWidgets = false; + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println(" TransitionHelper state:"); + pw.print(" mPendingUpdateConditions="); pw.println(mPendingUpdateConditions); + pw.print(" mPendingUpdateWidgets="); pw.println(mPendingUpdateWidgets); + pw.print(" mTransitioning="); pw.println(mTransitioning); + pw.print(" mTransitioningViews="); pw.println(mTransitioningViews); + } + + public void pendingUpdateConditions() { + mPendingUpdateConditions = true; + } + + public void pendingUpdateWidgets() { + mPendingUpdateWidgets = true; + } + + public boolean isTransitioning() { + return !mTransitioningViews.isEmpty(); + } + + @Override + public void startTransition(LayoutTransition transition, + ViewGroup container, View view, int transitionType) { + mTransitioningViews.add(view); + updateTransitioning(); + } + + @Override + public void endTransition(LayoutTransition transition, + ViewGroup container, View view, int transitionType) { + mTransitioningViews.remove(view); + updateTransitioning(); + } + + @Override + public void run() { + if (DEBUG) Log.d(mTag, "TransitionHelper run" + + " mPendingUpdateWidgets=" + mPendingUpdateWidgets + + " mPendingUpdateConditions=" + mPendingUpdateConditions); + if (mPendingUpdateWidgets) { + updateWidgets(); + } + if (mPendingUpdateConditions) { + handleUpdateConditions(); + } + mPendingUpdateWidgets = mPendingUpdateConditions = false; + } + + private void updateTransitioning() { + final boolean transitioning = isTransitioning(); + if (mTransitioning == transitioning) return; + mTransitioning = transitioning; + if (DEBUG) Log.d(mTag, "TransitionHelper mTransitioning=" + mTransitioning); + if (!mTransitioning) { + if (mPendingUpdateConditions || mPendingUpdateWidgets) { + mHandler.post(this); + } else { + mPendingUpdateConditions = mPendingUpdateWidgets = false; + } + } + } + } } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 89aebe8..63a0cf6 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -3421,7 +3421,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return false; } - // Windows are ordered in z order so start from the botton and find + // Windows are ordered in z order so start from the bottom and find // the window of interest. After that all windows that cover it should // be subtracted from the resulting region. Note that for accessibility // we are returning only interactive windows. @@ -3439,7 +3439,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { windowInteractiveRegion = outRegion; continue; } - } else { + } else if (currentWindow.getType() + != AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY) { Rect currentWindowBounds = mTempRect; currentWindow.getBoundsInScreen(currentWindowBounds); if (windowInteractiveRegion.op(currentWindowBounds, Region.Op.DIFFERENCE)) { diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java index fc4838c..bc31450 100644 --- a/services/core/java/com/android/server/AssetAtlasService.java +++ b/services/core/java/com/android/server/AssetAtlasService.java @@ -46,8 +46,11 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashSet; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -66,7 +69,7 @@ public class AssetAtlasService extends IAssetAtlas.Stub { */ public static final String ASSET_ATLAS_SERVICE = "assetatlas"; - private static final String LOG_TAG = "Atlas"; + private static final String LOG_TAG = "AssetAtlas"; // Turns debug logs on/off. Debug logs are kept to a minimum and should // remain on to diagnose issues @@ -131,7 +134,7 @@ public class AssetAtlasService extends IAssetAtlas.Stub { mContext = context; mVersionName = queryVersionName(context); - ArrayList<Bitmap> bitmaps = new ArrayList<Bitmap>(300); + Collection<Bitmap> bitmaps = new HashSet<Bitmap>(300); int totalPixelCount = 0; // We only care about drawables that hold bitmaps @@ -140,16 +143,18 @@ public class AssetAtlasService extends IAssetAtlas.Stub { final int count = drawables.size(); for (int i = 0; i < count; i++) { - final Bitmap bitmap = drawables.valueAt(i).getBitmap(); - if (bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888) { - bitmaps.add(bitmap); - totalPixelCount += bitmap.getWidth() * bitmap.getHeight(); + try { + totalPixelCount += drawables.valueAt(i).addAtlasableBitmaps(bitmaps); + } catch (Throwable t) { + Log.e("AssetAtlas", "Failed to fetch preloaded drawable state", t); + throw t; } } + ArrayList<Bitmap> sortedBitmaps = new ArrayList<Bitmap>(bitmaps); // Our algorithms perform better when the bitmaps are first sorted // The comparator will sort the bitmap by width first, then by height - Collections.sort(bitmaps, new Comparator<Bitmap>() { + Collections.sort(sortedBitmaps, new Comparator<Bitmap>() { @Override public int compare(Bitmap b1, Bitmap b2) { if (b1.getWidth() == b2.getWidth()) { @@ -160,7 +165,7 @@ public class AssetAtlasService extends IAssetAtlas.Stub { }); // Kick off the packing work on a worker thread - new Thread(new Renderer(bitmaps, totalPixelCount)).start(); + new Thread(new Renderer(sortedBitmaps, totalPixelCount)).start(); } /** diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 3117a17..ca376fd 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -535,15 +535,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub { Log.d(TAG, "Creating new ProfileServiceConnections object for" + " profile: " + bluetoothProfile); } - Intent intent = null; - if (bluetoothProfile == BluetoothProfile.HEADSET) { - intent = new Intent(IBluetoothHeadset.class.getName()); - } else { - return false; - } + + if (bluetoothProfile != BluetoothProfile.HEADSET) return false; + + Intent intent = new Intent(IBluetoothHeadset.class.getName()); psc = new ProfileServiceConnections(intent); + if (!psc.bindService()) return false; + mProfileServices.put(new Integer(bluetoothProfile), psc); - psc.bindService(); } } @@ -571,7 +570,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { synchronized (mProfileServices) { for (Integer i : mProfileServices.keySet()) { ProfileServiceConnections psc = mProfileServices.get(i); - mContext.unbindService(psc); + try { + mContext.unbindService(psc); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e); + } psc.removeAllProxies(); } mProfileServices.clear(); @@ -596,16 +599,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mIntent = intent; } - private void bindService() { - if (mIntent != null && mService == null) { - if (!doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) { - Log.w(TAG, "Unable to bind with intent: " + mIntent - + ". Triggering retry."); - } + private boolean bindService() { + if (mIntent != null && mService == null && + doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) { Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); msg.obj = this; mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); + return true; } + Log.w(TAG, "Unable to bind with intent: " + mIntent); + return false; } private void addProxy(IBluetoothProfileServiceConnection proxy) { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 9c0e486..e11fa93 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -20,22 +20,8 @@ import static android.Manifest.permission.MANAGE_NETWORK_POLICY; import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; -import static android.net.ConnectivityManager.TYPE_BLUETOOTH; -import static android.net.ConnectivityManager.TYPE_DUMMY; -import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.net.ConnectivityManager.TYPE_MOBILE_CBS; -import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; -import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; -import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; -import static android.net.ConnectivityManager.TYPE_MOBILE_IA; -import static android.net.ConnectivityManager.TYPE_MOBILE_IMS; -import static android.net.ConnectivityManager.TYPE_MOBILE_MMS; -import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL; import static android.net.ConnectivityManager.TYPE_NONE; -import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.TYPE_VPN; -import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; @@ -45,11 +31,9 @@ import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; -import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; -import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; @@ -62,7 +46,6 @@ import android.net.INetworkManagementEventObserver; import android.net.INetworkPolicyListener; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; -import android.net.LinkAddress; import android.net.LinkProperties; import android.net.LinkProperties.CompareResult; import android.net.MobileDataStateTracker; @@ -72,7 +55,6 @@ import android.net.NetworkCapabilities; import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; -import android.net.NetworkFactory; import android.net.NetworkMisc; import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; @@ -80,16 +62,12 @@ import android.net.NetworkState; import android.net.NetworkStateTracker; import android.net.NetworkUtils; import android.net.Proxy; -import android.net.ProxyDataTracker; import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.SamplingDataTracker; import android.net.UidRange; import android.net.Uri; -import android.net.wimax.WimaxManagerConstants; -import android.os.AsyncTask; import android.os.Binder; -import android.os.Build; import android.os.Bundle; import android.os.FileUtils; import android.os.Handler; @@ -103,7 +81,6 @@ import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; @@ -126,9 +103,6 @@ import com.android.internal.net.NetworkStatsFactory; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.AsyncChannel; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; @@ -146,8 +120,6 @@ import com.android.server.net.LockdownVpnTracker; import com.google.android.collect.Lists; import com.google.android.collect.Sets; -import dalvik.system.DexClassLoader; - import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -157,31 +129,20 @@ import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; -import java.lang.reflect.Constructor; -import java.net.HttpURLConnection; import java.net.Inet4Address; -import java.net.Inet6Address; import java.net.InetAddress; -import java.net.URL; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Random; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSession; - /** * @hide */ @@ -270,6 +231,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private static ConnectivityService sServiceInstance; private INetworkManagementService mNetd; + private INetworkStatsService mStatsService; private INetworkPolicyManager mPolicyManager; private String mCurrentTcpBufferSizes; @@ -328,12 +290,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 11; /** - * Used internally to - * {@link NetworkStateTracker#setPolicyDataEnable(boolean)}. - */ - private static final int EVENT_SET_POLICY_DATA_ENABLE = 12; - - /** * Used internally to disable fail fast of mobile data */ private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14; @@ -675,6 +631,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mContext = checkNotNull(context, "missing Context"); mNetd = checkNotNull(netManager, "missing INetworkManagementService"); + mStatsService = checkNotNull(statsService, "missing INetworkStatsService"); mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager"); mKeyStore = KeyStore.getInstance(); mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); @@ -825,17 +782,6 @@ public class ConnectivityService extends IConnectivityManager.Stub throw new IllegalStateException("No free netIds"); } - private int getConnectivityChangeDelay() { - final ContentResolver cr = mContext.getContentResolver(); - - /** Check system properties for the default value then use secure settings value, if any. */ - int defaultDelay = SystemProperties.getInt( - "conn." + Settings.Global.CONNECTIVITY_CHANGE_DELAY, - ConnectivityManager.CONNECTIVITY_CHANGE_DELAY_DEFAULT); - return Settings.Global.getInt(cr, Settings.Global.CONNECTIVITY_CHANGE_DELAY, - defaultDelay); - } - private boolean teardown(NetworkStateTracker netTracker) { if (netTracker.teardown()) { netTracker.setTeardownRequested(true); @@ -850,6 +796,7 @@ public class ConnectivityService extends IConnectivityManager.Stub LinkProperties lp = null; NetworkCapabilities nc = null; Network network = null; + String subscriberId = null; if (mLegacyTypeTracker.isTypeSupported(networkType)) { NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); @@ -859,6 +806,7 @@ public class ConnectivityService extends IConnectivityManager.Stub lp = new LinkProperties(nai.linkProperties); nc = new NetworkCapabilities(nai.networkCapabilities); network = new Network(nai.network); + subscriberId = (nai.networkMisc != null) ? nai.networkMisc.subscriberId : null; } info.setType(networkType); } else { @@ -872,7 +820,7 @@ public class ConnectivityService extends IConnectivityManager.Stub info = getFilteredNetworkInfo(info, lp, uid); } - return new NetworkState(info, lp, nc, network); + return new NetworkState(info, lp, nc, network, subscriberId, null); } private NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) { @@ -889,6 +837,7 @@ public class ConnectivityService extends IConnectivityManager.Stub LinkProperties lp = null; NetworkCapabilities nc = null; Network network = null; + String subscriberId = null; NetworkAgentInfo nai = mNetworkForRequestId.get(mDefaultRequest.requestId); @@ -920,10 +869,11 @@ public class ConnectivityService extends IConnectivityManager.Stub lp = new LinkProperties(nai.linkProperties); nc = new NetworkCapabilities(nai.networkCapabilities); network = new Network(nai.network); + subscriberId = (nai.networkMisc != null) ? nai.networkMisc.subscriberId : null; } } - return new NetworkState(info, lp, nc, network); + return new NetworkState(info, lp, nc, network, subscriberId, null); } /** @@ -1220,14 +1170,19 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public NetworkState[] getAllNetworkState() { - enforceAccessPermission(); - final int uid = Binder.getCallingUid(); + // Require internal since we're handing out IMSI details + enforceConnectivityInternalPermission(); + final ArrayList<NetworkState> result = Lists.newArrayList(); - for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE; - networkType++) { - NetworkState state = getFilteredNetworkState(networkType, uid); - if (state.networkInfo != null) { - result.add(state); + for (Network network : getAllNetworks()) { + final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); + if (nai != null) { + synchronized (nai) { + final String subscriberId = (nai.networkMisc != null) + ? nai.networkMisc.subscriberId : null; + result.add(new NetworkState(nai.networkInfo, nai.linkProperties, + nai.networkCapabilities, network, subscriberId, null)); + } } } return result.toArray(new NetworkState[result.size()]); @@ -1452,25 +1407,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } }; - @Override - public void setPolicyDataEnable(int networkType, boolean enabled) { - // only someone like NPMS should only be calling us - mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); - - mHandler.sendMessage(mHandler.obtainMessage( - EVENT_SET_POLICY_DATA_ENABLE, networkType, (enabled ? ENABLED : DISABLED))); - } - - private void handleSetPolicyDataEnable(int networkType, boolean enabled) { - // TODO - handle this passing to factories -// if (isNetworkTypeValid(networkType)) { -// final NetworkStateTracker tracker = mNetTrackers[networkType]; -// if (tracker != null) { -// tracker.setPolicyDataEnable(enabled); -// } -// } - } - private void enforceInternetPermission() { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERNET, @@ -1507,11 +1443,6 @@ public class ConnectivityService extends IConnectivityManager.Stub sendGeneralBroadcast(info, CONNECTIVITY_ACTION); } - private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) { - sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE); - sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs); - } - private void sendInetConditionBroadcast(NetworkInfo info) { sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION); } @@ -1543,10 +1474,6 @@ public class ConnectivityService extends IConnectivityManager.Stub sendStickyBroadcast(makeGeneralIntent(info, bcastType)); } - private void sendGeneralBroadcastDelayed(NetworkInfo info, String bcastType, int delayMs) { - sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs); - } - private void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) { Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE); intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType); @@ -1591,19 +1518,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private void sendStickyBroadcastDelayed(Intent intent, int delayMs) { - if (delayMs <= 0) { - sendStickyBroadcast(intent); - } else { - if (VDBG) { - log("sendStickyBroadcastDelayed: delayMs=" + delayMs + ", action=" - + intent.getAction()); - } - mHandler.sendMessageDelayed(mHandler.obtainMessage( - EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs); - } - } - void systemReady() { // start network sampling .. Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED); @@ -2221,6 +2135,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (isDefaultNetwork(nai)) { mDefaultInetConditionPublished = 0; } + notifyIfacesChanged(); notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST); nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED); mNetworkAgentInfos.remove(msg.replyTo); @@ -2457,12 +2372,6 @@ public class ConnectivityService extends IConnectivityManager.Stub sendStickyBroadcast(intent); break; } - case EVENT_SET_POLICY_DATA_ENABLE: { - final int networkType = msg.arg1; - final boolean enabled = msg.arg2 == ENABLED; - handleSetPolicyDataEnable(networkType, enabled); - break; - } case EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: { int tag = mEnableFailFastMobileDataTag.get(); if (msg.arg1 == tag) { @@ -3721,6 +3630,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (isDefaultNetwork(networkAgent)) handleApplyDefaultProxy(newLp.getHttpProxy()); // TODO - move this check to cover the whole function if (!Objects.equals(newLp, oldLp)) { + notifyIfacesChanged(); notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED); } } @@ -3858,7 +3768,6 @@ public class ConnectivityService extends IConnectivityManager.Stub mNumDnsEntries = last; } - private void updateCapabilities(NetworkAgentInfo networkAgent, NetworkCapabilities networkCapabilities) { if (!Objects.equals(networkAgent.networkCapabilities, networkCapabilities)) { @@ -4312,6 +4221,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } networkAgent.created = true; updateLinkProperties(networkAgent, null); + notifyIfacesChanged(); notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK); networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED); if (networkAgent.isVPN()) { @@ -4388,7 +4298,7 @@ public class ConnectivityService extends IConnectivityManager.Stub info.setType(type); if (connected) { info.setDetailedState(DetailedState.CONNECTED, null, info.getExtraInfo()); - sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay()); + sendConnectedBroadcast(info); } else { info.setDetailedState(DetailedState.DISCONNECTED, null, info.getExtraInfo()); Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); @@ -4419,10 +4329,9 @@ public class ConnectivityService extends IConnectivityManager.Stub final Intent immediateIntent = new Intent(intent); immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); sendStickyBroadcast(immediateIntent); - sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay()); + sendStickyBroadcast(intent); if (newDefaultAgent != null) { - sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo, - getConnectivityChangeDelay()); + sendConnectedBroadcast(newDefaultAgent.networkInfo); } } } @@ -4455,6 +4364,16 @@ public class ConnectivityService extends IConnectivityManager.Stub return "UNKNOWN"; } + /** + * Notify other system services that set of active ifaces has changed. + */ + private void notifyIfacesChanged() { + try { + mStatsService.forceUpdateIfaces(); + } catch (Exception ignored) { + } + } + @Override public boolean addVpnAddress(String address, int prefixLength) { throwIfLockdownEnabled(); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 4eadff9..82afeed 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1075,6 +1075,13 @@ public final class ActivityManagerService extends ActivityManagerNative */ boolean mSafeMode; + /** + * If true, we are running under a test environment so will sample PSS from processes + * much more rapidly to try to collect better data when the tests are rapidly + * running through apps. + */ + boolean mTestPssMode = false; + String mDebugApp = null; boolean mWaitForDebugger = false; boolean mDebugTransient = false; @@ -1091,6 +1098,8 @@ public final class ActivityManagerService extends ActivityManagerNative int mProfileType = 0; String mOpenGlTraceApp = null; + final long[] mTmpLong = new long[1]; + static class ProcessChangeItem { static final int CHANGE_ACTIVITIES = 1<<0; static final int CHANGE_PROCESS_STATE = 1<<1; @@ -1802,7 +1811,7 @@ public final class ActivityManagerService extends ActivityManagerNative continue; } } - nativeTotalPss += Debug.getPss(st.pid, null); + nativeTotalPss += Debug.getPss(st.pid, null, null); } } memInfo.readMemInfo(); @@ -1815,48 +1824,40 @@ public final class ActivityManagerService extends ActivityManagerNative } } - int i = 0; int num = 0; long[] tmp = new long[1]; do { ProcessRecord proc; int procState; int pid; + long lastPssTime; synchronized (ActivityManagerService.this) { - if (i >= mPendingPssProcesses.size()) { - if (DEBUG_PSS) Slog.d(TAG, "Collected PSS of " + num + " of " + i + if (mPendingPssProcesses.size() <= 0) { + if (mTestPssMode || DEBUG_PSS) Slog.d(TAG, "Collected PSS of " + num + " processes in " + (SystemClock.uptimeMillis()-start) + "ms"); mPendingPssProcesses.clear(); return; } - proc = mPendingPssProcesses.get(i); + proc = mPendingPssProcesses.remove(0); procState = proc.pssProcState; - if (proc.thread != null && procState == proc.setProcState) { + lastPssTime = proc.lastPssTime; + if (proc.thread != null && procState == proc.setProcState + && (lastPssTime+ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE) + < SystemClock.uptimeMillis()) { pid = proc.pid; } else { proc = null; pid = 0; } - i++; } if (proc != null) { - long pss = Debug.getPss(pid, tmp); + long pss = Debug.getPss(pid, tmp, null); synchronized (ActivityManagerService.this) { - if (proc.thread != null && proc.setProcState == procState - && proc.pid == pid) { + if (pss != 0 && proc.thread != null && proc.setProcState == procState + && proc.pid == pid && proc.lastPssTime == lastPssTime) { num++; - proc.lastPssTime = SystemClock.uptimeMillis(); - proc.baseProcessTracker.addPss(pss, tmp[0], true, proc.pkgList); - if (DEBUG_PSS) Slog.d(TAG, "PSS of " + proc.toShortString() - + ": " + pss + " lastPss=" + proc.lastPss - + " state=" + ProcessList.makeProcStateString(procState)); - if (proc.initialIdlePss == 0) { - proc.initialIdlePss = pss; - } - proc.lastPss = pss; - if (procState >= ActivityManager.PROCESS_STATE_HOME) { - proc.lastCachedPss = pss; - } + recordPssSample(proc, procState, pss, tmp[0], + SystemClock.uptimeMillis()); } } } @@ -5420,7 +5421,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } long[] tmpUss = new long[1]; - pss[i] = Debug.getPss(pids[i], tmpUss); + pss[i] = Debug.getPss(pids[i], tmpUss, null); if (proc != null) { synchronized (this) { if (proc.thread != null && proc.setAdj == oomAdj) { @@ -10949,7 +10950,7 @@ public final class ActivityManagerService extends ActivityManagerNative proc.notCachedSinceIdle = true; proc.initialIdlePss = 0; proc.nextPssTime = ProcessList.computeNextPssTime(proc.curProcState, true, - isSleeping(), now); + mTestPssMode, isSleeping(), now); } } @@ -12919,7 +12920,8 @@ public final class ActivityManagerService extends ActivityManagerNative + PowerManagerInternal.wakefulnessToString(mWakefulness)); pw.println(" mSleeping=" + mSleeping + " mLockScreenShown=" + lockScreenShownToString()); - pw.println(" mShuttingDown=" + mShuttingDown + " mRunningVoice=" + mRunningVoice); + pw.println(" mShuttingDown=" + mShuttingDown + " mRunningVoice=" + mRunningVoice + + " mTestPssMode=" + mTestPssMode); } if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient || mOrigWaitForDebugger) { @@ -14014,7 +14016,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (dumpDetails || (!brief && !oomOnly)) { Debug.getMemoryInfo(pid, mi); } else { - mi.dalvikPss = (int)Debug.getPss(pid, tmpLong); + mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null); mi.dalvikPrivateDirty = (int)tmpLong[0]; } ActivityThread.dumpMemInfoTable(pw, mi, isCheckinRequest, dumpFullDetails, @@ -14076,7 +14078,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (dumpDetails || (!brief && !oomOnly)) { Debug.getMemoryInfo(pid, mi); } else { - mi.dalvikPss = (int)Debug.getPss(pid, tmpLong); + mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null); mi.dalvikPrivateDirty = (int)tmpLong[0]; } if (dumpDetails) { @@ -14152,6 +14154,7 @@ public final class ActivityManagerService extends ActivityManagerNative // If we are showing aggregations, also look for native processes to // include so that our aggregations are more accurate. updateCpuStatsNow(); + mi = null; synchronized (mProcessCpuTracker) { final int N = mProcessCpuTracker.countStats(); for (int i=0; i<N; i++) { @@ -14163,7 +14166,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (!brief && !oomOnly) { Debug.getMemoryInfo(st.pid, mi); } else { - mi.nativePss = (int)Debug.getPss(st.pid, tmpLong); + mi.nativePss = (int)Debug.getPss(st.pid, tmpLong, null); mi.nativePrivateDirty = (int)tmpLong[0]; } @@ -14354,7 +14357,7 @@ public final class ActivityManagerService extends ActivityManagerNative } private void appendBasicMemEntry(StringBuilder sb, int oomAdj, int procState, long pss, - String name) { + long memtrack, String name) { sb.append(" "); sb.append(ProcessList.makeOomAdjString(oomAdj)); sb.append(' '); @@ -14363,11 +14366,16 @@ public final class ActivityManagerService extends ActivityManagerNative ProcessList.appendRamKb(sb, pss); sb.append(" kB: "); sb.append(name); + if (memtrack > 0) { + sb.append(" ("); + sb.append(memtrack); + sb.append(" kB memtrack)"); + } } private void appendMemInfo(StringBuilder sb, ProcessMemInfo mi) { - appendBasicMemEntry(sb, mi.oomAdj, mi.procState, mi.pss, mi.name); - sb.append(" ("); + appendBasicMemEntry(sb, mi.oomAdj, mi.procState, mi.pss, mi.memtrack, mi.name); + sb.append(" (pid "); sb.append(mi.pid); sb.append(") "); sb.append(mi.adjType); @@ -14386,17 +14394,19 @@ public final class ActivityManagerService extends ActivityManagerNative infoMap.put(mi.pid, mi); } updateCpuStatsNow(); + long[] memtrackTmp = new long[1]; synchronized (mProcessCpuTracker) { 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); + long pss = Debug.getPss(st.pid, null, memtrackTmp); 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; + mi.memtrack = memtrackTmp[0]; memInfos.add(mi); } } @@ -14405,12 +14415,15 @@ public final class ActivityManagerService extends ActivityManagerNative } long totalPss = 0; + long totalMemtrack = 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); + mi.pss = Debug.getPss(mi.pid, null, memtrackTmp); + mi.memtrack = memtrackTmp[0]; } totalPss += mi.pss; + totalMemtrack += mi.memtrack; } Collections.sort(memInfos, new Comparator<ProcessMemInfo>() { @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) { @@ -14437,6 +14450,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean firstLine = true; int lastOomAdj = Integer.MIN_VALUE; long extraNativeRam = 0; + long extraNativeMemtrack = 0; long cachedPss = 0; for (int i=0, N=memInfos.size(); i<N; i++) { ProcessMemInfo mi = memInfos.get(i); @@ -14487,18 +14501,19 @@ public final class ActivityManagerService extends ActivityManagerNative appendMemInfo(fullNativeBuilder, mi); if (mi.oomAdj == ProcessList.NATIVE_ADJ) { - // The short form only has native processes that are >= 1MB. - if (mi.pss >= 1000) { + // The short form only has native processes that are >= 512K. + if (mi.pss >= 512) { appendMemInfo(shortNativeBuilder, mi); } else { extraNativeRam += mi.pss; + extraNativeMemtrack += mi.memtrack; } } else { // Short form has all other details, but if we have collected RAM // from smaller native processes let's dump a summary of that. if (extraNativeRam > 0) { appendBasicMemEntry(shortNativeBuilder, ProcessList.NATIVE_ADJ, - -1, extraNativeRam, "(Other native)"); + -1, extraNativeRam, extraNativeMemtrack, "(Other native)"); shortNativeBuilder.append('\n'); extraNativeRam = 0; } @@ -14508,7 +14523,14 @@ public final class ActivityManagerService extends ActivityManagerNative fullJavaBuilder.append(" "); ProcessList.appendRamKb(fullJavaBuilder, totalPss); - fullJavaBuilder.append(" kB: TOTAL\n"); + fullJavaBuilder.append(" kB: TOTAL"); + if (totalMemtrack > 0) { + fullJavaBuilder.append(" ("); + fullJavaBuilder.append(totalMemtrack); + fullJavaBuilder.append(" kB memtrack)"); + } else { + } + fullJavaBuilder.append("\n"); MemInfoReader memInfo = new MemInfoReader(); memInfo.readMemInfo(); @@ -15680,11 +15702,13 @@ public final class ActivityManagerService extends ActivityManagerNative true, ALLOW_NON_FULL, "broadcast", callerPackage); // Make sure that the user who is receiving this broadcast is running. - // If not, we will just skip it. + // If not, we will just skip it. Make an exception for shutdown broadcasts + // and upgrade steps. if (userId != UserHandle.USER_ALL && !isUserRunningLocked(userId, false)) { - if (callingUid != Process.SYSTEM_UID || (intent.getFlags() - & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) { + if ((callingUid != Process.SYSTEM_UID + || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) + && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) { Slog.w(TAG, "Skipping broadcast of " + intent + ": user " + userId + " is stopped"); return ActivityManager.BROADCAST_FAILED_USER_STOPPED; @@ -17336,6 +17360,24 @@ public final class ActivityManagerService extends ActivityManagerNative } /** + * Record new PSS sample for a process. + */ + void recordPssSample(ProcessRecord proc, int procState, long pss, long uss, long now) { + proc.lastPssTime = now; + proc.baseProcessTracker.addPss(pss, uss, true, proc.pkgList); + if (DEBUG_PSS) Slog.d(TAG, "PSS of " + proc.toShortString() + + ": " + pss + " lastPss=" + proc.lastPss + + " state=" + ProcessList.makeProcStateString(procState)); + if (proc.initialIdlePss == 0) { + proc.initialIdlePss = pss; + } + proc.lastPss = pss; + if (procState >= ActivityManager.PROCESS_STATE_HOME) { + proc.lastCachedPss = pss; + } + } + + /** * Schedule PSS collection of a process. */ void requestPssLocked(ProcessRecord proc, int procState) { @@ -17370,13 +17412,24 @@ public final class ActivityManagerService extends ActivityManagerNative if (memLowered || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) { app.pssProcState = app.setProcState; app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true, - isSleeping(), now); + mTestPssMode, isSleeping(), now); mPendingPssProcesses.add(app); } } mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG); } + public void setTestPssMode(boolean enabled) { + synchronized (this) { + mTestPssMode = enabled; + if (enabled) { + // Whenever we enable the mode, we want to take a snapshot all of current + // process mem use. + requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, true); + } + } + } + /** * Ask a given process to GC right now. */ @@ -17673,19 +17726,33 @@ public final class ActivityManagerService extends ActivityManagerNative } if (app.setProcState < 0 || ProcessList.procStatesDifferForMem(app.curProcState, app.setProcState)) { + if (false && mTestPssMode && app.setProcState >= 0 && app.lastStateTime <= (now-200)) { + // Experimental code to more aggressively collect pss while + // running test... the problem is that this tends to collect + // the data right when a process is transitioning between process + // states, which well tend to give noisy data. + long start = SystemClock.uptimeMillis(); + long pss = Debug.getPss(app.pid, mTmpLong, null); + recordPssSample(app, app.curProcState, pss, mTmpLong[0], now); + mPendingPssProcesses.remove(app); + Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState + + " to " + app.curProcState + ": " + + (SystemClock.uptimeMillis()-start) + "ms"); + } app.lastStateTime = now; app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true, - isSleeping(), now); + mTestPssMode, isSleeping(), now); if (DEBUG_PSS) Slog.d(TAG, "Process state change from " + ProcessList.makeProcStateString(app.setProcState) + " to " + ProcessList.makeProcStateString(app.curProcState) + " next pss in " + (app.nextPssTime-now) + ": " + app); } else { if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL) - && now > (app.lastStateTime+ProcessList.PSS_MIN_TIME_FROM_STATE_CHANGE))) { + && now > (app.lastStateTime+ProcessList.minTimeFromStateChange( + mTestPssMode)))) { requestPssLocked(app, app.setProcState); app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false, - isSleeping(), now); + mTestPssMode, isSleeping(), now); } else if (false && DEBUG_PSS) { Slog.d(TAG, "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now)); } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index d98f03c..efed0b9 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -222,13 +222,6 @@ final class ActivityStack { long mLaunchStartTime = 0; long mFullyDrawnStartTime = 0; - /** - * Save the most recent screenshot for reuse. This keeps Recents from taking two identical - * screenshots, one for the Recents thumbnail and one for the pauseActivity thumbnail. - */ - private ActivityRecord mLastScreenshotActivity = null; - private Bitmap mLastScreenshotBitmap = null; - int mCurrentUser; final int mStackId; @@ -741,18 +734,6 @@ final class ActivityStack { } } - /** - * This resets the saved state from the last screenshot, forcing a new screenshot to be taken - * again when requested. - */ - private void invalidateLastScreenshot() { - mLastScreenshotActivity = null; - if (mLastScreenshotBitmap != null) { - mLastScreenshotBitmap.recycle(); - } - mLastScreenshotBitmap = null; - } - public final Bitmap screenshotActivities(ActivityRecord who) { if (DEBUG_SCREENSHOTS) Slog.d(TAG, "screenshotActivities: " + who); if (who.noDisplay) { @@ -762,30 +743,17 @@ final class ActivityStack { if (isHomeStack()) { // This is an optimization -- since we never show Home or Recents within Recents itself, - // we can just go ahead and skip taking the screenshot if this is the home stack. In - // the case where the most recent task is not the task that was supplied, then the stack - // has changed, so invalidate the last screenshot(). - invalidateLastScreenshot(); - if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tIs Home stack? " + isHomeStack()); + // we can just go ahead and skip taking the screenshot if this is the home stack. + if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tHome stack"); return null; } int w = mService.mThumbnailWidth; int h = mService.mThumbnailHeight; if (w > 0) { - if (who != mLastScreenshotActivity || mLastScreenshotBitmap == null - || mLastScreenshotActivity.state == ActivityState.RESUMED - || mLastScreenshotBitmap.getWidth() != w - || mLastScreenshotBitmap.getHeight() != h) { - if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tUpdating screenshot"); - mLastScreenshotActivity = who; - mLastScreenshotBitmap = mWindowManager.screenshotApplications( - who.appToken, Display.DEFAULT_DISPLAY, w, h, SCREENSHOT_FORCE_565); - } - if (mLastScreenshotBitmap != null) { - if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tReusing last screenshot"); - return mLastScreenshotBitmap.copy(mLastScreenshotBitmap.getConfig(), true); - } + if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tTaking screenshot"); + return mWindowManager.screenshotApplications(who.appToken, Display.DEFAULT_DISPLAY, + w, h, SCREENSHOT_FORCE_565); } Slog.e(TAG, "Invalid thumbnail dimensions: " + w + "x" + h); return null; @@ -1103,11 +1071,6 @@ final class ActivityStack { next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process } - // If we are resuming the activity that we had last screenshotted, then we know it will be - // updated, so invalidate the last screenshot to ensure we take a fresh one when requested - if (next == mLastScreenshotActivity) { - invalidateLastScreenshot(); - } next.returningOptions = null; if (mActivityContainer.mActivityDisplay.mVisibleBehindActivity == next) { @@ -1824,9 +1787,6 @@ final class ActivityStack { // Do over! mStackSupervisor.scheduleResumeTopActivities(); } - if (next == mLastScreenshotActivity) { - invalidateLastScreenshot(); - } if (mStackSupervisor.reportResumedActivityLocked(next)) { mNoAnimActivities.clear(); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index cdc5134..4ac6684 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -411,7 +411,10 @@ final class ProcessList { sb.append(ramKb); } - // The minimum amount of time after a state change it is safe ro collect PSS. + // How long after a state change that it is safe to collect PSS without it being dirty. + public static final int PSS_SAFE_TIME_FROM_STATE_CHANGE = 1000; + + // The minimum time interval after a state change it is safe to collect PSS. public static final int PSS_MIN_TIME_FROM_STATE_CHANGE = 15*1000; // The maximum amount of time we want to go between PSS collections. @@ -441,6 +444,21 @@ final class ProcessList { // The amount of time until PSS when a cached process stays in the same state. private static final int PSS_SAME_CACHED_INTERVAL = 30*60*1000; + // The minimum time interval after a state change it is safe to collect PSS. + public static final int PSS_TEST_MIN_TIME_FROM_STATE_CHANGE = 10*1000; + + // The amount of time during testing until PSS when a process first becomes top. + private static final int PSS_TEST_FIRST_TOP_INTERVAL = 3*1000; + + // The amount of time during testing until PSS when a process first goes into the background. + private static final int PSS_TEST_FIRST_BACKGROUND_INTERVAL = 5*1000; + + // The amount of time during testing until PSS when an important process stays in same state. + private static final int PSS_TEST_SAME_IMPORTANT_INTERVAL = 10*1000; + + // The amount of time during testing until PSS when a background process stays in same state. + private static final int PSS_TEST_SAME_BACKGROUND_INTERVAL = 15*1000; + public static final int PROC_MEM_PERSISTENT = 0; public static final int PROC_MEM_TOP = 1; public static final int PROC_MEM_IMPORTANT = 2; @@ -498,16 +516,54 @@ final class ProcessList { PSS_SAME_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_EMPTY }; + private static final long[] sTestFirstAwakePssTimes = new long[] { + PSS_TEST_FIRST_TOP_INTERVAL, // ActivityManager.PROCESS_STATE_PERSISTENT + PSS_TEST_FIRST_TOP_INTERVAL, // ActivityManager.PROCESS_STATE_PERSISTENT_UI + PSS_TEST_FIRST_TOP_INTERVAL, // ActivityManager.PROCESS_STATE_TOP + PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND + PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND + PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_BACKUP + PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT + PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_SERVICE + PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_RECEIVER + PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_HOME + PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY + PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY + PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT + PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_EMPTY + }; + + private static final long[] sTestSameAwakePssTimes = new long[] { + PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_PERSISTENT + PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_PERSISTENT_UI + PSS_TEST_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_TOP + PSS_TEST_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND + PSS_TEST_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND + PSS_TEST_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_BACKUP + PSS_TEST_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT + PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_SERVICE + PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_RECEIVER + PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_HOME + PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY + PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY + PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT + PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_EMPTY + }; + public static boolean procStatesDifferForMem(int procState1, int procState2) { return sProcStateToProcMem[procState1] != sProcStateToProcMem[procState2]; } - public static long computeNextPssTime(int procState, boolean first, boolean sleeping, - long now) { - final long[] table = sleeping + public static long minTimeFromStateChange(boolean test) { + return test ? PSS_TEST_MIN_TIME_FROM_STATE_CHANGE : PSS_MIN_TIME_FROM_STATE_CHANGE; + } + + public static long computeNextPssTime(int procState, boolean first, boolean test, + boolean sleeping, long now) { + final long[] table = test ? (first - ? sFirstAwakePssTimes - : sSameAwakePssTimes) + ? sTestFirstAwakePssTimes + : sTestSameAwakePssTimes) : (first ? sFirstAwakePssTimes : sSameAwakePssTimes); diff --git a/services/core/java/com/android/server/am/ProcessMemInfo.java b/services/core/java/com/android/server/am/ProcessMemInfo.java index c94694e..83d29e2 100644 --- a/services/core/java/com/android/server/am/ProcessMemInfo.java +++ b/services/core/java/com/android/server/am/ProcessMemInfo.java @@ -24,6 +24,7 @@ public class ProcessMemInfo { final String adjType; final String adjReason; long pss; + long memtrack; public ProcessMemInfo(String _name, int _pid, int _oomAdj, int _procState, String _adjType, String _adjReason) { diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java index d05910b..55aec65 100644 --- a/services/core/java/com/android/server/am/ProcessStatsService.java +++ b/services/core/java/com/android/server/am/ProcessStatsService.java @@ -583,7 +583,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]"); pw.println(" [--details] [--full-details] [--current] [--hours N] [--last N]"); pw.println(" [--max N] --active] [--commit] [--reset] [--clear] [--write] [-h]"); - pw.println(" [<package.name>]"); + pw.println(" [--start-testing] [--stop-testing] [<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."); @@ -603,6 +603,8 @@ public final class ProcessStatsService extends IProcessStats.Stub { pw.println(" --clear: clear all stats; does both --reset and deletes old stats."); pw.println(" --write: write current in-memory stats to disk."); pw.println(" --read: replace current stats with last-written stats."); + pw.println(" --start-testing: clear all stats and starting high frequency pss sampling."); + pw.println(" --stop-testing: stop high frequency pss sampling."); pw.println(" -a: print everything."); pw.println(" -h: print this help text."); pw.println(" <package.name>: optional name of package to filter output by."); @@ -636,6 +638,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { boolean dumpDetails = false; boolean dumpFullDetails = false; boolean dumpAll = false; + boolean quit = false; int aggregateHours = 0; int lastIndex = 0; int maxNum = 2; @@ -761,14 +764,14 @@ public final class ProcessStatsService extends IProcessStats.Stub { mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE; writeStateLocked(true, true); pw.println("Process stats committed."); + quit = true; } - return; } else if ("--reset".equals(arg)) { synchronized (mAm) { mProcessStats.resetSafely(); pw.println("Process stats reset."); + quit = true; } - return; } else if ("--clear".equals(arg)) { synchronized (mAm) { mProcessStats.resetSafely(); @@ -779,20 +782,32 @@ public final class ProcessStatsService extends IProcessStats.Stub { } } pw.println("All process stats cleared."); + quit = true; } - return; } else if ("--write".equals(arg)) { synchronized (mAm) { writeStateSyncLocked(); pw.println("Process stats written."); + quit = true; } - return; } else if ("--read".equals(arg)) { synchronized (mAm) { readLocked(mProcessStats, mFile); pw.println("Process stats read."); + quit = true; + } + } else if ("--start-testing".equals(arg)) { + synchronized (mAm) { + mAm.setTestPssMode(true); + pw.println("Started high frequency sampling."); + quit = true; + } + } else if ("--stop-testing".equals(arg)) { + synchronized (mAm) { + mAm.setTestPssMode(false); + pw.println("Stopped high frequency sampling."); + quit = true; } - return; } else if ("-h".equals(arg)) { dumpHelp(pw); return; @@ -815,6 +830,10 @@ public final class ProcessStatsService extends IProcessStats.Stub { } } + if (quit) { + return; + } + if (isCsv) { pw.print("Processes running summed over"); if (!csvSepScreenStats) { diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 487040c..62de534 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -1324,12 +1324,17 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @ServiceThreadOnly final void addCecDevice(HdmiDeviceInfo info) { assertRunOnServiceThread(); - addDeviceInfo(info); + HdmiDeviceInfo old = addDeviceInfo(info); if (info.getLogicalAddress() == mAddress) { // The addition of TV device itself should not be notified. return; } - invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_ADD_DEVICE); + if (old == null) { + invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_ADD_DEVICE); + } else if (!old.equals(info)) { + invokeDeviceEventListener(old, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE); + invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_ADD_DEVICE); + } } /** diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index cf19416..2be591b 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -120,7 +120,9 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.text.format.Formatter; import android.text.format.Time; import android.util.ArrayMap; @@ -136,16 +138,17 @@ import android.util.SparseIntArray; import android.util.TrustedTime; import android.util.Xml; +import libcore.io.IoUtils; + import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.SystemConfig; import com.google.android.collect.Lists; -import libcore.io.IoUtils; - import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -160,7 +163,6 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Objects; /** * Service that maintains low-level network policy rules, using @@ -253,38 +255,38 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private final boolean mSuppressDefaultPolicy; /** Defined network policies. */ - final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap< - NetworkTemplate, NetworkPolicy>(); + final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<>(); /** Currently active network rules for ifaces. */ - private final ArrayMap<NetworkPolicy, String[]> mNetworkRules = new ArrayMap< - NetworkPolicy, String[]>(); + final ArrayMap<NetworkPolicy, String[]> mNetworkRules = new ArrayMap<>(); /** Defined UID policies. */ final SparseIntArray mUidPolicy = new SparseIntArray(); /** Currently derived rules for each UID. */ - private final SparseIntArray mUidRules = new SparseIntArray(); + final SparseIntArray mUidRules = new SparseIntArray(); - /** UIDs that have been white-listed to always be able to have network access in - * power save mode. */ + /** + * UIDs that have been white-listed to always be able to have network access + * in power save mode. + */ private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray(); /** Set of ifaces that are metered. */ - private ArraySet<String> mMeteredIfaces = new ArraySet<String>(); + private ArraySet<String> mMeteredIfaces = new ArraySet<>(); /** Set of over-limit templates that have been notified. */ - private final ArraySet<NetworkTemplate> mOverLimitNotified = new ArraySet<NetworkTemplate>(); + private final ArraySet<NetworkTemplate> mOverLimitNotified = new ArraySet<>(); /** Set of currently active {@link Notification} tags. */ private final ArraySet<String> mActiveNotifs = new ArraySet<String>(); /** Foreground at both UID and PID granularity. */ - private final SparseIntArray mUidState = new SparseIntArray(); - final SparseArray<SparseIntArray> mUidPidState = new SparseArray<SparseIntArray>(); + final SparseIntArray mUidState = new SparseIntArray(); + final SparseArray<SparseIntArray> mUidPidState = new SparseArray<>(); /** The current maximum process state that we are considering to be foreground. */ private int mCurForegroundState = ActivityManager.PROCESS_STATE_TOP; - private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList< - INetworkPolicyListener>(); + private final RemoteCallbackList<INetworkPolicyListener> + mListeners = new RemoteCallbackList<>(); final Handler mHandler; @@ -740,21 +742,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * data connection status. */ private boolean isTemplateRelevant(NetworkTemplate template) { - final TelephonyManager tele = TelephonyManager.from(mContext); - - switch (template.getMatchRule()) { - case MATCH_MOBILE_3G_LOWER: - case MATCH_MOBILE_4G: - case MATCH_MOBILE_ALL: - // mobile templates are relevant when SIM is ready and - // subscriberId matches. - if (tele.getSimState() == SIM_STATE_READY) { - return Objects.equals(tele.getSubscriberId(), template.getSubscriberId()); - } else { - return false; + if (template.isMatchRuleMobile()) { + final TelephonyManager tele = TelephonyManager.from(mContext); + final SubscriptionManager sub = SubscriptionManager.from(mContext); + + // Mobile template is relevant when any active subscriber matches + final int[] subIds = sub.getActiveSubscriptionIdList(); + for (int subId : subIds) { + final String subscriberId = tele.getSubscriberId(subId); + final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE, + TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false); + if (template.matches(probeIdent)) { + return true; } + } + return false; + } else { + return true; } - return true; } /** @@ -961,6 +966,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { maybeRefreshTrustedTime(); synchronized (mRulesLock) { ensureActiveMobilePolicyLocked(); + normalizePoliciesLocked(); updateNetworkEnabledLocked(); updateNetworkRulesLocked(); updateNotificationsLocked(); @@ -1001,33 +1007,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } /** - * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)} - * for the given {@link NetworkTemplate}. + * Proactively disable networks that match the given + * {@link NetworkTemplate}. */ private void setNetworkTemplateEnabled(NetworkTemplate template, boolean enabled) { - final TelephonyManager tele = TelephonyManager.from(mContext); - - switch (template.getMatchRule()) { - case MATCH_MOBILE_3G_LOWER: - case MATCH_MOBILE_4G: - case MATCH_MOBILE_ALL: - // TODO: offer more granular control over radio states once - // 4965893 is available. - if (tele.getSimState() == SIM_STATE_READY - && Objects.equals(tele.getSubscriberId(), template.getSubscriberId())) { - setPolicyDataEnable(TYPE_MOBILE, enabled); - setPolicyDataEnable(TYPE_WIMAX, enabled); - } - break; - case MATCH_WIFI: - setPolicyDataEnable(TYPE_WIFI, enabled); - break; - case MATCH_ETHERNET: - setPolicyDataEnable(TYPE_ETHERNET, enabled); - break; - default: - throw new IllegalArgumentException("unexpected template"); - } + // TODO: reach into ConnectivityManager to proactively disable bringing + // up this network, since we know that traffic will be blocked. } /** @@ -1036,7 +1021,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * remaining quota based on usage cycle and historical stats. */ void updateNetworkRulesLocked() { - if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); + if (LOGV) Slog.v(TAG, "updateNetworkRulesLocked()"); final NetworkState[] states; try { @@ -1203,42 +1188,47 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (mSuppressDefaultPolicy) return; final TelephonyManager tele = TelephonyManager.from(mContext); + final SubscriptionManager sub = SubscriptionManager.from(mContext); - // avoid creating policy when SIM isn't ready - if (tele.getSimState() != SIM_STATE_READY) return; - - final String subscriberId = tele.getSubscriberId(); - final NetworkIdentity probeIdent = new NetworkIdentity( - TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false); + final int[] subIds = sub.getActiveSubscriptionIdList(); + for (int subId : subIds) { + final String subscriberId = tele.getSubscriberId(subId); + ensureActiveMobilePolicyLocked(subscriberId); + } + } - // examine to see if any policy is defined for active mobile - boolean mobileDefined = false; - for (int i = mNetworkPolicy.size()-1; i >= 0; i--) { - if (mNetworkPolicy.valueAt(i).template.matches(probeIdent)) { - mobileDefined = true; - break; + private void ensureActiveMobilePolicyLocked(String subscriberId) { + // Poke around to see if we already have a policy + final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE, + TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false); + for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) { + final NetworkTemplate template = mNetworkPolicy.keyAt(i); + if (template.matches(probeIdent)) { + if (LOGD) { + Slog.d(TAG, "Found template " + template + " which matches subscriber " + + NetworkIdentity.scrubSubscriberId(subscriberId)); + } + return; } } - if (!mobileDefined) { - Slog.i(TAG, "no policy for active mobile network; generating default policy"); + Slog.i(TAG, "No policy for subscriber " + NetworkIdentity.scrubSubscriberId(subscriberId) + + "; generating default policy"); - // build default mobile policy, and assume usage cycle starts today - final long warningBytes = mContext.getResources().getInteger( - com.android.internal.R.integer.config_networkPolicyDefaultWarning) - * MB_IN_BYTES; + // Build default mobile policy, and assume usage cycle starts today + final long warningBytes = mContext.getResources().getInteger( + com.android.internal.R.integer.config_networkPolicyDefaultWarning) * MB_IN_BYTES; - final Time time = new Time(); - time.setToNow(); + final Time time = new Time(); + time.setToNow(); - final int cycleDay = time.monthDay; - final String cycleTimezone = time.timezone; + final int cycleDay = time.monthDay; + final String cycleTimezone = time.timezone; - final NetworkTemplate template = buildTemplateMobileAll(subscriberId); - final NetworkPolicy policy = new NetworkPolicy(template, cycleDay, cycleTimezone, - warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, true); - addNetworkPolicyLocked(policy); - } + final NetworkTemplate template = buildTemplateMobileAll(subscriberId); + final NetworkPolicy policy = new NetworkPolicy(template, cycleDay, cycleTimezone, + warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, true); + addNetworkPolicyLocked(policy); } private void readPolicyLocked() { @@ -1321,8 +1311,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { inferred = false; } - final NetworkTemplate template = new NetworkTemplate( - networkTemplate, subscriberId, networkId); + final NetworkTemplate template = new NetworkTemplate(networkTemplate, + subscriberId, networkId); mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, cycleTimezone, warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze, metered, inferred)); @@ -1593,11 +1583,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { maybeRefreshTrustedTime(); synchronized (mRulesLock) { - mNetworkPolicy.clear(); - for (NetworkPolicy policy : policies) { - mNetworkPolicy.put(policy.template, policy); - } - + normalizePoliciesLocked(policies); updateNetworkEnabledLocked(); updateNetworkRulesLocked(); updateNotificationsLocked(); @@ -1606,12 +1592,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } void addNetworkPolicyLocked(NetworkPolicy policy) { - mNetworkPolicy.put(policy.template, policy); - - updateNetworkEnabledLocked(); - updateNetworkRulesLocked(); - updateNotificationsLocked(); - writePolicyLocked(); + NetworkPolicy[] policies = getNetworkPolicies(); + policies = ArrayUtils.appendElement(NetworkPolicy.class, policies, policy); + setNetworkPolicies(policies); } @Override @@ -1620,7 +1603,35 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG); synchronized (mRulesLock) { - return mNetworkPolicy.values().toArray(new NetworkPolicy[mNetworkPolicy.size()]); + final int size = mNetworkPolicy.size(); + final NetworkPolicy[] policies = new NetworkPolicy[size]; + for (int i = 0; i < size; i++) { + policies[i] = mNetworkPolicy.valueAt(i); + } + return policies; + } + } + + private void normalizePoliciesLocked() { + normalizePoliciesLocked(getNetworkPolicies()); + } + + private void normalizePoliciesLocked(NetworkPolicy[] policies) { + final TelephonyManager tele = TelephonyManager.from(mContext); + final String[] merged = tele.getMergedSubscriberIds(); + + mNetworkPolicy.clear(); + for (NetworkPolicy policy : policies) { + // When two normalized templates conflict, prefer the most + // restrictive policy + policy.template = NetworkTemplate.normalize(policy.template, merged); + final NetworkPolicy existing = mNetworkPolicy.get(policy.template); + if (existing == null || existing.compareTo(policy) > 0) { + if (existing != null) { + Slog.d(TAG, "Normalization replaced " + existing + " with " + policy); + } + mNetworkPolicy.put(policy.template, policy); + } } } @@ -1657,6 +1668,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { throw new IllegalArgumentException("unexpected type"); } + normalizePoliciesLocked(); updateNetworkEnabledLocked(); updateNetworkRulesLocked(); updateNotificationsLocked(); @@ -1784,6 +1796,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mNetworkPolicy.valueAt(i).clearSnooze(); } + normalizePoliciesLocked(); updateNetworkEnabledLocked(); updateNetworkRulesLocked(); updateNotificationsLocked(); @@ -1976,6 +1989,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // If the set of restricted networks may have changed, re-evaluate those. if (restrictedNetworksChanged) { + normalizePoliciesLocked(); updateNetworkRulesLocked(); } } @@ -2162,17 +2176,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - /** - * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)}. - */ - private void setPolicyDataEnable(int networkType, boolean enabled) { - try { - mConnManager.setPolicyDataEnable(networkType, enabled); - } catch (RemoteException e) { - // ignored; service lives in system_server - } - } - private long getTotalBytes(NetworkTemplate template, long start, long end) { try { return mNetworkStats.getNetworkTotalBytes(template, start, end); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 61f9a26..856a076 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -26,9 +26,7 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; -import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.ConnectivityManager.isNetworkTypeMobile; -import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; @@ -55,8 +53,6 @@ import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES; import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE; -import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE; -import static android.telephony.PhoneStateListener.LISTEN_NONE; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; @@ -102,7 +98,6 @@ import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.Global; -import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.text.format.DateUtils; import android.util.ArrayMap; @@ -308,10 +303,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { bootstrapStatsLocked(); } - // watch for network interfaces to be claimed - final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE); - mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler); - // watch for tethering changes final IntentFilter tetherFilter = new IntentFilter(ACTION_TETHER_STATE_CHANGED); mContext.registerReceiver(mTetherReceiver, tetherFilter, null, mHandler); @@ -338,12 +329,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // ignored; service lives in system_server } - // watch for networkType changes that aren't broadcast through - // CONNECTIVITY_ACTION_IMMEDIATE above. - if (!COMBINE_SUBTYPE_ENABLED) { - mTeleManager.listen(mPhoneListener, LISTEN_DATA_CONNECTION_STATE); - } - registerPollAlarmLocked(); registerGlobalAlert(); } @@ -358,16 +343,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private void shutdownLocked() { - mContext.unregisterReceiver(mConnReceiver); mContext.unregisterReceiver(mTetherReceiver); mContext.unregisterReceiver(mPollReceiver); mContext.unregisterReceiver(mRemovedReceiver); mContext.unregisterReceiver(mShutdownReceiver); - if (!COMBINE_SUBTYPE_ENABLED) { - mTeleManager.listen(mPhoneListener, LISTEN_NONE); - } - final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); @@ -620,6 +600,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override + public void forceUpdateIfaces() { + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + assertBandwidthControlEnabled(); + + final long token = Binder.clearCallingIdentity(); + try { + updateIfaces(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override public void forceUpdate() { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); assertBandwidthControlEnabled(); @@ -676,20 +669,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Receiver that watches for {@link IConnectivityManager} to claim network - * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()} - * with mobile interfaces. - */ - private BroadcastReceiver mConnReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // on background handler thread, and verified CONNECTIVITY_INTERNAL - // permission above. - updateIfaces(); - } - }; - - /** * Receiver that watches for {@link Tethering} to claim interface pairs. */ private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() { @@ -784,35 +763,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; - private int mLastPhoneState = TelephonyManager.DATA_UNKNOWN; - private int mLastPhoneNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; - - /** - * Receiver that watches for {@link TelephonyManager} changes, such as - * transitioning between network types. - */ - private PhoneStateListener mPhoneListener = new PhoneStateListener() { - @Override - public void onDataConnectionStateChanged(int state, int networkType) { - final boolean stateChanged = state != mLastPhoneState; - final boolean networkTypeChanged = networkType != mLastPhoneNetworkType; - - if (networkTypeChanged && !stateChanged) { - // networkType changed without a state change, which means we - // need to roll our own update. delay long enough for - // ConnectivityManager to process. - // TODO: add direct event to ConnectivityService instead of - // relying on this delay. - if (LOGV) Slog.v(TAG, "triggering delayed updateIfaces()"); - mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS); - } - - mLastPhoneState = state; - mLastPhoneNetworkType = networkType; - } - }; - private void updateIfaces() { synchronized (mStatsLock) { mWakeLock.acquire(); diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java index 5de1a64..64d77c1 100644 --- a/services/core/java/com/android/server/notification/ConditionProviders.java +++ b/services/core/java/com/android/server/notification/ConditionProviders.java @@ -50,10 +50,11 @@ public class ConditionProviders extends ManagedServices { private final ArrayMap<IBinder, IConditionListener> mListeners = new ArrayMap<IBinder, IConditionListener>(); private final ArrayList<ConditionRecord> mRecords = new ArrayList<ConditionRecord>(); - private final CountdownConditionProvider mCountdown = new CountdownConditionProvider(); + private final ArraySet<String> mSystemConditionProviders; + private final CountdownConditionProvider mCountdown; + private final DowntimeConditionProvider mDowntime; + private final NextAlarmConditionProvider mNextAlarm; private final NextAlarmTracker mNextAlarmTracker; - private final DowntimeConditionProvider mDowntime = new DowntimeConditionProvider(); - private final NextAlarmConditionProvider mNextAlarm = new NextAlarmConditionProvider(); private Condition mExitCondition; private ComponentName mExitConditionComponent; @@ -63,8 +64,22 @@ public class ConditionProviders extends ManagedServices { super(context, handler, new Object(), userProfiles); mZenModeHelper = zenModeHelper; mZenModeHelper.addCallback(new ZenModeHelperCallback()); + mSystemConditionProviders = safeSet(PropConfig.getStringArray(mContext, + "system.condition.providers", + R.array.config_system_condition_providers)); + final boolean countdown = mSystemConditionProviders.contains(ZenModeConfig.COUNTDOWN_PATH); + final boolean downtime = mSystemConditionProviders.contains(ZenModeConfig.DOWNTIME_PATH); + final boolean nextAlarm = mSystemConditionProviders.contains(ZenModeConfig.NEXT_ALARM_PATH); + mNextAlarmTracker = (downtime || nextAlarm) ? new NextAlarmTracker(mContext) : null; + mCountdown = countdown ? new CountdownConditionProvider() : null; + mDowntime = downtime ? new DowntimeConditionProvider(this, mNextAlarmTracker, + mZenModeHelper) : null; + mNextAlarm = nextAlarm ? new NextAlarmConditionProvider(mNextAlarmTracker) : null; loadZenConfig(); - mNextAlarmTracker = new NextAlarmTracker(context); + } + + public boolean isSystemConditionProviderEnabled(String path) { + return mSystemConditionProviders.contains(path); } @Override @@ -100,10 +115,19 @@ public class ConditionProviders extends ManagedServices { } } } - mCountdown.dump(pw, filter); - mDowntime.dump(pw, filter); - mNextAlarm.dump(pw, filter); - mNextAlarmTracker.dump(pw, filter); + pw.print(" mSystemConditionProviders: "); pw.println(mSystemConditionProviders); + if (mCountdown != null) { + mCountdown.dump(pw, filter); + } + if (mDowntime != null) { + mDowntime.dump(pw, filter); + } + if (mNextAlarm != null) { + mNextAlarm.dump(pw, filter); + } + if (mNextAlarmTracker != null) { + mNextAlarmTracker.dump(pw, filter); + } } @Override @@ -114,24 +138,32 @@ public class ConditionProviders extends ManagedServices { @Override public void onBootPhaseAppsCanStart() { super.onBootPhaseAppsCanStart(); - mNextAlarmTracker.init(); - mCountdown.attachBase(mContext); - registerService(mCountdown.asInterface(), CountdownConditionProvider.COMPONENT, - UserHandle.USER_OWNER); - mDowntime.attachBase(mContext); - registerService(mDowntime.asInterface(), DowntimeConditionProvider.COMPONENT, - UserHandle.USER_OWNER); - mDowntime.setCallback(new DowntimeCallback()); - mNextAlarm.attachBase(mContext); - registerService(mNextAlarm.asInterface(), NextAlarmConditionProvider.COMPONENT, - UserHandle.USER_OWNER); - mNextAlarm.setCallback(new NextAlarmCallback()); + if (mNextAlarmTracker != null) { + mNextAlarmTracker.init(); + } + if (mCountdown != null) { + mCountdown.attachBase(mContext); + registerService(mCountdown.asInterface(), CountdownConditionProvider.COMPONENT, + UserHandle.USER_OWNER); + } + if (mDowntime != null) { + mDowntime.attachBase(mContext); + registerService(mDowntime.asInterface(), DowntimeConditionProvider.COMPONENT, + UserHandle.USER_OWNER); + } + if (mNextAlarm != null) { + mNextAlarm.attachBase(mContext); + registerService(mNextAlarm.asInterface(), NextAlarmConditionProvider.COMPONENT, + UserHandle.USER_OWNER); + } } @Override public void onUserSwitched() { super.onUserSwitched(); - mNextAlarmTracker.onUserSwitched(); + if (mNextAlarmTracker != null) { + mNextAlarmTracker.onUserSwitched(); + } } @Override @@ -171,6 +203,7 @@ public class ConditionProviders extends ManagedServices { if (!r.component.equals(removed.component)) continue; if (r.isManual) { // removing the current manual condition, exit zen + onManualConditionClearing(); mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "manualServiceRemoved"); } if (r.isAutomatic) { @@ -273,6 +306,7 @@ public class ConditionProviders extends ManagedServices { } else if (DEBUG) { Slog.d(TAG, "Exit zen: manual condition false: " + c); } + onManualConditionClearing(); mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF, "manualConditionExit"); unsubscribeLocked(r); @@ -304,28 +338,28 @@ public class ConditionProviders extends ManagedServices { } } + private void ensureRecordExists(Condition condition, IConditionProvider provider, + ComponentName component) { + // constructed by convention, make sure the record exists... + final ConditionRecord r = getRecordLocked(condition.id, component); + if (r.info == null) { + // ... and is associated with the in-process service + r.info = checkServiceTokenLocked(provider); + } + } + public void setZenModeCondition(Condition condition, String reason) { - if (DEBUG) Slog.d(TAG, "setZenModeCondition " + condition); + if (DEBUG) Slog.d(TAG, "setZenModeCondition " + condition + " reason=" + reason); synchronized(mMutex) { ComponentName conditionComponent = null; if (condition != null) { - if (ZenModeConfig.isValidCountdownConditionId(condition.id)) { - // constructed by the client, make sure the record exists... - final ConditionRecord r = getRecordLocked(condition.id, + if (mCountdown != null && ZenModeConfig.isValidCountdownConditionId(condition.id)) { + ensureRecordExists(condition, mCountdown.asInterface(), CountdownConditionProvider.COMPONENT); - if (r.info == null) { - // ... and is associated with the in-process service - r.info = checkServiceTokenLocked(mCountdown.asInterface()); - } } - if (ZenModeConfig.isValidDowntimeConditionId(condition.id)) { - // constructed by the client, make sure the record exists... - final ConditionRecord r = getRecordLocked(condition.id, + if (mDowntime != null && ZenModeConfig.isValidDowntimeConditionId(condition.id)) { + ensureRecordExists(condition, mDowntime.asInterface(), DowntimeConditionProvider.COMPONENT); - if (r.info == null) { - // ... and is associated with the in-process service - r.info = checkServiceTokenLocked(mDowntime.asInterface()); - } } } final int N = mRecords.size(); @@ -370,6 +404,7 @@ public class ConditionProviders extends ManagedServices { ZenLog.traceSubscribe(r != null ? r.id : null, provider, re); } + @SafeVarargs private static <T> ArraySet<T> safeSet(T... items) { final ArraySet<T> rt = new ArraySet<T>(); if (items == null || items.length == 0) return rt; @@ -485,7 +520,9 @@ public class ConditionProviders extends ManagedServices { if (changingExit) { ZenLog.traceExitCondition(mExitCondition, mExitConditionComponent, "config"); } - mDowntime.setConfig(config); + if (mDowntime != null) { + mDowntime.setConfig(config); + } if (config.conditionComponents == null || config.conditionIds == null || config.conditionComponents.length != config.conditionIds.length) { if (DEBUG) Slog.d(TAG, "loadZenConfig: no conditions"); @@ -538,6 +575,12 @@ public class ConditionProviders extends ManagedServices { mZenModeHelper.setConfig(config); } + private void onManualConditionClearing() { + if (mDowntime != null) { + mDowntime.onManualConditionClearing(); + } + } + private class ZenModeHelperCallback extends ZenModeHelper.Callback { @Override void onConfigChanged() { @@ -554,46 +597,6 @@ public class ConditionProviders extends ManagedServices { } } - private class DowntimeCallback implements DowntimeConditionProvider.Callback { - @Override - public void onDowntimeChanged(int downtimeMode) { - final int mode = mZenModeHelper.getZenMode(); - final ZenModeConfig config = mZenModeHelper.getConfig(); - final boolean inDowntime = downtimeMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS - || downtimeMode == Global.ZEN_MODE_NO_INTERRUPTIONS; - final boolean downtimeCurrent = mDowntime.isDowntimeCondition(mExitCondition); - // enter downtime, or update mode if reconfigured during an active downtime - if (inDowntime && (mode == Global.ZEN_MODE_OFF || downtimeCurrent) && config != null) { - final Condition condition = mDowntime.createCondition(config.toDowntimeInfo(), - config.sleepNone, Condition.STATE_TRUE); - mZenModeHelper.setZenMode(downtimeMode, "downtimeEnter"); - setZenModeCondition(condition, "downtime"); - } - // exit downtime - if (!inDowntime && downtimeCurrent && (mode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS - || mode == Global.ZEN_MODE_NO_INTERRUPTIONS)) { - mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "downtimeExit"); - } - } - - @Override - public NextAlarmTracker getNextAlarmTracker() { - return mNextAlarmTracker; - } - } - - private class NextAlarmCallback implements NextAlarmConditionProvider.Callback { - @Override - public boolean isInDowntime() { - return mDowntime.isInDowntime(); - } - - @Override - public NextAlarmTracker getNextAlarmTracker() { - return mNextAlarmTracker; - } - } - private static class ConditionRecord { public final Uri id; public final ComponentName component; diff --git a/services/core/java/com/android/server/notification/DowntimeCalendar.java b/services/core/java/com/android/server/notification/DowntimeCalendar.java new file mode 100644 index 0000000..d14fd40 --- /dev/null +++ b/services/core/java/com/android/server/notification/DowntimeCalendar.java @@ -0,0 +1,113 @@ +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.notification; + +import java.util.Calendar; +import java.util.Objects; +import java.util.TimeZone; + +import android.service.notification.ZenModeConfig; +import android.service.notification.ZenModeConfig.DowntimeInfo; +import android.util.ArraySet; + +public class DowntimeCalendar { + + private final ArraySet<Integer> mDays = new ArraySet<Integer>(); + private final Calendar mCalendar = Calendar.getInstance(); + + private DowntimeInfo mInfo; + + @Override + public String toString() { + return "DowntimeCalendar[mDays=" + mDays + "]"; + } + + public void setDowntimeInfo(DowntimeInfo info) { + if (Objects.equals(mInfo, info)) return; + mInfo = info; + updateDays(); + } + + public long nextDowntimeStart(long time) { + if (mInfo == null || mDays.size() == 0) return Long.MAX_VALUE; + final long start = getTime(time, mInfo.startHour, mInfo.startMinute); + for (int i = 0; i < Calendar.SATURDAY; i++) { + final long t = addDays(start, i); + if (t > time && isInDowntime(t)) { + return t; + } + } + return Long.MAX_VALUE; + } + + public void setTimeZone(TimeZone tz) { + mCalendar.setTimeZone(tz); + } + + public long getNextTime(long now, int hr, int min) { + final long time = getTime(now, hr, min); + return time <= now ? addDays(time, 1) : time; + } + + private long getTime(long millis, int hour, int min) { + mCalendar.setTimeInMillis(millis); + mCalendar.set(Calendar.HOUR_OF_DAY, hour); + mCalendar.set(Calendar.MINUTE, min); + mCalendar.set(Calendar.SECOND, 0); + mCalendar.set(Calendar.MILLISECOND, 0); + return mCalendar.getTimeInMillis(); + } + + public boolean isInDowntime(long time) { + if (mInfo == null || mDays.size() == 0) return false; + final long start = getTime(time, mInfo.startHour, mInfo.startMinute); + long end = getTime(time, mInfo.endHour, mInfo.endMinute); + if (end <= start) { + end = addDays(end, 1); + } + return isInDowntime(-1, time, start, end) || isInDowntime(0, time, start, end); + } + + private boolean isInDowntime(int daysOffset, long time, long start, long end) { + final int n = Calendar.SATURDAY; + final int day = ((getDayOfWeek(time) - 1) + (daysOffset % n) + n) % n + 1; + start = addDays(start, daysOffset); + end = addDays(end, daysOffset); + return mDays.contains(day) && time >= start && time < end; + } + + private int getDayOfWeek(long time) { + mCalendar.setTimeInMillis(time); + return mCalendar.get(Calendar.DAY_OF_WEEK); + } + + private void updateDays() { + mDays.clear(); + if (mInfo != null) { + final int[] days = ZenModeConfig.tryParseDays(mInfo.mode); + for (int i = 0; days != null && i < days.length; i++) { + mDays.add(days[i]); + } + } + } + + private long addDays(long time, int days) { + mCalendar.setTimeInMillis(time); + mCalendar.add(Calendar.DATE, days); + return mCalendar.getTimeInMillis(); + } +} diff --git a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java index 097589a..df4ecfd 100644 --- a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java +++ b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java @@ -35,13 +35,13 @@ import android.text.format.DateFormat; import android.util.ArraySet; import android.util.Log; import android.util.Slog; +import android.util.TimeUtils; import com.android.internal.R; import com.android.server.notification.NotificationManagerService.DumpFilter; import java.io.PrintWriter; import java.text.SimpleDateFormat; -import java.util.Calendar; import java.util.Date; import java.util.Locale; import java.util.Objects; @@ -61,26 +61,44 @@ public class DowntimeConditionProvider extends ConditionProviderService { private static final int EXIT_CODE = 101; private static final String EXTRA_TIME = "time"; - private final Calendar mCalendar = Calendar.getInstance(); + private static final long SECONDS = 1000; + private static final long MINUTES = 60 * SECONDS; + private static final long HOURS = 60 * MINUTES; + private final Context mContext = this; - private final ArraySet<Integer> mDays = new ArraySet<Integer>(); - private final ArraySet<Long> mFiredAlarms = new ArraySet<Long>(); + private final DowntimeCalendar mCalendar = new DowntimeCalendar(); + private final FiredAlarms mFiredAlarms = new FiredAlarms(); + private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>(); + private final ConditionProviders mConditionProviders; + private final NextAlarmTracker mTracker; + private final ZenModeHelper mZenModeHelper; private boolean mConnected; - private NextAlarmTracker mTracker; - private int mDowntimeMode; + private long mLookaheadThreshold; private ZenModeConfig mConfig; - private Callback mCallback; + private boolean mDowntimed; + private boolean mConditionClearing; + private boolean mRequesting; - public DowntimeConditionProvider() { + public DowntimeConditionProvider(ConditionProviders conditionProviders, + NextAlarmTracker tracker, ZenModeHelper zenModeHelper) { if (DEBUG) Slog.d(TAG, "new DowntimeConditionProvider()"); + mConditionProviders = conditionProviders; + mTracker = tracker; + mZenModeHelper = zenModeHelper; } public void dump(PrintWriter pw, DumpFilter filter) { pw.println(" DowntimeConditionProvider:"); pw.print(" mConnected="); pw.println(mConnected); - pw.print(" mDowntimeMode="); pw.println(Global.zenModeToString(mDowntimeMode)); + pw.print(" mSubscriptions="); pw.println(mSubscriptions); + pw.print(" mLookaheadThreshold="); pw.print(mLookaheadThreshold); + pw.print(" ("); TimeUtils.formatDuration(mLookaheadThreshold, pw); pw.println(")"); + pw.print(" mCalendar="); pw.println(mCalendar); pw.print(" mFiredAlarms="); pw.println(mFiredAlarms); + pw.print(" mDowntimed="); pw.println(mDowntimed); + pw.print(" mConditionClearing="); pw.println(mConditionClearing); + pw.print(" mRequesting="); pw.println(mRequesting); } public void attachBase(Context base) { @@ -91,22 +109,20 @@ public class DowntimeConditionProvider extends ConditionProviderService { return (IConditionProvider) onBind(null); } - public void setCallback(Callback callback) { - mCallback = callback; - } - @Override public void onConnected() { if (DEBUG) Slog.d(TAG, "onConnected"); mConnected = true; + mLookaheadThreshold = PropConfig.getInt(mContext, "downtime.condition.lookahead", + R.integer.config_downtime_condition_lookahead_threshold_hrs) * HOURS; final IntentFilter filter = new IntentFilter(); filter.addAction(ENTER_ACTION); filter.addAction(EXIT_ACTION); filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); mContext.registerReceiver(mReceiver, filter); - mTracker = mCallback.getNextAlarmTracker(); mTracker.addCallback(mTrackerCallback); + mZenModeHelper.addCallback(mZenCallback); init(); } @@ -114,59 +130,125 @@ public class DowntimeConditionProvider extends ConditionProviderService { public void onDestroy() { if (DEBUG) Slog.d(TAG, "onDestroy"); mTracker.removeCallback(mTrackerCallback); + mZenModeHelper.removeCallback(mZenCallback); mConnected = false; } @Override public void onRequestConditions(int relevance) { if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance); - if ((relevance & Condition.FLAG_RELEVANT_NOW) != 0) { - if (isInDowntime() && mConfig != null) { - notifyCondition(createCondition(mConfig.toDowntimeInfo(), mConfig.sleepNone, - Condition.STATE_TRUE)); - } - } + if (!mConnected) return; + mRequesting = (relevance & Condition.FLAG_RELEVANT_NOW) != 0; + evaluateSubscriptions(); } @Override public void onSubscribe(Uri conditionId) { if (DEBUG) Slog.d(TAG, "onSubscribe conditionId=" + conditionId); final DowntimeInfo downtime = ZenModeConfig.tryParseDowntimeConditionId(conditionId); - if (downtime != null && mConfig != null) { - final int state = mConfig.toDowntimeInfo().equals(downtime) && isInDowntime() - ? Condition.STATE_TRUE : Condition.STATE_FALSE; - if (DEBUG) Slog.d(TAG, "notify condition state: " + Condition.stateToString(state)); - notifyCondition(createCondition(downtime, mConfig.sleepNone, state)); + if (downtime == null) return; + mFiredAlarms.clear(); + mSubscriptions.add(conditionId); + notifyCondition(downtime); + } + + private boolean shouldShowCondition() { + final long now = System.currentTimeMillis(); + if (DEBUG) Slog.d(TAG, "shouldShowCondition now=" + mCalendar.isInDowntime(now) + + " lookahead=" + + (mCalendar.nextDowntimeStart(now) <= (now + mLookaheadThreshold))); + return mCalendar.isInDowntime(now) + || mCalendar.nextDowntimeStart(now) <= (now + mLookaheadThreshold); + } + + private void notifyCondition(DowntimeInfo downtime) { + if (mConfig == null) { + // we don't know yet + notifyCondition(createCondition(downtime, Condition.STATE_UNKNOWN)); + return; + } + if (!downtime.equals(mConfig.toDowntimeInfo())) { + // not the configured downtime, consider it false + notifyCondition(createCondition(downtime, Condition.STATE_FALSE)); + return; + } + if (!shouldShowCondition()) { + // configured downtime, but not within the time range + notifyCondition(createCondition(downtime, Condition.STATE_FALSE)); + return; + } + if (isZenNone() && mFiredAlarms.findBefore(System.currentTimeMillis())) { + // within the configured time range, but wake up if none and the next alarm is fired + notifyCondition(createCondition(downtime, Condition.STATE_FALSE)); + return; + } + // within the configured time range, condition still valid + notifyCondition(createCondition(downtime, Condition.STATE_TRUE)); + } + + private boolean isZenNone() { + return mZenModeHelper.getZenMode() == Global.ZEN_MODE_NO_INTERRUPTIONS; + } + + private boolean isZenOff() { + return mZenModeHelper.getZenMode() == Global.ZEN_MODE_OFF; + } + + private void evaluateSubscriptions() { + ArraySet<Uri> conditions = mSubscriptions; + if (mConfig != null && mRequesting && shouldShowCondition()) { + final Uri id = ZenModeConfig.toDowntimeConditionId(mConfig.toDowntimeInfo()); + if (!conditions.contains(id)) { + conditions = new ArraySet<Uri>(conditions); + conditions.add(id); + } + } + for (Uri conditionId : conditions) { + final DowntimeInfo downtime = ZenModeConfig.tryParseDowntimeConditionId(conditionId); + if (downtime != null) { + notifyCondition(downtime); + } } } @Override public void onUnsubscribe(Uri conditionId) { - if (DEBUG) Slog.d(TAG, "onUnsubscribe conditionId=" + conditionId); + final boolean current = mSubscriptions.contains(conditionId); + if (DEBUG) Slog.d(TAG, "onUnsubscribe conditionId=" + conditionId + " current=" + current); + mSubscriptions.remove(conditionId); + mFiredAlarms.clear(); } public void setConfig(ZenModeConfig config) { if (Objects.equals(mConfig, config)) return; - if (DEBUG) Slog.d(TAG, "setConfig"); + final boolean downtimeChanged = mConfig == null || config == null + || !mConfig.toDowntimeInfo().equals(config.toDowntimeInfo()); mConfig = config; - if (mConnected) { + if (DEBUG) Slog.d(TAG, "setConfig downtimeChanged=" + downtimeChanged); + if (mConnected && downtimeChanged) { + mDowntimed = false; init(); } + // when active, mark downtime as entered for today + if (mConfig != null && mConfig.exitCondition != null + && ZenModeConfig.isValidDowntimeConditionId(mConfig.exitCondition.id)) { + mDowntimed = true; + } } - public boolean isInDowntime() { - return mDowntimeMode != Global.ZEN_MODE_OFF; + public void onManualConditionClearing() { + mConditionClearing = true; } - public Condition createCondition(DowntimeInfo downtime, boolean orAlarm, int state) { + private Condition createCondition(DowntimeInfo downtime, int state) { if (downtime == null) return null; final Uri id = ZenModeConfig.toDowntimeConditionId(downtime); final String skeleton = DateFormat.is24HourFormat(mContext) ? "Hm" : "hma"; final Locale locale = Locale.getDefault(); final String pattern = DateFormat.getBestDateTimePattern(locale, skeleton); final long now = System.currentTimeMillis(); - long endTime = getTime(now, downtime.endHour, downtime.endMinute); - if (orAlarm) { + long endTime = mCalendar.getNextTime(now, downtime.endHour, downtime.endMinute); + if (isZenNone()) { final AlarmClockInfo nextAlarm = mTracker.getNextAlarm(); final long nextAlarmTime = nextAlarm != null ? nextAlarm.getTriggerTime() : 0; if (nextAlarmTime > now && nextAlarmTime < endTime) { @@ -179,79 +261,11 @@ public class DowntimeConditionProvider extends ConditionProviderService { return new Condition(id, summary, line1, formatted, 0, state, Condition.FLAG_RELEVANT_NOW); } - public boolean isDowntimeCondition(Condition condition) { - return condition != null && ZenModeConfig.isValidDowntimeConditionId(condition.id); - } - private void init() { - updateDays(); - reevaluateDowntime(); + mCalendar.setDowntimeInfo(mConfig != null ? mConfig.toDowntimeInfo() : null); + evaluateSubscriptions(); updateAlarms(); - } - - private void updateDays() { - mDays.clear(); - if (mConfig != null) { - final int[] days = ZenModeConfig.tryParseDays(mConfig.sleepMode); - for (int i = 0; days != null && i < days.length; i++) { - mDays.add(days[i]); - } - } - } - - private boolean isInDowntime(long time) { - if (mConfig == null || mDays.size() == 0) return false; - final long start = getTime(time, mConfig.sleepStartHour, mConfig.sleepStartMinute); - long end = getTime(time, mConfig.sleepEndHour, mConfig.sleepEndMinute); - if (start == end) return false; - if (end < start) { - end = addDays(end, 1); - } - final boolean orAlarm = mConfig.sleepNone; - return isInDowntime(-1, time, start, end, orAlarm) - || isInDowntime(0, time, start, end, orAlarm); - } - - private boolean isInDowntime(int daysOffset, long time, long start, long end, boolean orAlarm) { - final int n = Calendar.SATURDAY; - final int day = ((getDayOfWeek(time) - 1) + (daysOffset % n) + n) % n + 1; - start = addDays(start, daysOffset); - end = addDays(end, daysOffset); - if (orAlarm) { - end = findFiredAlarm(start, end); - } - return mDays.contains(day) && time >= start && time < end; - } - - private long findFiredAlarm(long start, long end) { - final int N = mFiredAlarms.size(); - for (int i = 0; i < N; i++) { - final long firedAlarm = mFiredAlarms.valueAt(i); - if (firedAlarm > start && firedAlarm < end) { - return firedAlarm; - } - } - return end; - } - - private void reevaluateDowntime() { - final long now = System.currentTimeMillis(); - final boolean inDowntimeNow = isInDowntime(now); - final int downtimeMode = inDowntimeNow ? (mConfig.sleepNone - ? Global.ZEN_MODE_NO_INTERRUPTIONS : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) - : Global.ZEN_MODE_OFF; - if (DEBUG) Slog.d(TAG, "downtimeMode=" + downtimeMode); - if (downtimeMode == mDowntimeMode) return; - mDowntimeMode = downtimeMode; - Slog.i(TAG, (isInDowntime() ? "Entering" : "Exiting" ) + " downtime"); - ZenLog.traceDowntime(mDowntimeMode, getDayOfWeek(now), mDays); - fireDowntimeChanged(); - } - - private void fireDowntimeChanged() { - if (mCallback != null) { - mCallback.onDowntimeChanged(mDowntimeMode); - } + evaluateAutotrigger(); } private void updateAlarms() { @@ -260,38 +274,11 @@ public class DowntimeConditionProvider extends ConditionProviderService { updateAlarm(EXIT_ACTION, EXIT_CODE, mConfig.sleepEndHour, mConfig.sleepEndMinute); } - private int getDayOfWeek(long time) { - mCalendar.setTimeInMillis(time); - return mCalendar.get(Calendar.DAY_OF_WEEK); - } - - private long getTime(long millis, int hour, int min) { - mCalendar.setTimeInMillis(millis); - mCalendar.set(Calendar.HOUR_OF_DAY, hour); - mCalendar.set(Calendar.MINUTE, min); - mCalendar.set(Calendar.SECOND, 0); - mCalendar.set(Calendar.MILLISECOND, 0); - return mCalendar.getTimeInMillis(); - } - - private long addDays(long time, int days) { - mCalendar.setTimeInMillis(time); - mCalendar.add(Calendar.DATE, days); - return mCalendar.getTimeInMillis(); - } private void updateAlarm(String action, int requestCode, int hr, int min) { final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); final long now = System.currentTimeMillis(); - mCalendar.setTimeInMillis(now); - mCalendar.set(Calendar.HOUR_OF_DAY, hr); - mCalendar.set(Calendar.MINUTE, min); - mCalendar.set(Calendar.SECOND, 0); - mCalendar.set(Calendar.MILLISECOND, 0); - long time = mCalendar.getTimeInMillis(); - if (time <= now) { - time = addDays(time, 1); - } + final long time = mCalendar.getNextTime(now, hr, min); final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, requestCode, new Intent(action) .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) @@ -311,31 +298,34 @@ public class DowntimeConditionProvider extends ConditionProviderService { private void onEvaluateNextAlarm(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted) { if (!booted) return; // we don't know yet - // update condition description if we're in downtime (mode = none) - if (isInDowntime() && mConfig != null && mConfig.sleepNone) { - notifyCondition(createCondition(mConfig.toDowntimeInfo(), true /*orAlarm*/, - Condition.STATE_TRUE)); - } - if (nextAlarm == null) return; // not fireable if (DEBUG) Slog.d(TAG, "onEvaluateNextAlarm " + mTracker.formatAlarmDebug(nextAlarm)); - if (System.currentTimeMillis() > wakeupTime) { + if (nextAlarm != null && wakeupTime > 0 && System.currentTimeMillis() > wakeupTime) { if (DEBUG) Slog.d(TAG, "Alarm fired: " + mTracker.formatAlarmDebug(wakeupTime)); - trimFiredAlarms(); mFiredAlarms.add(wakeupTime); } - reevaluateDowntime(); + evaluateSubscriptions(); } - private void trimFiredAlarms() { - // remove fired alarms over 2 days old - final long keepAfter = System.currentTimeMillis() - 2 * 24 * 60 * 60 * 1000; - final int N = mFiredAlarms.size(); - for (int i = N - 1; i >= 0; i--) { - final long firedAlarm = mFiredAlarms.valueAt(i); - if (firedAlarm < keepAfter) { - mFiredAlarms.removeAt(i); - } + private void evaluateAutotrigger() { + String skipReason = null; + if (mConfig == null) { + skipReason = "no config"; + } else if (mDowntimed) { + skipReason = "already downtimed"; + } else if (mZenModeHelper.getZenMode() != Global.ZEN_MODE_OFF) { + skipReason = "already in zen"; + } else if (!mCalendar.isInDowntime(System.currentTimeMillis())) { + skipReason = "not in downtime"; } + if (skipReason != null) { + ZenLog.traceDowntimeAutotrigger("Autotrigger skipped: " + skipReason); + return; + } + ZenLog.traceDowntimeAutotrigger("Autotrigger fired"); + mZenModeHelper.setZenMode(mConfig.sleepNone ? Global.ZEN_MODE_NO_INTERRUPTIONS + : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, "downtime"); + final Condition condition = createCondition(mConfig.toDowntimeInfo(), Condition.STATE_TRUE); + mConditionProviders.setZenModeCondition(condition, "downtime"); } private BroadcastReceiver mReceiver = new BroadcastReceiver() { @@ -347,6 +337,12 @@ public class DowntimeConditionProvider extends ConditionProviderService { final long schTime = intent.getLongExtra(EXTRA_TIME, 0); if (DEBUG) Slog.d(TAG, String.format("%s scheduled for %s, fired at %s, delta=%s", action, ts(schTime), ts(now), now - schTime)); + if (ENTER_ACTION.equals(action)) { + evaluateAutotrigger(); + } else /*EXIT_ACTION*/ { + mDowntimed = false; + } + mFiredAlarms.clear(); } else if (Intent.ACTION_TIMEZONE_CHANGED.equals(action)) { if (DEBUG) Slog.d(TAG, "timezone changed to " + TimeZone.getDefault()); mCalendar.setTimeZone(TimeZone.getDefault()); @@ -357,7 +353,7 @@ public class DowntimeConditionProvider extends ConditionProviderService { } else { if (DEBUG) Slog.d(TAG, action + " fired at " + now); } - reevaluateDowntime(); + evaluateSubscriptions(); updateAlarms(); } }; @@ -369,8 +365,45 @@ public class DowntimeConditionProvider extends ConditionProviderService { } }; - public interface Callback { - void onDowntimeChanged(int downtimeMode); - NextAlarmTracker getNextAlarmTracker(); + private final ZenModeHelper.Callback mZenCallback = new ZenModeHelper.Callback() { + @Override + void onZenModeChanged() { + if (mConditionClearing && isZenOff()) { + evaluateAutotrigger(); + } + mConditionClearing = false; + evaluateSubscriptions(); + } + }; + + private class FiredAlarms { + private final ArraySet<Long> mFiredAlarms = new ArraySet<Long>(); + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < mFiredAlarms.size(); i++) { + if (i > 0) sb.append(','); + sb.append(mTracker.formatAlarmDebug(mFiredAlarms.valueAt(i))); + } + return sb.toString(); + } + + public void add(long firedAlarm) { + mFiredAlarms.add(firedAlarm); + } + + public void clear() { + mFiredAlarms.clear(); + } + + public boolean findBefore(long time) { + for (int i = 0; i < mFiredAlarms.size(); i++) { + if (mFiredAlarms.valueAt(i) < time) { + return true; + } + } + return false; + } } } diff --git a/services/core/java/com/android/server/notification/NextAlarmConditionProvider.java b/services/core/java/com/android/server/notification/NextAlarmConditionProvider.java index 35bbaa0..1634c65 100644 --- a/services/core/java/com/android/server/notification/NextAlarmConditionProvider.java +++ b/services/core/java/com/android/server/notification/NextAlarmConditionProvider.java @@ -25,6 +25,8 @@ import android.service.notification.Condition; import android.service.notification.ConditionProviderService; import android.service.notification.IConditionProvider; import android.service.notification.ZenModeConfig; +import android.text.TextUtils; +import android.util.ArraySet; import android.util.Log; import android.util.Slog; import android.util.TimeUtils; @@ -38,10 +40,7 @@ import java.io.PrintWriter; * Built-in zen condition provider for alarm-clock-based conditions. * * <p>If the user's next alarm is within a lookahead threshold (config, default 12hrs), advertise - * it as an exit condition for zen mode (unless the built-in downtime condition is also available). - * - * <p>When this next alarm is selected as the active exit condition, follow subsequent changes - * to the user's next alarm, assuming it remains within the 12-hr window. + * it as an exit condition for zen mode. * * <p>The next alarm is defined as {@link AlarmManager#getNextAlarmClock(int)}, which does not * survive a reboot. Maintain the illusion of a consistent next alarm value by holding on to @@ -55,20 +54,22 @@ public class NextAlarmConditionProvider extends ConditionProviderService { private static final long MINUTES = 60 * SECONDS; private static final long HOURS = 60 * MINUTES; - private static final String NEXT_ALARM_PATH = "next_alarm"; + private static final long BAD_CONDITION = -1; + public static final ComponentName COMPONENT = new ComponentName("android", NextAlarmConditionProvider.class.getName()); private final Context mContext = this; + private final NextAlarmTracker mTracker; + private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>(); - private NextAlarmTracker mTracker; private boolean mConnected; private long mLookaheadThreshold; - private Callback mCallback; - private Uri mCurrentSubscription; + private boolean mRequesting; - public NextAlarmConditionProvider() { + public NextAlarmConditionProvider(NextAlarmTracker tracker) { if (DEBUG) Slog.d(TAG, "new NextAlarmConditionProvider()"); + mTracker = tracker; } public void dump(PrintWriter pw, DumpFilter filter) { @@ -76,20 +77,16 @@ public class NextAlarmConditionProvider extends ConditionProviderService { pw.print(" mConnected="); pw.println(mConnected); pw.print(" mLookaheadThreshold="); pw.print(mLookaheadThreshold); pw.print(" ("); TimeUtils.formatDuration(mLookaheadThreshold, pw); pw.println(")"); - pw.print(" mCurrentSubscription="); pw.println(mCurrentSubscription); - } - - public void setCallback(Callback callback) { - mCallback = callback; + pw.print(" mSubscriptions="); pw.println(mSubscriptions); + pw.print(" mRequesting="); pw.println(mRequesting); } @Override public void onConnected() { if (DEBUG) Slog.d(TAG, "onConnected"); - mLookaheadThreshold = mContext.getResources() - .getInteger(R.integer.config_next_alarm_condition_lookahead_threshold_hrs) * HOURS; + mLookaheadThreshold = PropConfig.getInt(mContext, "nextalarm.condition.lookahead", + R.integer.config_next_alarm_condition_lookahead_threshold_hrs) * HOURS; mConnected = true; - mTracker = mCallback.getNextAlarmTracker(); mTracker.addCallback(mTrackerCallback); } @@ -103,34 +100,27 @@ public class NextAlarmConditionProvider extends ConditionProviderService { @Override public void onRequestConditions(int relevance) { - if (!mConnected || (relevance & Condition.FLAG_RELEVANT_NOW) == 0) return; - - final AlarmClockInfo nextAlarm = mTracker.getNextAlarm(); - if (nextAlarm == null) return; // no next alarm - if (mCallback != null && mCallback.isInDowntime()) return; // prefer downtime condition - if (!isWithinLookaheadThreshold(nextAlarm)) return; // alarm not within window - - // next alarm exists, and is within the configured lookahead threshold - notifyCondition(newConditionId(), nextAlarm, Condition.STATE_TRUE, "request"); + if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance); + if (!mConnected) return; + mRequesting = (relevance & Condition.FLAG_RELEVANT_NOW) != 0; + mTracker.evaluate(); } @Override public void onSubscribe(Uri conditionId) { if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId); - if (!isNextAlarmCondition(conditionId)) { + if (tryParseNextAlarmCondition(conditionId) == BAD_CONDITION) { notifyCondition(conditionId, null, Condition.STATE_FALSE, "badCondition"); return; } - mCurrentSubscription = conditionId; + mSubscriptions.add(conditionId); mTracker.evaluate(); } @Override public void onUnsubscribe(Uri conditionId) { if (DEBUG) Slog.d(TAG, "onUnsubscribe " + conditionId); - if (conditionId != null && conditionId.equals(mCurrentSubscription)) { - mCurrentSubscription = null; - } + mSubscriptions.remove(conditionId); } public void attachBase(Context base) { @@ -157,43 +147,72 @@ public class NextAlarmConditionProvider extends ConditionProviderService { formattedAlarm, 0, state, Condition.FLAG_RELEVANT_NOW)); } - private Uri newConditionId() { + private Uri newConditionId(AlarmClockInfo nextAlarm) { return new Uri.Builder().scheme(Condition.SCHEME) .authority(ZenModeConfig.SYSTEM_AUTHORITY) - .appendPath(NEXT_ALARM_PATH) + .appendPath(ZenModeConfig.NEXT_ALARM_PATH) .appendPath(Integer.toString(mTracker.getCurrentUserId())) + .appendPath(Long.toString(nextAlarm.getTriggerTime())) .build(); } - private boolean isNextAlarmCondition(Uri conditionId) { + private long tryParseNextAlarmCondition(Uri conditionId) { return conditionId != null && conditionId.getScheme().equals(Condition.SCHEME) && conditionId.getAuthority().equals(ZenModeConfig.SYSTEM_AUTHORITY) - && conditionId.getPathSegments().size() == 2 - && conditionId.getPathSegments().get(0).equals(NEXT_ALARM_PATH) + && conditionId.getPathSegments().size() == 3 + && conditionId.getPathSegments().get(0).equals(ZenModeConfig.NEXT_ALARM_PATH) && conditionId.getPathSegments().get(1) - .equals(Integer.toString(mTracker.getCurrentUserId())); + .equals(Integer.toString(mTracker.getCurrentUserId())) + ? tryParseLong(conditionId.getPathSegments().get(2), BAD_CONDITION) + : BAD_CONDITION; + } + + private static long tryParseLong(String value, long defValue) { + if (TextUtils.isEmpty(value)) return defValue; + try { + return Long.valueOf(value); + } catch (NumberFormatException e) { + return defValue; + } } private void onEvaluate(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted) { final boolean withinThreshold = isWithinLookaheadThreshold(nextAlarm); - if (DEBUG) Slog.d(TAG, "onEvaluate mCurrentSubscription=" + mCurrentSubscription + final long nextAlarmTime = nextAlarm != null ? nextAlarm.getTriggerTime() : 0; + if (DEBUG) Slog.d(TAG, "onEvaluate mSubscriptions=" + mSubscriptions + + " nextAlarmTime=" + mTracker.formatAlarmDebug(nextAlarmTime) + " nextAlarmWakeup=" + mTracker.formatAlarmDebug(wakeupTime) + " withinThreshold=" + withinThreshold + " booted=" + booted); - if (mCurrentSubscription == null) return; // no one cares - if (!booted) { - // we don't know yet - notifyCondition(mCurrentSubscription, nextAlarm, Condition.STATE_UNKNOWN, "!booted"); - return; + + ArraySet<Uri> conditions = mSubscriptions; + if (mRequesting && nextAlarm != null && withinThreshold) { + final Uri id = newConditionId(nextAlarm); + if (!conditions.contains(id)) { + conditions = new ArraySet<Uri>(conditions); + conditions.add(id); + } } - if (!withinThreshold) { - // next alarm outside threshold or in the past, condition = false - notifyCondition(mCurrentSubscription, nextAlarm, Condition.STATE_FALSE, "!within"); - mCurrentSubscription = null; - return; + for (Uri conditionId : conditions) { + final long time = tryParseNextAlarmCondition(conditionId); + if (time == BAD_CONDITION) { + notifyCondition(conditionId, nextAlarm, Condition.STATE_FALSE, "badCondition"); + } else if (!booted) { + // we don't know yet + if (mSubscriptions.contains(conditionId)) { + notifyCondition(conditionId, nextAlarm, Condition.STATE_UNKNOWN, "!booted"); + } + } else if (time != nextAlarmTime) { + // next alarm changed since subscription, consider obsolete + notifyCondition(conditionId, nextAlarm, Condition.STATE_FALSE, "changed"); + } else if (!withinThreshold) { + // next alarm outside threshold or in the past, condition = false + notifyCondition(conditionId, nextAlarm, Condition.STATE_FALSE, "!within"); + } else { + // next alarm within threshold and in the future, condition = true + notifyCondition(conditionId, nextAlarm, Condition.STATE_TRUE, "within"); + } } - // next alarm in the future and within threshold, condition = true - notifyCondition(mCurrentSubscription, nextAlarm, Condition.STATE_TRUE, "within"); } private final NextAlarmTracker.Callback mTrackerCallback = new NextAlarmTracker.Callback() { @@ -202,9 +221,4 @@ public class NextAlarmConditionProvider extends ConditionProviderService { NextAlarmConditionProvider.this.onEvaluate(nextAlarm, wakeupTime, booted); } }; - - public interface Callback { - boolean isInDowntime(); - NextAlarmTracker getNextAlarmTracker(); - } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index aec20bc..650f0e2 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1028,6 +1028,7 @@ public class NotificationManagerService extends SystemService { ? mListenersDisablingEffects.valueAt(0).component : null; if (Objects.equals(suppressor, mEffectsSuppressor)) return; mEffectsSuppressor = suppressor; + mZenModeHelper.setEffectsSuppressed(suppressor != null); getContext().sendBroadcast(new Intent(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED) .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)); } @@ -1551,6 +1552,12 @@ public class NotificationManagerService extends SystemService { MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS, MATCHES_CALL_FILTER_TIMEOUT_AFFINITY); } + + @Override + public boolean isSystemConditionProviderEnabled(String path) { + enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled"); + return mConditionProviders.isSystemConditionProviderEnabled(path); + } }; private String[] getActiveNotificationKeys(INotificationListener token) { diff --git a/services/core/java/com/android/server/notification/PropConfig.java b/services/core/java/com/android/server/notification/PropConfig.java new file mode 100644 index 0000000..97bf90d --- /dev/null +++ b/services/core/java/com/android/server/notification/PropConfig.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.notification; + +import android.content.Context; +import android.os.SystemProperties; + +public class PropConfig { + private static final String UNSET = "UNSET"; + + public static int getInt(Context context, String propName, int resId) { + return SystemProperties.getInt(propName, context.getResources().getInteger(resId)); + } + + public static String[] getStringArray(Context context, String propName, int resId) { + final String prop = SystemProperties.get(propName, UNSET); + return !UNSET.equals(prop) ? prop.split(",") : context.getResources().getStringArray(resId); + } +} diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java index 6960159..dda0b37 100644 --- a/services/core/java/com/android/server/notification/ZenLog.java +++ b/services/core/java/com/android/server/notification/ZenLog.java @@ -89,12 +89,12 @@ public class ZenLog { ringerModeToString(ringerModeExternalOut)); } - public static void traceDowntime(int downtimeMode, int day, ArraySet<Integer> days) { - append(TYPE_DOWNTIME, zenModeToString(downtimeMode) + ",day=" + day + ",days=" + days); + public static void traceDowntimeAutotrigger(String result) { + append(TYPE_DOWNTIME, result); } - public static void traceSetZenMode(int mode, String reason) { - append(TYPE_SET_ZEN_MODE, zenModeToString(mode) + "," + reason); + public static void traceSetZenMode(int zenMode, String reason) { + append(TYPE_SET_ZEN_MODE, zenModeToString(zenMode) + "," + reason); } public static void traceUpdateZenMode(int fromMode, int toMode) { diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 5ceb503..31d5cd7 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -17,6 +17,7 @@ package com.android.server.notification; import static android.media.AudioAttributes.USAGE_ALARM; +import static android.media.AudioAttributes.USAGE_NOTIFICATION; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import android.app.AppOpsManager; @@ -77,6 +78,7 @@ public class ZenModeHelper implements AudioManagerInternal.RingerModeDelegate { private ZenModeConfig mConfig; private AudioManagerInternal mAudioManager; private int mPreviousRingerMode = -1; + private boolean mEffectsSuppressed; public ZenModeHelper(Context context, Looper looper) { mContext = context; @@ -108,6 +110,10 @@ public class ZenModeHelper implements AudioManagerInternal.RingerModeDelegate { mCallbacks.add(callback); } + public void removeCallback(Callback callback) { + mCallbacks.remove(callback); + } + public void onSystemReady() { mAudioManager = LocalServices.getService(AudioManagerInternal.class); if (mAudioManager != null) { @@ -149,6 +155,12 @@ public class ZenModeHelper implements AudioManagerInternal.RingerModeDelegate { } } + public void setEffectsSuppressed(boolean effectsSuppressed) { + if (mEffectsSuppressed == effectsSuppressed) return; + mEffectsSuppressed = effectsSuppressed; + applyRestrictions(); + } + public boolean shouldIntercept(NotificationRecord record) { if (isSystem(record)) { return false; @@ -208,9 +220,9 @@ public class ZenModeHelper implements AudioManagerInternal.RingerModeDelegate { return mZenMode; } - public void setZenMode(int zenModeValue, String reason) { - ZenLog.traceSetZenMode(zenModeValue, reason); - Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zenModeValue); + public void setZenMode(int zenMode, String reason) { + ZenLog.traceSetZenMode(zenMode, reason); + Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zenMode); } public void updateZenMode() { @@ -221,29 +233,35 @@ public class ZenModeHelper implements AudioManagerInternal.RingerModeDelegate { ZenLog.traceUpdateZenMode(oldMode, newMode); } mZenMode = newMode; + applyRestrictions(); + onZenUpdated(oldMode, newMode); + dispatchOnZenModeChanged(); + } + + private void applyRestrictions() { final boolean zen = mZenMode != Global.ZEN_MODE_OFF; - final String[] exceptionPackages = null; // none (for now) + + // notification restrictions + final boolean muteNotifications = mEffectsSuppressed; + applyRestrictions(muteNotifications, USAGE_NOTIFICATION); // call restrictions - final boolean muteCalls = zen && !mConfig.allowCalls; - mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, USAGE_NOTIFICATION_RINGTONE, - muteCalls ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, - exceptionPackages); - mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, USAGE_NOTIFICATION_RINGTONE, - muteCalls ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, - exceptionPackages); + final boolean muteCalls = zen && !mConfig.allowCalls || mEffectsSuppressed; + applyRestrictions(muteCalls, USAGE_NOTIFICATION_RINGTONE); // alarm restrictions final boolean muteAlarms = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; - mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, USAGE_ALARM, - muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, + applyRestrictions(muteAlarms, USAGE_ALARM); + } + + private void applyRestrictions(boolean mute, int usage) { + final String[] exceptionPackages = null; // none (for now) + mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, usage, + mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, exceptionPackages); - mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, USAGE_ALARM, - muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, + mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, usage, + mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, exceptionPackages); - - onZenUpdated(oldMode, newMode); - dispatchOnZenModeChanged(); } public void dump(PrintWriter pw, String prefix) { @@ -253,6 +271,7 @@ public class ZenModeHelper implements AudioManagerInternal.RingerModeDelegate { pw.print(prefix); pw.print("mDefaultConfig="); pw.println(mDefaultConfig); pw.print(prefix); pw.print("mPreviousRingerMode="); pw.println(mPreviousRingerMode); pw.print(prefix); pw.print("mDefaultPhoneApp="); pw.println(mDefaultPhoneApp); + pw.print(prefix); pw.print("mEffectsSuppressed="); pw.println(mEffectsSuppressed); } public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 6f1e851..91637e3 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -10199,13 +10199,13 @@ public class PackageManagerService extends IPackageManager.Stub { // default to original signature matching if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { - res.setError(INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, + res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "New package has a different signature: " + pkgName); return; } } else { if(!checkUpgradeKeySetLP(ps, pkg)) { - res.setError(INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, + res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "New package not signed by keys specified by upgrade-keysets: " + pkgName); return; diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java new file mode 100644 index 0000000..64a67fc --- /dev/null +++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.telecom; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.UserHandle; +import android.util.Slog; + +import com.android.server.SystemService; + +/** + * Starts the telecom component by binding to its ITelecomService implementation. Telecom is setup + * to run in the system-server process so once it is loaded into memory it will stay running. + * @hide + */ +public class TelecomLoaderService extends SystemService { + private static final String TAG = "TelecomLoaderService"; + + private class TelecomServiceConnection implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + // Normally, we would listen for death here, but since telecom runs in the same process + // as this loader (process="system") thats redundant here. + try { + service.linkToDeath(new IBinder.DeathRecipient() { + @Override + public void binderDied() { + connectToTelecom(); + } + }, 0); + + ServiceManager.addService(Context.TELECOM_SERVICE, service); + } catch (RemoteException e) { + Slog.w(TAG, "Failed linking to death."); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + connectToTelecom(); + } + } + + private static final ComponentName SERVICE_COMPONENT = new ComponentName( + "com.android.server.telecom", + "com.android.server.telecom.TelecomService"); + + private static final String SERVICE_ACTION = "com.android.ITelecomService"; + + private final Context mContext; + private TelecomServiceConnection mServiceConnection; + + public TelecomLoaderService(Context context) { + super(context); + mContext = context; + } + + @Override + public void onStart() { + } + + @Override + public void onBootPhase(int phase) { + if (phase == PHASE_ACTIVITY_MANAGER_READY) { + connectToTelecom(); + } + } + + private void connectToTelecom() { + if (mServiceConnection != null) { + // TODO: Is unbinding worth doing or wait for system to rebind? + mContext.unbindService(mServiceConnection); + mServiceConnection = null; + } + + TelecomServiceConnection serviceConnection = new TelecomServiceConnection(); + Intent intent = new Intent(SERVICE_ACTION); + intent.setComponent(SERVICE_COMPONENT); + int flags = Context.BIND_IMPORTANT | Context.BIND_AUTO_CREATE; + + // Bind to Telecom and register the service + if (mContext.bindServiceAsUser(intent, serviceConnection, flags, UserHandle.OWNER)) { + mServiceConnection = serviceConnection; + } + } +} diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index ba89f23..021a6e4 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -617,8 +617,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { mOverscanInsets.set(Math.max(mOverscanFrame.left - mFrame.left, 0), Math.max(mOverscanFrame.top - mFrame.top, 0), - Math.min(mFrame.right - mOverscanFrame.right, 0), - Math.min(mFrame.bottom - mOverscanFrame.bottom, 0)); + Math.max(mFrame.right - mOverscanFrame.right, 0), + Math.max(mFrame.bottom - mOverscanFrame.bottom, 0)); mContentInsets.set(mContentFrame.left - mFrame.left, mContentFrame.top - mFrame.top, diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b3a696e..334cdf6 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -89,6 +89,7 @@ import com.android.server.restrictions.RestrictionsManagerService; import com.android.server.search.SearchManagerService; import com.android.server.statusbar.StatusBarManagerService; import com.android.server.storage.DeviceStorageMonitorService; +import com.android.server.telecom.TelecomLoaderService; import com.android.server.trust.TrustManagerService; import com.android.server.tv.TvInputManagerService; import com.android.server.twilight.TwilightService; @@ -428,6 +429,8 @@ public final class SystemServer { Slog.i(TAG, "Scheduling Policy"); ServiceManager.addService("scheduling_policy", new SchedulingPolicyService()); + mSystemServiceManager.startService(TelecomLoaderService.class); + Slog.i(TAG, "Telephony Registry"); telephonyRegistry = new TelephonyRegistry(context); ServiceManager.addService("telephony.registry", telephonyRegistry); diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index b74716f..0b4d42e 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -916,10 +916,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } private Future<Void> expectPolicyDataEnable(int type, boolean enabled) throws Exception { - final FutureAnswer future = new FutureAnswer(); - mConnManager.setPolicyDataEnable(type, enabled); - expectLastCall().andAnswer(future); - return future; + // TODO: bring back this test + return null; } private void expectAdvisePersistThreshold() throws Exception { diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index f9a03fc..7383478 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -1023,7 +1023,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { info.setDetailedState(DetailedState.CONNECTED, null, null); final LinkProperties prop = new LinkProperties(); prop.setInterfaceName(iface); - return new NetworkState(info, prop, null, null); + return new NetworkState(info, prop, null, null, null, null); } private NetworkStats buildEmptyStats() { diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index abf1ead..39cce69 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.NonNull; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; @@ -51,6 +52,7 @@ public class SubscriptionManager { private static final boolean VDBG = false; /** An invalid subscription identifier */ + /** @hide */ public static final int INVALID_SUBSCRIPTION_ID = -1; /** Base value for Dummy SUBSCRIPTION_ID's. */ @@ -661,7 +663,7 @@ public class SubscriptionManager { * @param subId the unique SubscriptionInfo index in database * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE, * 2: NAME_SOURCE_USER_INPUT, -1 NAME_SOURCE_UNDEFINED - * @return the number of records updated or -1 if invalid subId + * @return the number of records updated or < 0 if invalid subId * @hide */ public int setDisplayName(String displayName, int subId, long nameSource) { @@ -748,7 +750,7 @@ public class SubscriptionManager { /** * Get slotId associated with the subscription. * @return slotId as a positive integer or a negative value if an error either - * SIM_NOT_INSERTED or INVALID_SLOT_ID. + * SIM_NOT_INSERTED or < 0 if an invalid slot index * @hide */ public static int getSlotId(int subId) { @@ -883,7 +885,7 @@ public class SubscriptionManager { /** * @return subId of the DefaultSms subscription or - * the value INVALID_SUBSCRIPTION_ID if an error. + * a value < 0 if an error. * * @hide */ @@ -997,7 +999,7 @@ public class SubscriptionManager { /** * If a default is set to subscription which is not active, this will reset that default back to - * INVALID_SUBSCRIPTION_ID. + * an invalid subscription id, i.e. < 0. * @hide */ public void clearDefaultsForInactiveSubIds() { @@ -1022,7 +1024,7 @@ public class SubscriptionManager { /** * @return true if subId is an usable subId value else false. A - * usable subId means its neither a INVALID_SUBSCRIPTION_ID nor a DEFAUL_SUB_ID. + * usable subId means its neither a INVALID_SUBSCRIPTION_ID nor a DEFAULT_SUB_ID. * @hide */ public static boolean isUsableSubIdValue(int subId) { @@ -1064,7 +1066,7 @@ public class SubscriptionManager { * is never null but the length maybe 0. * @hide */ - public int[] getActiveSubscriptionIdList() { + public @NonNull int[] getActiveSubscriptionIdList() { int[] subId = null; try { diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 751e11b..73e3213 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -40,6 +41,7 @@ import com.android.internal.telephony.TelephonyProperties; import java.io.FileInputStream; import java.io.IOException; +import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -1879,6 +1881,23 @@ public class TelephonyManager { } /** + * Return the set of subscriber IDs that should be considered as "merged + * together" for data usage purposes. This is commonly {@code null} to + * indicate no merging is required. Any returned subscribers are sorted in a + * deterministic order. + * + * @hide + */ + public @Nullable String[] getMergedSubscriberIds() { + try { + return getITelephony().getMergedSubscriberIds(); + } catch (RemoteException ex) { + } catch (NullPointerException ex) { + } + return null; + } + + /** * Returns the MSISDN string. * for a GSM phone. Return null if it is unavailable. * <p> @@ -3490,8 +3509,15 @@ public class TelephonyManager { /** @hide */ @SystemApi public void setDataEnabled(boolean enable) { + setDataEnabled(SubscriptionManager.getDefaultDataSubId(), enable); + } + + /** @hide */ + @SystemApi + public void setDataEnabled(int subId, boolean enable) { try { - getITelephony().setDataEnabled(enable); + Log.d(TAG, "setDataEnabled: enabled=" + enable); + getITelephony().setDataEnabled(subId, enable); } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#setDataEnabled", e); } @@ -3500,12 +3526,21 @@ public class TelephonyManager { /** @hide */ @SystemApi public boolean getDataEnabled() { + return getDataEnabled(SubscriptionManager.getDefaultDataSubId()); + } + + /** @hide */ + @SystemApi + public boolean getDataEnabled(int subId) { + boolean retVal; try { - return getITelephony().getDataEnabled(); + retVal = getITelephony().getDataEnabled(subId); } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#getDataEnabled", e); + retVal = false; } - return false; + Log.d(TAG, "getDataEnabled: retVal=" + retVal); + return retVal; } /** @@ -3593,5 +3628,3 @@ public class TelephonyManager { } } } - - diff --git a/telephony/java/com/android/ims/internal/IImsCallSession.aidl b/telephony/java/com/android/ims/internal/IImsCallSession.aidl index d1946e3..b1f2d32 100644 --- a/telephony/java/com/android/ims/internal/IImsCallSession.aidl +++ b/telephony/java/com/android/ims/internal/IImsCallSession.aidl @@ -223,6 +223,20 @@ interface IImsCallSession { void sendDtmf(char c, in Message result); /** + * Start a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>, + * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15, + * and event flash to 16. Currently, event flash is not supported. + * + * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs. + */ + void startDtmf(char c); + + /** + * Stop a DTMF code. + */ + void stopDtmf(); + + /** * Sends an USSD message. * * @param ussdMessage USSD message to send diff --git a/telephony/java/com/android/ims/internal/IImsConfig.aidl b/telephony/java/com/android/ims/internal/IImsConfig.aidl index c5ccf5f..c17637c 100644 --- a/telephony/java/com/android/ims/internal/IImsConfig.aidl +++ b/telephony/java/com/android/ims/internal/IImsConfig.aidl @@ -49,22 +49,22 @@ import com.android.ims.ImsConfigListener; */ interface IImsConfig { /** - * Gets the value for ims service/capabilities parameters from the master + * Gets the value for ims service/capabilities parameters from the provisioned * value storage. Synchronous blocking call. * * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants. * @return value in Integer format. */ - int getMasterValue(int item); + int getProvisionedValue(int item); /** - * Gets the value for ims service/capabilities parameters from the master + * Gets the value for ims service/capabilities parameters from the provisioned * value storage. Synchronous blocking call. * * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants. * @return value in String format. */ - String getMasterStringValue(int item); + String getProvisionedStringValue(int item); /** * Sets the value for IMS service/capabilities parameters by the operator device @@ -112,4 +112,12 @@ interface IImsConfig { * @return void */ oneway void setFeatureValue(int feature, int network, int value, ImsConfigListener listener); + + /** + * Gets the value for IMS volte provisioned. + * This should be the same as the operator provisioned value if applies. + * + * @return void + */ + boolean getVolteProvisioned(); } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index bf7f332..4affad8 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -679,14 +679,14 @@ interface ITelephony { * * @param enable true to turn on, else false */ - void setDataEnabled(boolean enable); + void setDataEnabled(int subId, boolean enable); /** * Get the user enabled state of Mobile Data. * * @return true on enabled */ - boolean getDataEnabled(); + boolean getDataEnabled(int subId); /** * Get P-CSCF address from PCO after data connection is established or modified. @@ -772,6 +772,8 @@ interface ITelephony { */ String getLine1AlphaTagForDisplay(int subId); + String[] getMergedSubscriberIds(); + /** * Override the operator branding for the current ICCID. * diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java index 256a1d4..1216fc4 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java @@ -17,12 +17,14 @@ package com.android.test.hwui; import android.animation.Animator; +import android.animation.Animator.AnimatorListener; import android.animation.AnimatorSet; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.os.Bundle; +import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewAnimationUtils; @@ -37,6 +39,29 @@ public class RevealActivity extends Activity implements OnClickListener { private boolean mShouldBlock; private int mIteration = 0; + private AnimatorListener mListener = new AnimatorListener() { + + @Override + public void onAnimationStart(Animator animation) { + Log.d("Reveal", "onAnimatorStart " + animation); + } + + @Override + public void onAnimationRepeat(Animator animation) { + Log.d("Reveal", "onAnimationRepeat " + animation); + } + + @Override + public void onAnimationEnd(Animator animation) { + Log.d("Reveal", "onAnimationEnd " + animation); + } + + @Override + public void onAnimationCancel(Animator animation) { + Log.d("Reveal", "onAnimationCancel " + animation); + } + }; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -59,6 +84,8 @@ public class RevealActivity extends Activity implements OnClickListener { Animator animator = ViewAnimationUtils.createCircularReveal(view, view.getWidth() / 2, view.getHeight() / 2, 0, Math.max(view.getWidth(), view.getHeight())); + Log.d("Reveal", "Calling start..."); + animator.addListener(mListener); if (mIteration < 2) { animator.setDuration(DURATION); animator.start(); @@ -66,6 +93,7 @@ public class RevealActivity extends Activity implements OnClickListener { AnimatorSet set = new AnimatorSet(); set.playTogether(animator); set.setDuration(DURATION); + set.addListener(mListener); set.start(); } diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index f5f70c5..d23b82e 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -516,12 +516,10 @@ static void printFeatureGroup(const FeatureGroup& grp, const size_t numFeatures = grp.features.size(); for (size_t i = 0; i < numFeatures; i++) { - if (!grp.features[i]) { - continue; - } + const bool required = grp.features[i]; const String8& featureName = grp.features.keyAt(i); - printf(" uses-feature: name='%s'\n", + printf(" uses-feature%s: name='%s'\n", (required ? "" : "-not-required"), ResTable::normalizeForOutput(featureName.string()).string()); } @@ -1844,7 +1842,7 @@ int doDump(Bundle* bundle) } } - if (!grp.features.isEmpty()) { + if (!grp.features.isEmpty()) { printFeatureGroup(grp); } } |
